# Logic Analyzer core: Range Detectors

The advanced trigger supports detecting when sampled data falls within a range of values. ie: if the sample is between a lower limit & upper limit. ie:

hit = (upper-limit >= sample) && (sample >= lower-limit)

So we need magnitude comparators. In hardware, that means adding or subtracting two numbers to see if something overflows or "carry's" over. A bit like long addition. Add a column, carry the one, add another, etc...

In hardware there is parallel to long addition: the full adder. The adder adds A+B+Cin, and outputs S & Cout, where all signals are single bits. To add wide values you chain the carry signals as needed.

```A    B    CIn    Cout    S
0    0    0    0    0
0    0    1    0    1
0    1    0    0    1
0    1    1    1    0
1    0    0    0    1
1    0    1    1    0
1    1    0    1    0
1    1    1    1    1```

Chains of full adders work, but are slow. The carry-out signal is derived from the inputs. In a 32-bit adder, there would be 32 chained carry circuits. Achieving timing would be harder than necessary.

An improvement is the carry-look-ahead adder.There is still a combinatorial element per bit, but it's very fast -- a simple mux. The fpga even has an integral "fast-carry-chain" circuit available for implementing such adders.

To make things even better, a magnitude comparison doesn't need the sum output at all. Just the fast carry chain. Thus we end up with something that fits perfectly into a single Logic Block. The LUT table simply needs loading with the result of an XOR between the input on A0, and the target value.

Figure 12 - Carry Look Ahead Comparator

## 4.1 Complex Range Compares

The fast carry change logic has a couple of interesting possibilities.

First of all, the range comparison can start anywhere. If the first bit of interest is bit 7 (for example), simply fill all lower LUT's with 1's. This NOP's them in the comparator.

Second, the bits participating in the range comparison don't need to be contiguous. You could setup to range check the value formed by indata bits 7,9,11, & 15. Simply NOP the LUT's of the don't care indata bits.

## 4.2 Prepare Target Values for Comparator

There are two ways to compare a value. Subtract a value & look for underflow/borrow, or add & look for overflow/carry. Since we have the fast-carry-chain, we're using the latter approach.

A given range target must be bitwise inverted before being programmed. For non-contiguous range checks, the inverted value must also be spaced out, across only those bits of interest.

```Lower value = ~(lower_target - 1)
Upper value = ~(upper_target)
Yields a hit if (upper_target >= indata >= lower_target)```

## 4.3 Range Compare LUT Chains

There are 32 LUT's in each range-check magnitude comparator. Each needs 16-bits, so that totals 512 bits of configuration. Two LUT's are programmed at once for each write to the chain-data register.

Figure 13 - Range LUT Organization

## 4.4 Example (Range Detect Initialization)

```#define RANGE_XOR0 0xAAAA
#define RANGE_XOR1 0x5555
#define RANGE_NOP 0xFFFF

//
// Setup LUT's for Range Detectors
//
// Inputs:
//   rangesel:  0=range1-lower, 1=range1-upper, 2=range2-lower, 3=range2-upper
//   target:    Limit value.
//   mask:      Indicate which bits should participate in range compare.
//
void write_range (int rangesel, unsigned int target, unsigned int mask)
{
unsigned int value;
unsigned int lutvalue=0;
int i;

write_select(0x30+(rangesel&3));

// Count # of bits in mask...
int bitcount=0;
bitcount++;

// Prepare target value...
if (rangesel & 1)
value = ~target; // upper range target
else value = ~(target-1); // lower range value

// Push MSB of target into bit 31...
value <<= (32-bitcount);

// Generate & program LUT values.  Total of 512 bits.
for (i=0; i<16; i=i+1) {
lutvalue = RANGE_NOP;
else {
lutvalue = ((value>>31)&1) ? RANGE_XOR1 : RANGE_XOR0;
value <<= 1;
}
lutvalue <<= 16;

lutvalue |= RANGE_NOP;
else {
lutvalue |= ((value>>31)&1) ? RANGE_XOR1 : RANGE_XOR0;
value <<= 1;
}
```This document is Copyright © 2011 Ian Davis