Trig

Trig

A language/VM/system for computational rhythmic patterns. Designed to eventually be programmed using the monome grid interface.

Top Files

<<trigvm.h>>=
#ifndef TRIGVM_H
#define TRIGVM_H
<<typedefs>>
<<funcdefs>>
#ifdef TRIGVM_PRIVATE
<<structs>>
#endif
#endif
<<trigvm.c>>=
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#define TRIGVM_PRIVATE
#include "trigvm.h"
<<static_funcdefs>>
<<funcs>>

The Cell

The core building block of Trig is the cell. A cell is mainly comprised of 2 32-bit words, which will eventually be displayed on a 8x8 grid. The topmost word holds the data, the other will hold the command.

<<typedefs>>=
typedef struct trig_cell trig_cell;
<<structs>>=
struct trig_cell {
   uint32_t cmd;
   uint32_t data;
};

Get these values directly with trig_cell_cmd and trig_cell_data.

<<funcdefs>>=
uint32_t trig_cell_cmd(trig_cell *c);
uint32_t trig_cell_data(trig_cell *c);

<<funcs>>=
uint32_t trig_cell_cmd(trig_cell *c)
{
    return c->cmd;
}

uint32_t trig_cell_data(trig_cell *c)
{
    return c->data;
}

The main way to program cells is to set bits. This is done by determining the word and the local XY position. Word 0 is the top word. Word 1 is the bottom word. This is how programming will be done on the monome (bit-by-bit, literally).

<<funcdefs>>=
void trig_cell_set(trig_cell *c, int w, int pos, int s);
<<funcs>>=
void trig_cell_set(trig_cell *c, int w, int pos, int s)
{
    uint32_t *x;
    if (w) {
        x = &c->data;
    } else {
        x = &c->cmd;
    }

    if (s) {
        *x |= 1 << pos;
    } else {
        *x &= ~(1 << pos);
    }
}

In practice, bits will be toggled, not set. Do this with trig_cell_tog. It's similar to trig_cell_set, except that the state value isn't supplied.

<<funcdefs>>=
void trig_cell_tog(trig_cell *c, int w, int pos);

<<funcs>>=
void trig_cell_tog(trig_cell *c, int w, int pos)
{
    uint32_t *x;

    if (w) {
        x = &c->data;
    } else {
        x = &c->cmd;
    }

    *x ^= 1 << pos;
}

Printing a cell is useful for debugging. It will also provide a good preview for what a cell will look like displayed on a monome.

<<funcdefs>>=
void trig_cell_print(trig_cell *c);
<<funcs>>=
void trig_cell_print(trig_cell *c)
{
    int i;

    for (i = 0; i < 64; i++) {
        int s;
        uint32_t byte;
        int pos;

        if (i < 32) {
            byte = c->cmd;
            pos = i;
        } else {
            byte = c->data;
            pos = i - 32;
        }

        if (i == 32) {
            printf("\n");
        }

        s = (byte >> pos) & 1;

        if (s) {
            printf("#");
        } else {
            printf("-");
        }

        if (((i + 1) % 8) == 0) {
            printf("\n");
        }
    }

    printf("\n");
}

The VM

All state data is maintained inside of a struct called trig_vm.

VM Data

<<typedefs>>=
typedef struct trig_vm trig_vm;
<<structs>>=
<<trig_state>>
struct trig_vm {
    <<trig_vm>>
};

A trig_vm is initialized with trig_vm_init.

<<funcdefs>>=
void trig_vm_init(trig_vm *vm);

<<funcs>>=
void trig_vm_init(trig_vm *vm)
{
    <<trig_vm_init>>
}

No destroy function needed, as there is no memory allocation.

VM struct size

<<funcdefs>>=
size_t trig_vm_size(void);
<<funcs>>=
size_t trig_vm_size(void)
{
    return sizeof(trig_vm);
}

The Cell Pool

