ECE351 Digital Systems Design, Spring 2016 Lab 2 Background information: The Xilinx Spartan3E FPGA on the Basys2 board contains embedded memory resources, specifically: • • Distributed RAM can use the LUTs of CLBs that are not otherwise allocated for logic functions. Each Spartan3E CLB has 8 LUTs and each LUT is 16*1 bits. Distributed RAM supports o Single-port RAM (64 bits per CLB) with sync write [into RAM at a clock edge] and async read using a single input address bus. o Dual-port RAM (32 bits per CLB) with one sync write port and two async, but independent, read ports using two input address buses. o Single-port ROM (128 bits per CLB) with no write capabilities. Block RAM (BRAM) is separate and not part of the CLBs. The BRAM on the Spartan3E o Consists of four blocks of 18kbits each. o Is synchronous, so writes and reads are always clocked. o Physically is dual-port but can simulate single-port. o Has data flow options Read-After-Write, Read-Before-Write, or No-ReadOn-Write (selected on WRITE MODE in CORE GENERATOR). Since BRAM on the Spartan3E has sync reads only, RAM for async read would have to be distributed RAM. Unless you really want to control the implementation, you can let XST manage RAM resources on the FPGA. Refer to the technical document “Using Block RAM in Spartan-3 Generation FPGAs” for more technical details. Table 2 of “Using Block RAM in Spartan-3 Generation FPGAs” shows that the Spartan3E100’s 72kbits BRAM is partitioned into four blocks of 18kbits, and Table 3 shows that the BRAM can be configured in several ways, some with and some without parity bits: 16k*1, 8k*2, 4k*4, …, 512*36, 256*72. The Look-up Tables note states that each LUT in a CLB implements a 16*1 RAM with synchronous writes and async reads. Its Table 1 lists LUT memory capabilities and Table 2 lists single- and double-port distributed RAM configurability. Generally speaking, you can implement RAM by 1. Your own VHDL code written in the style of XST HDL Coding Technology where you define TYPE RAM_TYPE as a 1-D array (the index is the RAM address) of std_logic vectors (the bit-words in memory) 2. Xilinx ISE IP core generation for a RAM component that you customize to your needs. You also have several ways to initialize the values in RAM or ROM. One way is by initializing a signal in an architecture block, for example using hex notation: type ram_type is array(0 to 63) of std_logic_vector(15 downto 0); signal RAM: ram_type := (X”020A”, X”C300”, …); Other ways of initialization include use of the predefined package TEXTIO in the libaray std to load an external text file, or to use CORE GENERATOR to initialize the Memory component. Lab tasks: The object of this lab is to use a binary counter to step through all addresses of BRAM and display the initialized words on the LEDs. The memory is small so you don’t have many initial values to type or display. Task 1: Using XST HDL Coding Technology guides, write your own VHDL code (50%): • Implement single-port BRAM with 8 addresses and 16-bit words. • Use signal initialization like (0xFFFF, 0xEEEE, …) for the BRAM. Task 2: Step through the BRAM addresses (50%): • • Implement a 3-bit cyclic up-counter to single-step through the addresses with debounced BTN0 (use core IP counter if you want to). Step through BRAM addresses and display the word a 4 hex digits on 7-segment displays AN3-AN0. In your short write-up, be sure to state which data flow option you implement: Read-After-Write or one of the others.