Dual-Port Block RAM with Two Write Ports and Byte-wide Write Enable in Read-First Mode

Initializing Block RAM from external intel hex file

1
-- 2 -- Dual-Port Block RAM with Two Write Ports and 3 -- Byte-wide Write Enable in Read-First Mode 4 -- 5 -- Initializing Block RAM from external intel hex file 6 -- 7 -- http://www.keil.com/support/docs/1584/ 8 -------------------------------------------------------------------- 9 -- http://en.wikipedia.org/wiki/Intel_HEX 10 -------------------------------------------------------------------- 11 -- 12 -- The format is a text file, with each line containing hexadecimal values 13 -- encoding a sequence of data and their starting offset or absolute address. 14 -- 15 -- There are three types of Intel HEX: 16 -- 8-bit, 16-bit, and 32-bit. They are distinguished by their byte order. 17 -- 18 -- Each line of Intel HEX file consists of six parts: 19 -- 20 -- Start code, one character, an ASCII colon ':'. 21 -- 22 -- Byte count, two hex digits, a number of bytes (hex digit pairs) in the data field. 23 -- 16 (0x10) or 32 (0x20) bytes of data are the usual compromise values 24 -- between line length and address overhead. 25 -- 26 -- Address, four hex digits, a 16-bit address of the beginning of the memory position for the data. 27 -- Limited to 64 kilobytes, the limit is worked around by specifying higher bits via additional record types. 28 -- This address is big endian. 29 -- 30 -- Record type, two hex digits, 00 to 05, defining the type of the data field. 31 -- 32 -- Data, a sequence of n bytes of the data themselves, represented by 2n hex digits. 33 -- 34 -- Checksum, two hex digits - the least significant byte of the two's complement 35 -- of the sum of the values of all fields except fields 1 and 6 36 -- (Start code ":" byte and two hex digits of the Checksum). 37 -- It is calculated by adding together the hex-encoded bytes (hex digit pairs), 38 -- then leaving only the least significant byte of the result, 39 -- and making a 2's complement (either by subtracting the byte from 0x100, 40 -- or inverting it by XOR-ing with 0xFF and adding 0x01). 41 -- If you are not working with 8-bit variables, 42 -- you must suppress the overflow by AND-ing the result with 0xFF. 43 -- The overflow may occur since both 0x100-0 and (0x00 XOR 0xFF)+1 equal 0x100. 44 -- If the checksum is correctly calculated, adding all the bytes 45 -- (the Byte count, both bytes in Address, the Record type, each Data byte and the Checksum) 46 -- together will always result in a value wherein the least significant byte is zero (0x00). 47 -- 48 -- For example, on :0300300002337A1E 49 -- 03 + 00 + 30 + 00 + 02 + 33 + 7A = E2, 2's complement is 1E 50 -- 51 -- There are six record types: 52 -- 00, data record, contains data and 16-bit address. The format described above. 53 -- 54 -- 01, End Of File record. 55 -- Must occur exactly once per file in the last line of the file. 56 -- The byte count is 00 and the data field is empty. 57 -- Usually the address field is also 0000, in which case the complete line is ':00000001FF'. 58 -- Originally the End Of File record could contain a start address for the program being loaded, 59 -- e.g. :00AB2F0125 would cause a jump to address AB2F. 60 -- This was convenient when programs were loaded from punched paper tape. 61 -- 62 -- 02, Extended Segment Address Record, segment-base address (two hex digit pairs in big endian order). 63 -- Used when 16 bits are not enough, identical to 80x86 real mode addressing. 64 -- The address specified by the data field of the most recent 02 record is 65 -- multiplied by 16 (shifted 4 bits left) and added to the subsequent 00 record addresses. 66 -- This allows addressing of up to a megabyte of address space. 67 -- The address field of this record has to be 0000, the byte count is 02 (the segment is 16-bit). 68 -- The least significant hex digit of the segment address is always 0. 69 -- 70 -- 03, Start Segment Address Record. For 80x86 processors, it specifies the initial content of the CS:IP registers. 71 -- The address field is 0000, the byte count is 04, 72 -- the first two bytes are the CS value, the latter two are the IP value. 73 -- 74 -- 04, Extended Linear Address Record, allowing for fully 32 bit addressing (up to 4GiB). 75 -- The address field is 0000, the byte count is 02. 76 -- The two data bytes (two hex digit pairs in big endian order) represent 77 -- the upper 16 bits of the 32 bit address for all subsequent 00 type records 78 -- until the next 04 type record comes. 79 -- If there is not a 04 type record, the upper 16 bits default to 0000. 80 -- To get the absolute address for subsequent 00 type records, 81 -- the address specified by the data field of the most recent 04 record is added to the 00 record addresses. 82 -- 83 -- 05, Start Linear Address Record. The address field is 0000, the byte count is 04. 84 -- The 4 data bytes represent the 32-bit value loaded into the EIP register of the 80386 and higher CPU. 85 86 -- 87 -- :10 0100 00 214601360121470136007EFE09D21901 40 88 -- :10 0110 00 2146017EB7C20001FF5F160021480119 88 89 -- :10 0120 00 194E79234623965778239EDA3F01B2CA A7 90 -- :10 0130 00 3F0156702B5E712B722B732146013421 C7 91 -- :00 0000 01 FF 92 -------------------------------------------------------------------- 93 94 library ieee; 95 use ieee.numeric_std.all; 96 use ieee.std_logic_1164.all; 97 use ieee.std_logic_textio.hread; 98 use std.textio.all; 99 100 entity dpram is 101 102 generic ( 103 HEX_FILE_NAME : string := "dpram.hex"; 104 ADDR_WIDTH : natural := 13; -- 32K BYTE = 8K DWORD 105 BYTE_WIDTH : natural := 8; -- always 8 106 BYTES : natural := 4); -- 1, 2, 4 107 108 port ( 109 clk1 : in std_logic; 110 en1 : in std_logic; 111 we1 : in std_logic_vector (BYTES - 1 downto 0); 112 addr1 : in std_logic_vector(ADDR_WIDTH - 1 downto 0); 113 data_in1 : in std_logic_vector(BYTES*BYTE_WIDTH - 1 downto 0); 114 data_out1 : out std_logic_vector(BYTES*BYTE_WIDTH-1 downto 0); 115 clk2 : in std_logic; 116 en2 : in std_logic; 117 we2 : in std_logic_vector (BYTES - 1 downto 0); 118 addr2 : in std_logic_vector(ADDR_WIDTH - 1 downto 0); 119 data_in2 : in std_logic_vector(BYTES*BYTE_WIDTH - 1 downto 0); 120 data_out2 : out std_logic_vector(BYTES*BYTE_WIDTH-1 downto 0)); 121 122 end dpram; 123 124 architecture rtl of dpram is 125 type ram_array_type is array (2 ** ADDR_WIDTH-1 downto 0) of std_logic_vector (BYTES*BYTE_WIDTH-1 downto 0); 126 type ram_byte_array_type is array (BYTES*(2 ** ADDR_WIDTH )-1 downto 0) of std_logic_vector (BYTE_WIDTH-1 downto 0); 127 128 impure function ram_init_from_hex_file (constant hex_file_name : in string) return ram_array_type is 129 file hex_file : text is in hex_file_name; 130 variable ram_array : ram_array_type; 131 variable ram_byte_array : ram_byte_array_type; 132 variable line_buf : line; 133 variable char : CHARACTER; 134 variable rec_type : STD_LOGIC_VECTOR( 7 downto 0); 135 variable byte : STD_LOGIC_VECTOR( 7 downto 0); 136 variable count : STD_LOGIC_VECTOR( 7 downto 0); 137 variable check : STD_LOGIC_VECTOR( 7 downto 0); 138 variable addr : unsigned(15 downto 0); 139 begin 140 -- clear all bytes 141 for i in 0 to BYTES*(2 ** ADDR_WIDTH )-1 loop 142 ram_byte_array( i ) := ( others => '0' ); 143 end loop; 144 145 -- load from hex file 146 while not endfile( hex_file ) loop 147 -- read line 148 readline(hex_file, line_buf); 149 150 -- read ':' from line 151 read(line_buf, char); 152 if char /= ':' then next; end if; -- go to next loop 153 -- read count from line 154 hread(line_buf, count); 155 -- read address from line 156 hread(line_buf, byte); addr(15 downto 8) := unsigned( byte ); 157 hread(line_buf, byte); addr( 7 downto 0) := unsigned( byte ); 158 159 -- check recored type 160 hread(line_buf, rec_type); 161 if rec_type = "00000001" then exit; end if; -- it is an end of file record 162 163 if rec_type = "00000000" then 164 -- read bytes from line 165 for i in 1 to to_integer( unsigned( count ) ) loop 166 hread(line_buf, byte); 167 ram_byte_array( to_integer( addr ) ) := byte; 168 169 addr := addr + 1; 170 end loop; 171 end if; 172 173 -- read checksum from line 174 hread(line_buf, check); 175 end loop; 176 177 -- convert ram_byte_array to ram_array 178 if BYTES = 4 then 179 for i in 0 to 2 ** ADDR_WIDTH-1 loop 180 ram_array( i ) := ram_byte_array( i * 4 + 3 ) 181 & ram_byte_array( i * 4 + 2 ) 182 & ram_byte_array( i * 4 + 1 ) 183 & ram_byte_array( i * 4 + 0 ); 184 end loop; 185 186 elsif BYTES = 2 then 187 for i in 0 to 2 ** ADDR_WIDTH-1 loop 188 ram_array( i ) := ram_byte_array( i * 2 + 1 ) 189 & ram_byte_array( i * 2 ) ; 190 end loop; 191 192 elsif BYTES = 1 then 193 for i in 0 to 2 ** ADDR_WIDTH-1 loop 194 ram_array( i ) := ram_byte_array( i ); 195 end loop; 196 197 end if; 198 199 return ram_array; 200 end function; 201 202 203 shared variable ram : ram_array_type := ram_init_from_hex_file(HEX_FILE_NAME); 204 attribute ram_style : string; 205 attribute ram_style of ram : variable is "block"; 206 207 type data_byte_array_type is array (BYTES-1 downto 0) of std_logic_vector (BYTE_WIDTH-1 downto 0); 208 signal data_in1_byte_array : data_byte_array_type; 209 signal data_in2_byte_array : data_byte_array_type; 210 signal data_out1_byte_array : data_byte_array_type; 211 signal data_out2_byte_array : data_byte_array_type; 212 213 signal data_in1_pack : std_logic_vector (BYTES*BYTE_WIDTH-1 downto 0); 214 signal data_in2_pack : std_logic_vector (BYTES*BYTE_WIDTH-1 downto 0); 215 signal data_out1_pack : std_logic_vector (BYTES*BYTE_WIDTH-1 downto 0); 216 signal data_out2_pack : std_logic_vector (BYTES*BYTE_WIDTH-1 downto 0); 217 218 begin 219 BYTES_1_generate : if BYTES = 1 generate 220 data_in1_pack <= data_in1_byte_array(0); 221 data_in2_pack <= data_in2_byte_array(0); 222 data_out1_pack <= data_out1_byte_array(0); 223 data_out2_pack <= data_out2_byte_array(0); 224 end generate BYTES_1_generate; 225 226 BYTES_2_generate : if BYTES = 2 generate 227 data_in1_pack <= data_in1_byte_array(1) & data_in1_byte_array(0); 228 data_in2_pack <= data_in2_byte_array(1) & data_in2_byte_array(0); 229 data_out1_pack <= data_out1_byte_array(1) & data_out1_byte_array(0); 230 data_out2_pack <= data_out2_byte_array(1) & data_out2_byte_array(0); 231 end generate BYTES_2_generate; 232 233 BYTES_4_generate : if BYTES = 4 generate 234 data_in1_pack <= data_in1_byte_array(3) & data_in1_byte_array(2) & data_in1_byte_array(1) & data_in1_byte_array(0); 235 data_in2_pack <= data_in2_byte_array(3) & data_in2_byte_array(2) & data_in2_byte_array(1) & data_in2_byte_array(0); 236 data_out1_pack <= data_out1_byte_array(3) & data_out1_byte_array(2) & data_out1_byte_array(1) & data_out1_byte_array(0); 237 data_out2_pack <= data_out2_byte_array(3) & data_out2_byte_array(2) & data_out2_byte_array(1) & data_out2_byte_array(0); 238 end generate BYTES_4_generate; 239 240 unpack : for i in 0 to BYTES - 1 generate 241 data_out1_byte_array(i) <= ram( to_integer( unsigned( addr1 ) ) ) ( (i+1)*BYTE_WIDTH-1 downto i*BYTE_WIDTH ) ; 242 data_out2_byte_array(i) <= ram( to_integer( unsigned( addr2 ) ) ) ( (i+1)*BYTE_WIDTH-1 downto i*BYTE_WIDTH ) ; 243 244 process( we1(i), data_in1, addr1 ) 245 begin 246 if we1(i) = '1' then 247 data_in1_byte_array(i) <= data_in1((i+1)*BYTE_WIDTH-1 downto i*BYTE_WIDTH ); 248 else 249 data_in1_byte_array(i) <= ram( to_integer( unsigned( addr1 ) ) ) ( (i+1)*BYTE_WIDTH-1 downto i*BYTE_WIDTH ) ; 250 end if; 251 end process; 252 253 process( we2(i), data_in2, addr2 ) 254 begin 255 if we2(i) = '1' then 256 data_in2_byte_array(i) <= data_in2((i+1)*BYTE_WIDTH-1 downto i*BYTE_WIDTH ); 257 else 258 data_in2_byte_array(i) <= ram( to_integer( unsigned( addr2 ) ) ) ( (i+1)*BYTE_WIDTH-1 downto i*BYTE_WIDTH ) ; 259 end if; 260 end process; 261 262 end generate unpack; 263 264 process(clk1) 265 begin 266 if(rising_edge(clk1)) then 267 if(en1 = '1') then 268 ram( to_integer( unsigned( addr1 ) ) ) := data_in1_pack; 269 data_out1 <= data_out1_pack; 270 end if; 271 end if; 272 end process; 273 274 process(clk2) 275 begin 276 if(rising_edge(clk2)) then 277 if(en2 = '1') then 278 ram( to_integer( unsigned( addr2 ) ) ) := data_in2_pack; 279 data_out2 <= data_out2_pack; 280 end if; 281 end if; 282 end process; 283 284 end rtl;
posted @ 2012-05-10 13:58  IAmAProgrammer  阅读(662)  评论(0编辑  收藏  举报