Cells are managed in a pool of exactly 32. This fits into a 8x4 rectangle.

<<trig_vm>>=
trig_cell cell[32];

<<trig_vm_init>>=
{
    int i;
    for (i = 0; i < 32; i++) {
        vm->cell[i].cmd = 0;
        vm->cell[i].data = 0;
    }
}

Internal State

Internal state variables that can be swapped out. Used to have multiple readers happening at once.

<<trig_vm>>=
trig_state *state;
trig_state istate;

<<trig_vm_init>>=
vm->state = &vm->istate;

<<trig_vm_init>>=
trig_state_init(&vm->istate);

Goto

Sets the cell position of the internal struct.

<<funcdefs>>=
void trig_vm_goto(trig_vm *vm, int pos);

<<funcs>>=
void trig_vm_goto(trig_vm *vm, int pos)
{
    vm->istate.pos = pos;
}
Counter

A global counter is used by certain kinds of cells for performing patterns.

<<funcdefs>>=
void trig_vm_counter_reset(trig_vm *vm);

Just the main counter. Other states will have to be reset another way (inside a patchwerk node... re-compilation).

<<funcs>>=
void trig_vm_counter_reset(trig_vm *vm)
{
    vm->istate.counter = -1;
}

Wires

"Wires" are floating point variables that can be used for input or output. The VM doesn't really make a distinction.

The number of wires can be set with the TRIG_NWIRES macro, which for now is set to be 8 by default.

<<trig_vm>>=
#ifndef TRIG_NWIRES
#define TRIG_NWIRES 8
#endif
float wires[TRIG_NWIRES];

<<trig_vm_init>>=
{
    int i;
    for (i = 0; i < TRIG_NWIRES; i++) {
        vm->wires[i] = 0;
    }
}

A value of a wire can be retrieved using the function trig_vm_wire_get.

<<funcdefs>>=
float trig_vm_wire_get(trig_vm *vm, int wire);
<<funcs>>=
float trig_vm_wire_get(trig_vm *vm, int wire)
{
    return vm->wires[wire];
}

A value of a wire can be set using the function trig_vm_wire_set.

<<funcdefs>>=
void trig_vm_wire_set(trig_vm *vm, int wire, float val);
<<funcs>>=
void trig_vm_wire_set(trig_vm *vm, int wire, float val)
{
    vm->wires[wire] = val;
    if (vm->set != NULL) {
        vm->set(vm, vm->ud, wire, val);
    }
}

The pointer reference of the wire can be retrieved with trig_vm_wire_ref

<<funcdefs>>=
float* trig_vm_wire_ref(trig_vm *vm, int wire);
<<funcs>>=
float* trig_vm_wire_ref(trig_vm *vm, int wire)
{
    return &vm->wires[wire];
}

Wire Callback

In order to integrate wires with Patchwerk, a callback interface is provided. This gets called anytime a cable value is set.

<<typedefs>>=
typedef void (*trig_setter) (trig_vm *, void *, int, float);
<<trig_vm>>=
trig_setter set;
void *ud;
<<trig_vm_init>>=
vm->set = NULL;
vm->ud = NULL;

It can be set with the callback with trig_vm_setter.

<<funcdefs>>=
void trig_vm_setter(trig_vm *vm, trig_setter fun, void *ud);
<<funcs>>=
void trig_vm_setter(trig_vm *vm, trig_setter fun, void *ud)
{
    vm->set = fun;
    vm->ud = ud;
}

Run Flag

This flag is set at the beginning of a step, and will cause the program to step through the system until a cell flips it off.

<<trig_vm>>=
int running;

<<trig_vm_init>>=
vm->running = 0;

Get Cell

<<funcdefs>>=
trig_cell * trig_vm_cell_get(trig_vm *vm, int cell);
<<funcs>>=
trig_cell * trig_vm_cell_get(trig_vm *vm, int cell)
{
    return &vm->cell[cell];
}

