Slices — Slice L and Slice M
Explore the two types of Slices in Xilinx 7-series FPGAs: Slice L for pure logic, and Slice M which adds distributed RAM and shift register capability. Understand when each is used and why.
Two Types of Slices
The Slice is the smallest independently routable unit in Xilinx 7-series FPGAs. While all Slices share the same LUT6, FF, and CARRY4 resources, Xilinx makes a critical distinction between two types:
Slice L — Logic
- 4× LUT6 (logic mode only)
- 8× Flip-Flop / Latch
- 1× CARRY4
- F7MUX, F8MUX
- No distributed RAM
- No SRL shift register
- Constitutes ~75% of all Slices
Slice M — Memory
- 4× LUT6 (logic, RAM, or SRL)
- 8× Flip-Flop / Latch
- 1× CARRY4
- F7MUX, F8MUX
- + Distributed RAM (64×1-bit)
- + SRL16 / SRL32 shift registers
- Constitutes ~25% of all Slices
Slice L vs Slice M — Internal Comparison
Slice L (left) vs Slice M (right) — Slice M adds distributed RAM and SRL shift register modes to each LUT6
Slice Type Distribution in 7-Series
Distributed RAM (Slice M Only)
In Slice M, the LUT6's 64-bit storage array (normally holding the truth table) can instead be used as 64×1-bit synchronous-write, asynchronous-read SRAM. This is distributed RAM — scattered across the fabric wherever Slice M resources are available, as opposed to the dedicated BRAM columns.
| Configuration | Depth | Width | LUTs Used | Ports |
|---|---|---|---|---|
| RAM64X1S (single-port) | 64 | 1-bit | 1 | 1 read/write |
| RAM64X1D (simple dual-port) | 64 | 1-bit | 2 | 1 read + 1 write |
| RAM32X2S | 32 | 2-bit | 2 | 1 read/write |
| RAM32M (true dual-port) | 32 | 8-bit (4×2) | 4 | 2 independent ports |
| RAM128X1S | 128 | 1-bit | 2 + F7MUX | 1 read/write |
| RAM256X1S | 256 | 1-bit | 4 + MUXes | 1 read/write |
Key characteristic: distributed RAM has synchronous write and asynchronous read. Data written on the rising clock edge appears at the output immediately (without an extra clock cycle). This can create timing problems if not accounted for — output registers are often added to resolve setup violations.
SRL — Shift Register LUT (Slice M Only)
In SRL mode, the LUT6 implements a shift register with a programmable tap depth. Data shifts in on every clock edge, and a 5-bit address selects which bit position to read (dynamic length).
| Primitive | Length | LUTs | Address | Equivalent FFs |
|---|---|---|---|---|
| SRL16E | 1–16 bits | 1 | 4-bit (A3:A0) | 16 |
| SRL32E (SRLC32E) | 1–32 bits | 1 | 5-bit (A4:A0) | 32 |
| 2× SRL32 cascaded | 1–64 bits | 2 | 6-bit | 64 |
An SRL32 shift register replaces 32 D flip-flops using a single LUT6. This is a massive resource saving for pipeline alignment, FIFO delays, and delay matching between parallel paths. The dynamic address makes it suitable for variable-length pipelines configurable at runtime.
Slice M LUT Operating Modes
Slice L vs Slice M — Full Comparison
| Feature | Slice L | Slice M |
|---|---|---|
| LUT as logic | Yes | Yes |
| LUT as distributed RAM | No | Yes (64×1-bit) |
| LUT as SRL16 | No | Yes |
| LUT as SRL32 | No | Yes |
| Flip-flops | 8 | 8 |
| CARRY4 | 1 | 1 |
| F7MUX / F8MUX | Yes | Yes |
| Proportion in 7-series | ~75% | ~25% |
| Silicon area overhead | Lower | Higher (write circuitry) |
| UltraScale equivalent | No L/M split — all Slices support RAM and SRL | |
Why Have Two Slice Types?
Slice M requires additional silicon circuitry compared to Slice L — specifically, write enable logic, write address decode, and the data input path for RAM mode, plus the shift input for SRL mode. Making all Slices type M would increase die area and power consumption with no benefit for designs that don't use distributed RAM or SRL.
Statistical analysis of typical FPGA designs showed that only ~25% of Slices need RAM/SRL capability. So Xilinx distributes Slice M (25%) and Slice L (75%) across the die, reducing area overhead while ensuring sufficient Slice M resources for most designs.
In UltraScale and UltraScale+, Xilinx eliminated the L/M distinction. All Slices support distributed RAM and SRL in every LUT. The improved 16nm process made the overhead acceptable, simplifying the architecture and improving placement flexibility.
- "LUT Flip Flop Pairs" — packed pairs using both LUT and FF
- "Slice LUTs used as Memory" — these are using Slice M distributed RAM
- "Slice LUTs used as Shift Register" — SRL16/SRL32 usage
SHREG_EXTRACT
set to "YES" to infer SRLs automatically from pipeline shift-register patterns in
HDL.
A: Distributed RAM requires a synchronous write port — this involves write enable decode, address multiplexing, and write data steering that is only present in Slice M. Slice L contains only the LUT6 truth table storage and output routing; it has no provision for writing to the LUT contents at runtime (outside of configuration). Slice M adds the extra circuitry needed to write to the 64-bit LUT memory on each clock cycle.
Knowledge Check
1. What is the key capability that Slice M has but Slice L does not?
- A More flip-flops per LUT
- B Faster carry chain
- C LUTs configurable as distributed RAM or SRL shift registers
- D Support for differential IO signals
2. How many bits can a single SRL32 shift register (one LUT6 in Slice M) store?
- A 16
- B 32
- C 64
- D 8
3. What percentage of Slices in a Xilinx 7-series FPGA are type M?
- A 50%
- B 10%
- C 25%
- D 75%
4. In UltraScale+, how does the Slice M / Slice L split differ from 7-series?
- A UltraScale+ has 50% Slice M, 50% Slice L
- B UltraScale+ has 100% Slice L (no distributed RAM)
- C UltraScale+ has no L/M distinction — all Slices support RAM and SRL
- D UltraScale+ has 0% Slice M (uses HBM instead)
5. What is the read behavior of distributed RAM (Slice M) by default?
- A Synchronous read — output appears one cycle after the address
- B Asynchronous read — output appears immediately as address changes
- C Pipelined read with 2-cycle latency
- D Read requires a separate clock enable signal
Practical Exercise
-
Using 20 standard D flip-flops:
reg [19:0] pipe; always @(posedge clk) pipe <= {pipe[18:0], data_in}; -
Using an SRL32 with address 19:
SRLC32E #(.INIT(32'h0)) srl (.D(data_in), .CE(1'b1), .CLK(clk), .A(5'd19), .Q(data_out));