Pamięć można pokazać jako tablicę stałych lub zmiennych, w której wszystkie dane mają swój unikalny adres i każdy wpis ma tę samą liczbę bitów. W FPGA najczęściej stosujemy pamięci równoległe. To znaczy, że w jednym takcie zegarowym dokonujemy odczytu lub zapisu całej danej z pamięci, wskazanej przez wejście adresowe. Dla kontrastu, w przypadku pamięci szeregowych, dane odczytujemy lub zapisujemy do pamięci bit po bicie.
Zwykle mamy do czynienia z pamięciami, gdzie dane mają długość 8, 16 lub 32 bitów. Dane wchodzą i wychodzą z pamięci w sposób równoległy, zatem wejście i wyjście danych musi mieć tyle bitów, ile ma pojedynczy wpis. Najczęściej w równoległych pamięciach RAM, Flash czy EPROM, dostępnych w formie samodzielnych układów scalonych (np. 62256, 39Fxxx, 27Cxxx), wejście i wyjście realizowane jest w formie dwukierunkowego portu wyposażonego w bufor trójstanowy. Takie rozwiązanie ma na celu zmniejszenie liczby wyprowadzeń układu scalonego. Natomiast wewnątrz FPGA nie musimy przejmować się takimi ograniczeniami, więc stosuje się osobny port dla wejścia danych i osobny na wyjście.
Wejście adresowe wskazuje nam, którą daną chcemy odczytać lub zapisać. Liczba bitów tego wejścia jest ściśle powiązana z pojemnością pamięci. Mając N-bitowe wejście adresowe, możemy zaadresować 2N danych (obojętnie, ile bitów mają dane), czyli przykładowo 8-bitowa magistrala adresowa może obsłużyć maksymalnie 256 danych.
Pojemność pamięci to iloczyn liczby bitów danych oraz liczby wszystkich danych w pamięci. Przykładowo, pamięć obsługująca 1024 danych 8-bitowych ma pojemność 8 kilobitów. Pamięć 512 danych 16-bitowych również ma pojemność 8 kilobitów, ale to przecież nie jest taka sama pamięć! Podawanie pojemności pamięci bez informacji o jej organizacji stwarza możliwość nieporozumień. Z tego powodu dobrze jest podawać pojemność pamięci w formie 1024×8 lub 512×16.
W FPGA mamy dwa typy pamięci pod względem rodzaju używanych zasobów. Są to pamięć rozproszona (distributed memory) i blokowa (block memory). Pamięć rozproszona powstaje z uniwersalnych zasobów logicznych. Dzięki temu pamięć może mieć najróżniejszą architekturę oraz nietypowe funkcjonalności. Jednak jej wadą jest to, że pamięć rozproszona jest bardzo zasobochłonna i może się okazać, że nawet mała i nieskomplikowana pamięć rozproszona wymaga zastosowania dużego i drogiego układu FPGA.
W praktyce pamięć rozproszona jest stosowana tylko do prostych tablic lub bardzo nietypowych zastosowań. W naszym kursie już raz spotkaliśmy się z pamięcią rozproszoną, choć nie używałem wtedy takiej nazwy. Mowa o module Decoder7seg, którego używaliśmy do sterowania 7-segmentowym wyświetlaczem LED. Moduł ten zawierał tablicę (co prawda opisaną za pomocą instrukcji case) z szesnastoma 7-bitowymi stałymi. Każdej 4-bitowej liczbie binarnej był przypisany 7-bitowy kod, sterujący segmentami wyświetlacza. W gruncie rzeczy jest to asynchroniczna pamięć ROM. Wejście liczby do pokazania na wyświetlaczu można by nazwać 4-bitowym wejściem adresowym, a wyjście segmentów byłoby 7-bitowym wyjściem danych z pamięci.
Pamięć jest peryferium na tyle często stosowanym, że większość układów FPGA ma w swojej strukturze umieszczone gotowe bloki pamięci. Możemy je konfigurować na wiele sposóbów oraz łączyć, aby uzyskać większe bloki pamięci. W MachXO2 nazywają się EBR, czyli Embedded Block RAM, choć te bloki mogą funkcjonować także jako ROM. Układy MachXO2 mają także osobny blok pamięci Flash, ale nie będziemy go omawiać w tej części kursu.