VM State

<<typedefs>>=
typedef struct trig_state trig_state;

The idea here is to have a component that allows multiple readers to read from one pool. This sort of functionality would make it easier for a single Trig instance to play multiple sequences.

It is initialized with trig_state_init.

<<funcdefs>>=
void trig_state_init(trig_state *ts);

<<funcs>>=
void trig_state_init(trig_state *ts)
{
    <<trig_state_init>>
}

Two big things that an independent VM state would need: counter + cell position.

For convenience purposes, an optional pointer holding trig_vm is also part of the state. This makes it easier to wrap a patchwerk node around a reader.

<<trig_state>>=
struct trig_state {
    int counter;
    int pos;
    int ipos;
    void *ud;
};

<<trig_state_init>>=
ts->counter = -1;
ts->pos = 0;
ts->ipos = 0;
ts->ud = NULL;

The data in the trig_state struct can be set/get with trig_state_ud_set and trig_state_ud_get.

<<funcdefs>>=
void trig_state_ud_set(trig_state *state, void *ud);
void * trig_state_ud_get(trig_state *state);

<<funcs>>=
void trig_state_ud_set(trig_state *state, void *ud)
{
    state->ud = ud;
}

void * trig_state_ud_get(trig_state *state)
{
    return state->ud;
}

If vm is not empty, trig_state_step can run trig_vm_state_step internally.

An initial position, ipos, dictates where to start. Internally, this is represented as an 0-indexed array offset. Externally, the values are 1-indexed in order for it to make it align more with the visuals.

<<funcdefs>>=
void trig_state_ipos(trig_state *state, int ipos);

<<funcs>>=
void trig_state_ipos(trig_state *state, int ipos)
{
    if (ipos < 1 || ipos > 32) return;
    state->ipos = ipos - 1;
}

A state can be reset with trig_state_reset. This sets the pos to be ipos.

<<funcdefs>>=
void trig_state_reset(trig_state *state);
<<funcs>>=
void trig_state_reset(trig_state *state)
{
    state->pos = state->ipos;
    state->counter = -1;
}

Procedure (trig_vm_ex)

A cell procedure determines how to determine the bitpattern to perform a particular function. It will always return an integer, which is the next cell position to jump to. The three major parameters it takes in are current position, command word, the data word. This function parses the command word, and executes the appropriate function.

When a cell is computed, it copies it's internal words over to this function to be parsed.

There are a potential of 8 major opcode types, stored in the first 8 bits of the bytes, which correspond to 8 potential functions.

<<funcdefs>>=
int trig_vm_ex(trig_vm *vm,
               int pos,
               uint32_t cmd,
               uint32_t data);
<<funcs>>=
<<exfuncs>>
int trig_vm_ex(trig_vm *vm,
               int pos,
               uint32_t cmd,
               uint32_t data)
{
    if (cmd == 0) return empty(vm, pos, cmd, data);
    if (cmd & 1) return pattern(vm, pos, cmd, data);
    if (cmd & 2) return jump(vm, pos, cmd, data);
    if (cmd & 4) return maygate(vm, pos, cmd, data);
    if (cmd & 8) return metapattern(vm, pos, cmd, data);

    return empty(vm, pos, cmd, data);
}

Step

<<funcdefs>>=
void trig_vm_step(trig_vm *vm);

When a VM step happens, it will run through the program until it reaches a pattern cell or an empty cell. Some protection is done to ensure that an infinite loop doesn't happen.

This now wraps around trig_vm_step_state using the internal state file. See that function for more detail.s

<<funcs>>=
void trig_vm_step(trig_vm *vm)
{
    trig_vm_step_state(vm, &vm->istate);
}

This trig_vm_step_state steps with an external state. This can be used to allow multiple readers to happen concurrently.

<<funcdefs>>=
void trig_vm_step_state(trig_vm *vm, trig_state *ts);

