Visible to Intel only — GUID: mwh1409959591173
Ixiasoft
Visible to Intel only — GUID: mwh1409959591173
Ixiasoft
2.4.2. Inferring ROM Functions from HDL Code
Because small ROMs typically achieve the best performance when they are implemented using the registers in regular logic, each ROM function must meet a minimum size requirement for inference and placement in memory.
Some synthesis tools provide options to control the implementation of inferred ROM blocks for Intel FPGA devices with synchronous memory blocks. For example, Intel® Quartus® Prime Standard Edition integrated synthesis provides the romstyle synthesis attribute to specify the type of memory block or to specify the use of regular logic instead of a dedicated memory block.
For device architectures with synchronous RAM blocks, such as the Arria® series, Cyclone® series, or Stratix® series devices, to infer a ROM block, synthesis must use registers for either the address or the output. When your design uses output registers, synthesis implements registers from the input registers of the RAM block without affecting the functionality of the ROM. If you register the address, the power-up state of the inferred ROM can be different from the HDL design. In this scenario, Intel® Quartus® Prime synthesis issues a warning.
The following ROM examples map directly to the Intel FPGA memory architecture.
Verilog HDL Synchronous ROM
module sync_rom (clock, address, data_out); input clock; input [7:0] address; output reg [5:0] data_out; reg [5:0] data_out; always @ (posedge clock) begin case (address) 8'b00000000: data_out = 6'b101111; 8'b00000001: data_out = 6'b110110; ... 8'b11111110: data_out = 6'b000001; 8'b11111111: data_out = 6'b101010; endcase end endmodule
VHDL Synchronous ROM
LIBRARY ieee; USE ieee.std_logic_1164.all; ENTITY sync_rom IS PORT ( clock: IN STD_LOGIC; address: IN STD_LOGIC_VECTOR(7 downto 0); data_out: OUT STD_LOGIC_VECTOR(5 downto 0) ); END sync_rom; ARCHITECTURE rtl OF sync_rom IS BEGIN PROCESS (clock) BEGIN IF rising_edge (clock) THEN CASE address IS WHEN "00000000" => data_out <= "101111"; WHEN "00000001" => data_out <= "110110"; ... WHEN "11111110" => data_out <= "000001"; WHEN "11111111" => data_out <= "101010"; WHEN OTHERS => data_out <= "101111"; END CASE; END IF; END PROCESS; END rtl;
Verilog HDL Dual-Port Synchronous ROM Using readmemb
module dual_port_rom #(parameter data_width=8, parameter addr_width=8) ( input [(addr_width-1):0] addr_a, addr_b, input clk, output reg [(data_width-1):0] q_a, q_b ); reg [data_width-1:0] rom[2**addr_width-1:0]; initial // Read the memory contents in the file //dual_port_rom_init.txt. begin $readmemb("dual_port_rom_init.txt", rom); end always @ (posedge clk) begin q_a <= rom[addr_a]; q_b <= rom[addr_b]; end endmodule
VHDL Dual-Port Synchronous ROM Using Initialization Function
library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; entity dual_port_rom is generic ( DATA_WIDTH : natural := 8; ADDR_WIDTH : natural := 8 ); port ( clk : in std_logic; addr_a : in natural range 0 to 2**ADDR_WIDTH - 1; addr_b : in natural range 0 to 2**ADDR_WIDTH - 1; q_a : out std_logic_vector((DATA_WIDTH -1) downto 0); q_b : out std_logic_vector((DATA_WIDTH -1) downto 0) ); end entity; architecture rtl of dual_port_rom is -- Build a 2-D array type for the ROM subtype word_t is std_logic_vector((DATA_WIDTH-1) downto 0); type memory_t is array(2**ADDR_WIDTH - 1 downto 0) of word_t; function init_rom return memory_t is variable tmp : memory_t := (others => (others => '0')); begin for addr_pos in 0 to 2**ADDR_WIDTH - 1 loop -- Initialize each address with the address itself tmp(addr_pos) := std_logic_vector(to_unsigned(addr_pos, DATA_WIDTH)); end loop; return tmp; end init_rom; -- Declare the ROM signal and specify a default initialization value. signal rom : memory_t := init_rom; begin process(clk) begin if (rising_edge(clk)) then q_a <= rom(addr_a); q_b <= rom(addr_b); end if; end process; end rtl;