We now need to add a couple of Wizard generated components.
Then click "Generate".
In the Hierarchy window you will now have a "counter30" component. Click on it and then under the Processes tree select "View HDL Instantiation Template":
Copy and paste the useful bits into your top level project - add a signal "counter" to be connected to the output of the counter. Here’s the completed source:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
entity FlashyLights is
Port ( clk : in STD_LOGIC;
LEDs : out STD_LOGIC_VECTOR (7 downto 0));
end FlashyLights;
architecture Behavioral of FlashyLights is
COMPONENT counter30
PORT (
clk : IN STD_LOGIC;
q : OUT STD_LOGIC_VECTOR(29 DOWNTO 0)
);
END COMPONENT;
signal count : STD_LOGIC_VECTOR(30 downto 0);
begin
addr_counter : counter30
PORT MAP (
clk => clk,
q => count
);
end Behavioral;
Adding the ROM component
Add another new IP module called "memory", but this time select the Block Memory Generator:
The Block Memory Generator has 6 pages of settings - at the moment we only need to enter things on the first three. Just click "Next" on the first screen:
Select that we want a Single Port ROM, then click "Next":
Set "Read Width" to 8 - we have eight LEDs to light. Set the "Read Depth" to 1024. Click "Next":
Don’t bother going through the rest of the screens - they don’t apply at the moment - just click "Generate"
You will now have another component, and you can view its instantiation template.
Add it to the source, connecting the top 10 bits of the counter to the ROM’s address bus (addra), and the data bus (douta) to the LEDs:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
entity FlashyLights is
Port ( clk : in STD_LOGIC;
LEDs : out STD_LOGIC_VECTOR (7 downto 0));
end FlashyLights;
architecture Behavioral of FlashyLights is
COMPONENT counter30
PORT (
clk : IN STD_LOGIC;
q : OUT STD_LOGIC_VECTOR(29 DOWNTO 0)
);
END COMPONENT;
COMPONENT memory
PORT (
clka : IN STD_LOGIC;
addra : IN STD_LOGIC_VECTOR(9 DOWNTO 0);
douta : OUT STD_LOGIC_VECTOR(7 DOWNTO 0)
);
END COMPONENT;
signal count : STD_LOGIC_VECTOR(29 downto 0);
begin
addr_counter : counter30
PORT MAP (
clk => clk,
q => count
);
rom_memory: memory
PORT MAP (
clka => clk,
addra => count(29 downto 20),
douta => LEDs
);
end Behavioral;
Once built, you can view the RTL schematic - looks as you would expect:
Setting the contents of the ROM
At the moment the ROM is blank (all ’0’s). When the FPGA is configured, the contents of the block RAM can be set to values that are predefined in the configuration bit stream.
Page 4 of the Block Memory Generator gives you the option to set the contents of the ROM using a ".coe" file. Here’s enough of the file that you will be able to write your own from scratch:
memory_initialization_radix=10;
memory_initialization_vector=
128,
128,
127,
127,
127,
Here’s another, using binary (as memory_initialization_radix=2) for a memory with a data width of 15:
memory_initialization_radix=2;
memory_initialization_vector=
001110000000001,
010110000000010,
000010000000011,
000010000000100,
000010000000101,
000010000000110,
Create a sample file of 8 bit binary values - make the 1 bits zig-zag from left to right, or some other pattern - the more lines the merrier. Call it "flashy.coe".
Edit the "memory" component (just double-click it in the Hierarchy tree) and skip through to Page 4. Set the initialisation file to flashy.coe.
It is always a good idea to click on the "Show" button - it will give you a warning if your .coe file is not correct. Click the Generate button to update the IP module.
As an aside, there are other ways to do this, allowing you to inject contents (e.g., maybe bootloader) after the .bit file is built. This allows you to avoid a lengthy rebuild of a whole project just to change the initial values in a BRAM. It is also a good way to allow an end-user to customise the .bit file without providing access to your source code. Search for "Xilinx data2mem" on Google.
The finishing touches
NET LEDs(7) LOC = "P5" | IOSTANDARD=LVCMOS25;
NET LEDs(6) LOC = "P9" | IOSTANDARD=LVCMOS25;
NET LEDs(5) LOC = "P10" | IOSTANDARD=LVCMOS25;
NET LEDs(4) LOC = "P11" | IOSTANDARD=LVCMOS25;
NET LEDs(3) LOC = "P12" | IOSTANDARD=LVCMOS25;
NET LEDs(2) LOC = "P15" | IOSTANDARD=LVCMOS25;
NET LEDs(1) LOC = "P16" | IOSTANDARD=LVCMOS25;
NET LEDs(0) LOC = "P17" | IOSTANDARD=LVCMOS25;
NET "clk" LOC="P89" | IOSTANDARD=LVCMOS25 | PERIOD=31.25ns;
Rebuild the project, download it and watch the lights!