<<funcs>>=
void trig_vm_step_state(trig_vm *vm, trig_state *ts)
{
    int count;
    vm->running = 1;

    count = 0;
    vm->state = ts;
    while (vm->running) {
        trig_cell *c;

        count++;

        if (count >= 64) {
            fprintf(stderr,
            "trig: max count of 64 reached. "
            "breaking.\n");
            vm->running = 0;
            break;
        }

        if (ts->pos < 0 || ts->pos >= 32) {
            fprintf(stderr,
                    "trig: invalid position %d\n",
                    ts->pos);
            vm->running = 0;
            break;
        }
        c = &vm->cell[ts->pos];
        ts->pos = trig_vm_ex(vm, ts->pos, c->cmd, c->data);
    }

    vm->state = &vm->istate;
}

Empty Cell

Does nothing. Goes nowhere. This can be used to terminate programs.

<<exfuncs>>=
static int empty(trig_vm *vm,
                 int pos,
                 uint32_t cmd,
                 uint32_t data)
{
    vm->running = 0;
    trig_vm_wire_set(vm, 0, 0);
    return pos;
}

Pattern Cell

A pattern cell is a kind of cell that plays a rhythmic pattern. It can have a maximum size of 32. When the VM arrives on a pattern cell, it will begin playing the cell pattern. It will remain on this cell until it reaches the end of the pattern, then it will go to the next cell.

A pattern cell can write to any of the 8 wires. It will use the rightmost bit on the second byte to determine which wire to write to. If no bits are turned on, it is assumed to be wire 1.

The counter is used to extract the corresponding bit state in a way you'd typically expect. When the counter reaches the end of pattern, it returns the next position in the series, with loopback if appropriate.

A pattern cell uses the global counter variable to maintain state. If the counter is at -1, it assumed that the VM just arrived at the pattern, and uses this to initialize the counter to be 0.

A bit of bitwise magic is used to determine the rightmost bit of the third byte (x & -x) was retrieved from the book "hackers delight" in the section called "the basics".

Wire number from the byte gets converted to a wire position wp using a sort of log2 while-loop function.

The fourth command byte is used for additional functionality. The byte is divided up into 2 nibbles. The lower nibble determines the command, the upper nibble defines the data. This is done because it will show up command, data on the monome.

If the command nibble is 0, nothing happens.

Nibble command 1 enables switch mode. It will split the pattern into 2 16-bit sections. It will reading from the wire specified in the nibble data. A zero value will' select the lower half pattern. A non-zero value selects the upper half pattern. The wire data is specified as a binary value.

<<exfuncs>>=
static int pattern(trig_vm *vm,
                   int pos,
                   uint32_t cmd,
                   uint32_t data)
{
    int nib;
    int dur;
    uint32_t pat;
    trig_state *ts;

    ts = vm->state;
    dur = (cmd >> 16) & 0xFF;
    dur *= (dur <= 32);
    nib = (cmd >> 24) & 0xFF;
    pat = data;

    if (nib & 0xf) {
        int ncmd;
        int ndat;

        ncmd = nib & 0xf;
        ndat = (nib >> 4) & 0xf;

        if (ncmd == 1) {
            int wire;

            wire = ndat;
            if (wire > 0 && wire <= 8) wire--;
            else wire = 0;

            if (vm->wires[wire] == 0) {
                pat = data & 0xFFFF;
            } else {
                pat = (data >> 16) & 0xFFFF;
            }
        }
    }

    vm->running = 0;

    if (ts->counter == -1) {
        ts->counter = 0;
    } else {
        ts->counter++;
    }

    if (ts->counter == dur || dur == 0) {
        ts->counter = -1;
        vm->running = 1;
        return (pos + 1) % 32;
    } else {
        int wire;
        int s;
        int wp;

        wire = (cmd >> 8) & 0xFF;

        if (wire == 0) {
            wire = 1;
        } else {
            /* only use rightmost bit */
            wire = wire & -wire;
        }

        wp = 0;

        while (wire >>= 1) wp++;


        s = (pat & (1 << ts->counter)) != 0;

        trig_vm_wire_set(vm, wp, s);

        return pos;
    }

    return pos;
}

