# Array Instructions Overview

Source: https://rungs.dev/docs/ladder-logic/instructions/array-instructions

> Reference for the Ladder Logic array instructions in rungs.dev — BSL, BSR, FFL, FFU, LFL, LFU, COP, CPS, FLL, AVE, SRT, STD, SIZE, FAL and FSC — and the CONTROL tag structure.

Most instructions work on one value at a time. The array instructions work on a **run of
elements**: a stretch of a `DINT` array, a whole buffer, a window inside a longer array.

They all need to remember two things between scans — how many elements they are working
through, and which one they are on. That is what a `CONTROL` tag holds, the way a `TIMER` tag
holds a timer's preset and accumulator.

## Available Array Instructions [#available-array-instructions]

| Instruction      | Symbol                            | Purpose                                                                                                                            |
| ---------------- | --------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------- |
| [BSL](https://rungs.dev/docs/ladder-logic/instructions/bsl-bsr) |   | Shifts every bit of a DINT array one place toward the high end on each rising edge, feeding the source bit in at bit 0.            |
| [BSR](https://rungs.dev/docs/ladder-logic/instructions/bsl-bsr) |   | Shifts every bit of a DINT array one place toward the low end on each rising edge, feeding the source bit in at the far end.       |
| [FFL](https://rungs.dev/docs/ladder-logic/instructions/ffl-ffu) |   | Puts a value into the next free slot of a queue on each rising edge, and stops once the queue holds .LEN of them.                  |
| [FFU](https://rungs.dev/docs/ladder-logic/instructions/ffl-ffu) |   | Takes the oldest value out of a queue on each rising edge, shifting the rest down one place.                                       |
| [LFL](https://rungs.dev/docs/ladder-logic/instructions/lfl-lfu) |   | Puts a value on top of a stack on each rising edge, and stops once the stack holds .LEN of them.                                   |
| [LFU](https://rungs.dev/docs/ladder-logic/instructions/lfl-lfu) |   | Takes the newest value off the top of a stack on each rising edge, leaving the others where they are.                              |
| [COP](https://rungs.dev/docs/ladder-logic/instructions/cop-cps) |   | Copies a run of elements from one array into another, stopping at whichever array runs out first.                                  |
| [CPS](https://rungs.dev/docs/ladder-logic/instructions/cop-cps) |   | Copies a run of elements the way COP does, holding the copy so nothing else can change the data part-way through.                  |
| [FLL](https://rungs.dev/docs/ladder-logic/instructions/fll)     |   | Writes one value into every element of a run of an array.                                                                          |
| [AVE](https://rungs.dev/docs/ladder-logic/instructions/ave-std) |   | Adds up a run of array elements and stores their average in a tag.                                                                 |
| [SRT](https://rungs.dev/docs/ladder-logic/instructions/srt)     |   | Sorts a run of array elements into ascending order, in place.                                                                      |
| [STD](https://rungs.dev/docs/ladder-logic/instructions/ave-std) |   | Works out how spread out a run of array elements is and stores the result in a REAL tag.                                           |
| [SIZE](https://rungs.dev/docs/ladder-logic/instructions/size)   |  | Counts the elements of an array and stores the count in the destination tag.                                                       |
| [FAL](https://rungs.dev/docs/ladder-logic/instructions/fal-fsc) |   | Works out an expression once for every element of an array and stores each answer, with the control tag counting the elements off. |
| [FSC](https://rungs.dev/docs/ladder-logic/instructions/fal-fsc) |   | Tests an expression against each element of an array in turn and stops at the first one that passes.                               |

## CONTROL Tag Members [#control-tag-members]

Every `CONTROL` tag exposes the same fields. Access them with a dot (`MyControl.POS`).

| Member | Type   | Meaning                                                        |
| ------ | ------ | -------------------------------------------------------------- |
| `.LEN` | `DINT` | Length — how many elements to work through                     |
| `.POS` | `DINT` | Position — which element the instruction is on                 |
| `.EN`  | `BOOL` | Enable — 1 while a loading or shifting rung is true            |
| `.EU`  | `BOOL` | Enable unload — 1 while an FFU or LFU rung is true             |
| `.DN`  | `BOOL` | Done — 1 when the instruction has worked through .LEN elements |
| `.EM`  | `BOOL` | Empty — 1 when the buffer holds nothing                        |
| `.ER`  | `BOOL` | Error — 1 when .LEN or .POS is out of range                    |
| `.UL`  | `BOOL` | Unload — the bit BSL or BSR shifted out                        |
| `.IN`  | `BOOL` | Inhibit — 1 while an FSC search is paused                      |
| `.FD`  | `BOOL` | Found — 1 when an FSC search matched                           |

Not every instruction uses every bit — and four of them use no control at all.

| Instruction                 | Control | Bits it uses              |
| --------------------------- | ------- | ------------------------- |
| `BSL`, `BSR`                | yes     | `.EN .DN .ER .UL`         |
| `FFL`, `LFL`                | yes     | `.EN .DN .EM`             |
| `FFU`, `LFU`                | yes     | `.EU .DN .EM`             |
| `AVE`, `STD`, `SRT`         | yes     | `.EN .DN .ER`             |
| `FAL`, `FSC`                | yes     | `.EN .DN .ER .UL .IN .FD` |
| `COP`, `CPS`, `FLL`, `SIZE` | **no**  | none — they keep no state |

`.IN` and `.FD` belong to `FSC`: `.FD` says it found a match and `.IN` parks the search there
until you clear it.

`.DN` and `.EM` are **results**, not switches: the load and unload instructions work them out
again from `.POS` every time they run, so writing one yourself changes nothing.

Reference these members as contacts, the same way you would a timer's:

```ladder
XIC(Track.DN)OTE(Light)

Track.LEN = 8
```

## Once per edge, or every scan [#once-per-edge-or-every-scan]

The two halves of the family differ on **when** they run, and mixing them up is the commonest
surprise:

- **Once per rising edge** — `BSL`, `BSR`, `FFL`, `FFU`, `LFL`, `LFU`, `AVE`, `STD`, `SRT`,
  and `FAL`/`FSC` in `ALL` or `INC` mode. Holding the rung true does the job once. To do it
  again, let the rung go false first.
- **Spread over several scans** — `FAL` and `FSC` with a numerical mode. They keep going on
  every scan until the run finishes, even after the rung goes false.
- **Every scan the rung is true** — `COP`, `CPS`, `FLL`, `SIZE`. Leave one of these on a
  permanently true rung and it runs on every scan, overwriting whatever else touched the
  destination.

## Where the Length comes from [#where-the-length-comes-from]

The `length` you type into the box is a **starting value**, not something the instruction reads
each scan. It is written into `.LEN` once, when the program starts, and after that the
instruction reads `.LEN` from the control tag.

So writing `Track.LEN := 4` from your logic changes how many elements the instruction works
through on its next run, even though the box still shows the number you typed. That is
deliberate — it is how you make a buffer that grows and shrinks while the program runs.

> **WARNING**
>
> **The array has to be long enough for .LEN**
>
> Studio checks the number you type against the array's declared size and tells you in the
> editor if it does not fit. It cannot check a `.LEN` your logic writes, because the value only
> exists while the program runs — so an over-long `.LEN` stops the program with a major fault
> instead.

## Starting Part-Way Along [#starting-part-way-along]

The array operand names where the region **starts**, so both of these are valid:

- `BSL(Samples, …)` — start at element 0
- `BSL(Samples[4], …)` — start at element 4

Elements before the start are never touched.

## Sharing a control [#sharing-a-control]

One buffer's load and its unload are **meant** to share a control tag — that is how they agree
on how full it is. Every other array instruction needs a control of its own. A `BSL` and a
`BSR` do not cooperate through theirs: each one writes its own `.UL` there, so sharing one
means the second shift overwrites what the first reported. Studio warns when it sees that.

## Related [#related]

- [BSL and BSR](https://rungs.dev/docs/ladder-logic/instructions/bsl-bsr) — the bit shift instructions
- [FFL and FFU](https://rungs.dev/docs/ladder-logic/instructions/ffl-ffu) — a first-in first-out queue
- [LFL and LFU](https://rungs.dev/docs/ladder-logic/instructions/lfl-lfu) — a last-in first-out stack
- [COP and CPS](https://rungs.dev/docs/ladder-logic/instructions/cop-cps) — copy a run of elements
- [FLL](https://rungs.dev/docs/ladder-logic/instructions/fll) — write one value into every element
- [AVE and STD](https://rungs.dev/docs/ladder-logic/instructions/ave-std) — average and spread
- [SRT](https://rungs.dev/docs/ladder-logic/instructions/srt) — sort a run in place
- [SIZE](https://rungs.dev/docs/ladder-logic/instructions/size) — how many elements an array has
- [FAL and FSC](https://rungs.dev/docs/ladder-logic/instructions/fal-fsc) — run your own expression over every element
- [CONTROL tags](https://rungs.dev/docs/tags/data-types#structured-types) — declaring one
- [RES](https://rungs.dev/docs/ladder-logic/instructions/res) — clears `.POS` and the status bits, keeps `.LEN`
- [Arrays](https://rungs.dev/docs/tags/arrays) — declaring an array tag