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;