Jump Cell

A jump cell is used to jump to a particular cell. This wire is multifunctional, depending on the states of the command cell.

Location is stored in the rightmost turned on bit in data. Each bit correspond to a location in the cell pool (of size 32). If no bits are turned on, the jump cell is is ignored.

If the second command byte is zero, it will behave as a goto operation and immediately go to the cell location in the data word.

If the second command byte is a non zero value, it will use the wire in the rightmost bit as a conditional. If the wire is non-zero, it will go to the location. Otherwise, it will continue on to the next cell in the VM.

<<exfuncs>>=
static int jump(trig_vm *vm,
                int pos,
                uint32_t cmd,
                uint32_t data)
{
    int go;
    int rbit;
    int wire;

    if (data == 0) return (pos + 1) % 32;

    rbit = (data & -data);

    go = 0;

    while (rbit >>= 1) go++;

    wire = (cmd >> 8) & 0xFF;

    if (wire == 0) {
        return go % 32;
    } else {
        int wp;

        rbit = wire & -wire;

        wp = 0;
        while (rbit >>= 1) wp++;

        if (trig_vm_wire_get(vm, wp) != 0) return go % 32;
    }

    return (pos + 1) % 32;
}

Maygate Cell

Randomly sets the state of a wire to be 1 or 0.

byte 1: wire to set. 0 by default.

For now, this is just a cointoss (50/50) probability.

If the data is non-zero, maygate can function as a conditional jump. The random state of 1 will cause a jump to the location stored in the data byte.

<<exfuncs>>=
static int maygate(trig_vm *vm,
                   int pos,
                   uint32_t cmd,
                   uint32_t data)
{
    int byte;
    int wire;
    double rnd;

    byte = (cmd >> 8) & 0xFF;

    /* right most bit */
    byte &= -byte;

    wire = 0;
    while (byte >>= 1) wire++;

    rnd = (double) rand() / RAND_MAX;

    if (rnd > 0.5) {
        trig_vm_wire_set(vm, wire, 1);
    } else {
        trig_vm_wire_set(vm, wire, 0);
    }

    if (data == 0) {
        return (pos + 1) % 32;
    } else {
        if (rnd > 0.5) {
            int go;

            byte = data;
            byte &= -byte;
            go = 0;
            while (byte >>= 1) go++;

            return go;
        } else {
            return (pos + 1) % 32;
        }
    }
}

Metapatterns

A "metapattern" is a pattern that references another pattern, and applies some transformations to it. After it applies the transformations, it behaves just like a pattern would.

The metapattern uses all bytes in the word as a single unit, rather than making between data + command.

After the first metapattern identifying byte comes the byte that holds the pattern reference. Encoded in binary, the pattern reference the location in the cell pool. This reference can either be a pattern or another metapattern.

The remaining 6 bytes are used as transformation commands that can be composed together. These transformation commands non-destructively alter the pattern in some way.

A transformation command byte is divided up into two nibbles. The lower (lefthand) nibble displays the command, the upper (righthand) nibble is the parameter.

Transformations may include:

left/right rotational shift: shift the entire pattern by some amount with wraparound.

shrink/expand: take a pattern and stretch/squash it by some factor.

invert: flips the bits of the pattern.

crop: takes only a portion of the pattern

repeat: repeats a segment of a pattern a certain number of times

reverse: reverses the pattern

mirror: creates a mirror image of the pattern

decimate: add some kind of noise/randomness to the pattern

<<exfuncs>>=
static int metaprocess(trig_vm *vm, int pos,
                       uint32_t cmd,
                       uint32_t data,
                       uint32_t *cmdout,
                       uint32_t *dataout)
{
    int pat;
    uint32_t pcmd;
    uint32_t pdat;
    trig_cell *c;

    pat = (cmd >> 8) & 0xFF;

    if (pat < 1 || pat > 32) {
        return empty(vm, pos, 0, 0);
    }
    pat--;

    c = trig_vm_cell_get(vm, pat);

    pcmd = c->cmd;
    pdat = c->data;

    if (pcmd & 8) {
        if (pos == pat) return empty(vm, pos, 0, 0);
        return metaprocess(vm, pos, pcmd, pdat, cmdout, dataout);
    } else if (pcmd & 1) {
        uint8_t ncmd;
        uint8_t ndat;
        uint8_t nib;
        int n;
        int update;
        int next;

        update = 0;
        for (n = 0; n < 6; n++) {
            if (n <= 1) {
                nib = (cmd >> (16 + n*8)) & 0xFF;
            } else {
                nib = (data >> ((n - 2)*8)) & 0xFF;
            }

            ncmd = nib & 0xf;
            ndat = (nib >> 4) & 0xf;

            if (ncmd == 1) {
                <<simple_commands>>
            } else if (ncmd == 2) {
                <<backward_shift>>
            } else if (ncmd == 3) {
                <<forward_shift>>
            } else if (ncmd == 15) {
                <<cellular_automata>>
            }
        }

        next = pattern(vm, pos, pcmd, pdat);

        if (update) {
            <<update_the_cell>>
        }

        return next;
    }

    return empty(vm, pos, 0, 0);
}

static int metapattern(trig_vm *vm,
                       int pos,
                       uint32_t cmd,
                       uint32_t data)
{
    uint32_t pcmd;
    uint32_t pdat;

    pcmd = 0;
    pdat = 0;

    return metaprocess(vm, pos, cmd, data, &pcmd, &pdat);
}

Parameterless Transformations

To save on bits, all commands that do not require any parameters in the data nib are thrown into command nib 1. These are known as "simple" commands. The data portion of the simple commands is used to tell which command to use.

At the moment:

0: invert

1: reverse

2: update

<<simple_commands>>=
if (ndat == 0) {
    <<command_invert>>
} else if (ndat == 1) {
    <<reverse_command>>
} else if (ndat == 2) {
    <<update_command>>
}
Inversion

Inversion (0) simply inverts the entire data bit. Anything that is a 1 becomes a 0, and vice versa.

<<command_invert>>=
pdat = ~pdat;
Reverse

Reversal (1) reverses the pattern. This requires knowing the size of the pattern, so both the command and data words of the pattern are needed.

<<reverse_command>>=
pdat = reverse(pcmd, pdat);

<<static_funcdefs>>=
static uint32_t reverse(uint32_t cmd, uint32_t dat);

Reversal does what you'd do for a reverse-in-place on a string, only with bits.

<<funcs>>=
static uint32_t reverse(uint32_t cmd, uint32_t dat)
{
    uint32_t out;
    uint8_t sz;
    uint8_t szd2;
    int n;

    sz = (cmd >> 16) & 0xFF;
    szd2 = sz / 2;

    out = dat;

    for (n = 0; n < szd2; n++) {
        int s1, s2;
        int end;

        end = sz - n - 1;

        s1 = (dat >> n) & 1;
        s2 = (dat >> end) & 1;

        if (s1) {
            out |= (1 << end);
        } else {
            out &= ~(1 << end);
        }

        if (s2) {
            out |= (1 << n);
        } else {
            out &= ~(1 << n);
        }

   }

    return out;
}
Update

The update copies over the metapattern as it exists back to the original pattern. This command will set an update flag to be 1.

<<update_command>>=
update = 1;

The cell should only be updated when the pattern reaches the end. This is checked by seeing if the return position differs.

<<update_the_cell>>=
if (next != pos) {
    c->cmd = pcmd;
    c->data = pdat;
}

1-bit CA

1-dimensional cellular automata (15, all on) can be applied to the 32-bit pattern data from a rule. A rule is an 8-bit number. Command nibbles are only 4 bits, so to make this work, this command gobbles up the following byte, and reads all 8 bits as the parameter for rule.

This particular cellular automata implementation was adapted from rosetta code.

<<cellular_automata>>=
uint8_t rule;
uint32_t out;
int j;

rule = 0;
out = 0;
#define B(x) (1 << (x))
if (n < 5) {
    n++; /* skips the next byte */
    if (n <= 1) {
        rule = (cmd >> (16 + n*8)) & 0xFF;
    } else {
        rule = (data >> ((n - 2)*8)) & 0xFF;
    }

    for (j = 0; j < 32; j++) {
        if (rule & B(7 & (pdat>>(j-1) | pdat<<(32+1-j))))
            out |= B(j);
    }

    pdat = out;
}
#undef B

WIP Shifts

ncmds 2 and 3 do rotational shifts of a pattern, with the ncmd being a value for how many times to shift.

Normally, these shifts are referred to as left/right shifts, but this can be confusing with the little-endian binary representation. Instead, the terms forward and backward will be used relative to how they are displayed. 2 will be a forward (right) shift, and 3 will be a backward (left) shift.

A rotational shift moves bits in a direction, and does wrap around. This operation to be specially built in order to compensate for pattern size. This operation does one shift at a time. It shifts the value, takes the shifted bit, and ORs it to the other side.

A forward shift is actually a left shift on the the layout (counter-intuitive riight?).

<<static_funcdefs>>=
static uint32_t fshift_1(uint32_t n, uint32_t patsize);

First, the rotated bit is retrieved by ANDing the value at the end of the pattern position.

The value is then left shifted, masked, and then the rotated bit is OR'd into the first position.

<<funcs>>=
static uint32_t fshift_1(uint32_t x, uint32_t patsize)
{
    uint32_t out;
    int bit;

    bit = (x & (1 << (patsize - 1))) > 0;
    out = (x << 1);
    out |= bit;
    if (patsize < 32) out &= (1 << patsize) - 1;
    return out;
}

<<static_funcdefs>>=
static uint32_t fshift(uint32_t cmd, uint32_t dat, int n);

<<funcs>>=
static uint32_t fshift(uint32_t cmd, uint32_t dat, int n)
{
    uint32_t out;
    uint32_t sz;
    int i;
    sz = (cmd >> 16) & 0xFF;
    out = dat;

    for (i = 0; i < n; i++) out = fshift_1(out, sz);

    return out;
}

<<forward_shift>>=
{
    pdat = fshift(pcmd, pdat, ndat);
}

A backward shift (right shift) is mirror of the forward shift. The rotated bit is the very first bit, and gets OR'd into the last bit position in the pattern.

<<static_funcdefs>>=
static uint32_t bshift_1(uint32_t n, uint32_t patsize);

<<funcs>>=
static uint32_t bshift_1(uint32_t x, uint32_t patsize)
{
    uint32_t out;
    int bit;

    bit = (x & 1);
    out = (x >> 1);
    out |= (bit << (patsize - 1));
    if (patsize < 32) out &= (1 << patsize) - 1;
    return out;
}

<<static_funcdefs>>=
static uint32_t bshift(uint32_t cmd, uint32_t dat, int n);

<<funcs>>=
static uint32_t bshift(uint32_t cmd, uint32_t dat, int n)
{
    uint32_t out;
    uint32_t sz;
    int i;
    sz = (cmd >> 16) & 0xFF;
    out = dat;

    for (i = 0; i < n; i++) out = bshift_1(out, sz);

    return out;
}

<<backward_shift>>=
{
    pdat = bshift(pcmd, pdat, ndat);
}