Library of reusable VHDL components
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

671 lines
27 KiB

  1. --
  2. -- File Name: MemoryPkg.vhd
  3. -- Design Unit Name: MemoryPkg
  4. -- Revision: STANDARD VERSION
  5. --
  6. -- Maintainer: Jim Lewis email: jim@synthworks.com
  7. -- Contributor(s):
  8. -- Jim Lewis email: jim@synthworks.com
  9. --
  10. -- Description
  11. -- Package defines a protected type, MemoryPType, and methods
  12. -- for efficiently implementing memory data structures
  13. --
  14. -- Developed for:
  15. -- SynthWorks Design Inc.
  16. -- VHDL Training Classes
  17. -- 11898 SW 128th Ave. Tigard, Or 97223
  18. -- http://www.SynthWorks.com
  19. --
  20. -- Revision History:
  21. -- Date Version Description
  22. -- 05/2005: 0.1 Initial revision
  23. -- 06/2015: 2015.06 Updated for Alerts, ...
  24. -- Numerous revisions for VHDL Testbenches and Verification
  25. -- 01/2016: 2016.01 Update for buf.all(buf'left)
  26. -- 11/2016: 2016.11 Refinement to MemRead to return value, X (if X), U (if not initialized)
  27. --
  28. --
  29. -- Copyright (c) 2005 - 2016 by SynthWorks Design Inc. All rights reserved.
  30. --
  31. -- Verbatim copies of this source file may be used and
  32. -- distributed without restriction.
  33. --
  34. -- This source file is free software; you can redistribute it
  35. -- and/or modify it under the terms of the ARTISTIC License
  36. -- as published by The Perl Foundation; either version 2.0 of
  37. -- the License, or (at your option) any later version.
  38. --
  39. -- This source is distributed in the hope that it will be
  40. -- useful, but WITHOUT ANY WARRANTY; without even the implied
  41. -- warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
  42. -- PURPOSE. See the Artistic License for details.
  43. --
  44. -- You should have received a copy of the license with this source.
  45. -- If not download it from,
  46. -- http://www.perlfoundation.org/artistic_license_2_0
  47. --
  48. use std.textio.all ;
  49. library IEEE ;
  50. use IEEE.std_logic_1164.all ;
  51. use IEEE.numeric_std.all ;
  52. use IEEE.numeric_std_unsigned.all ;
  53. use IEEE.math_real.all ;
  54. use work.TextUtilPkg.all ;
  55. use work.TranscriptPkg.all ;
  56. use work.AlertLogPkg.all ;
  57. package MemoryPkg is
  58. type MemoryPType is protected
  59. ------------------------------------------------------------
  60. procedure MemInit ( AddrWidth, DataWidth : in integer ) ;
  61. ------------------------------------------------------------
  62. procedure MemWrite ( Addr, Data : in std_logic_vector ) ;
  63. ------------------------------------------------------------
  64. procedure MemRead (
  65. Addr : in std_logic_vector ;
  66. Data : out std_logic_vector
  67. ) ;
  68. impure function MemRead ( Addr : std_logic_vector ) return std_logic_vector ;
  69. ------------------------------------------------------------
  70. procedure MemErase ;
  71. procedure deallocate ;
  72. ------------------------------------------------------------
  73. procedure SetAlertLogID (A : AlertLogIDType) ;
  74. procedure SetAlertLogID (Name : string ; ParentID : AlertLogIDType := ALERTLOG_BASE_ID ; CreateHierarchy : Boolean := TRUE) ;
  75. impure function GetAlertLogID return AlertLogIDType ;
  76. ------------------------------------------------------------
  77. procedure FileReadH ( -- Hexadecimal File Read
  78. FileName : string ;
  79. StartAddr : std_logic_vector ;
  80. EndAddr : std_logic_vector
  81. ) ;
  82. procedure FileReadH (FileName : string ; StartAddr : std_logic_vector) ;
  83. procedure FileReadH (FileName : string) ;
  84. ------------------------------------------------------------
  85. procedure FileReadB ( -- Binary File Read
  86. FileName : string ;
  87. StartAddr : std_logic_vector ;
  88. EndAddr : std_logic_vector
  89. ) ;
  90. procedure FileReadB (FileName : string ; StartAddr : std_logic_vector) ;
  91. procedure FileReadB (FileName : string) ;
  92. ------------------------------------------------------------
  93. procedure FileWriteH ( -- Hexadecimal File Write
  94. FileName : string ;
  95. StartAddr : std_logic_vector ;
  96. EndAddr : std_logic_vector
  97. ) ;
  98. procedure FileWriteH (FileName : string ; StartAddr : std_logic_vector) ;
  99. procedure FileWriteH (FileName : string) ;
  100. ------------------------------------------------------------
  101. procedure FileWriteB ( -- Binary File Write
  102. FileName : string ;
  103. StartAddr : std_logic_vector ;
  104. EndAddr : std_logic_vector
  105. ) ;
  106. procedure FileWriteB (FileName : string ; StartAddr : std_logic_vector) ;
  107. procedure FileWriteB (FileName : string) ;
  108. end protected MemoryPType ;
  109. end MemoryPkg ;
  110. package body MemoryPkg is
  111. constant BLOCK_WIDTH : integer := 10 ;
  112. type MemoryPType is protected body
  113. type MemBlockType is array (integer range <>) of integer ;
  114. type MemBlockPtrType is access MemBlockType ;
  115. type MemArrayType is array (integer range <>) of MemBlockPtrType ;
  116. type ArrayPtrVarType is access MemArrayType ;
  117. variable ArrayPtrVar : ArrayPtrVarType := NULL ;
  118. variable AddrWidthVar : integer := -1 ; -- set by MemInit - merges addr length and initialized checks.
  119. variable DataWidthVar : natural := 1 ; -- set by MemInit
  120. variable BlockkWidthVar : natural := 0 ; -- set by MemInit
  121. variable AlertLogIDVar : AlertLogIDType := OSVVM_ALERTLOG_ID ;
  122. type FileFormatType is (BINARY, HEX) ;
  123. ------------------------------------------------------------
  124. procedure MemInit ( AddrWidth, DataWidth : In integer ) is
  125. ------------------------------------------------------------
  126. begin
  127. if AddrWidth <= 0 then
  128. Alert(AlertLogIDVar, "MemoryPType.MemInit. AddrWidth = " & to_string(AddrWidth) & " must be > 0.", FAILURE) ;
  129. return ;
  130. end if ;
  131. if DataWidth <= 0 then
  132. Alert(AlertLogIDVar, "MemoryPType.MemInit. DataWidth = " & to_string(DataWidth) & " must be > 0.", FAILURE) ;
  133. return ;
  134. end if ;
  135. AddrWidthVar := AddrWidth ;
  136. DataWidthVar := DataWidth ;
  137. BlockkWidthVar := minimum(BLOCK_WIDTH, AddrWidth) ;
  138. ArrayPtrVar := new MemArrayType(0 to 2**(AddrWidth-BlockkWidthVar)-1) ;
  139. end procedure MemInit ;
  140. ------------------------------------------------------------
  141. procedure MemWrite ( Addr, Data : in std_logic_vector ) is
  142. ------------------------------------------------------------
  143. variable BlockAddr, WordAddr : integer ;
  144. alias aAddr : std_logic_vector (Addr'length-1 downto 0) is Addr ;
  145. begin
  146. -- Check Bounds of Address and if memory is initialized
  147. if Addr'length /= AddrWidthVar then
  148. if (ArrayPtrVar = NULL) then
  149. Alert(AlertLogIDVar, "MemoryPType.MemWrite: Memory not initialized, Write Ignored.", FAILURE) ;
  150. else
  151. Alert(AlertLogIDVar, "MemoryPType.MemWrite: Addr'length: " & to_string(Addr'length) & " /= Memory Address Width: " & to_string(AddrWidthVar), FAILURE) ;
  152. end if ;
  153. return ;
  154. end if ;
  155. -- Check Bounds on Data
  156. if Data'length /= DataWidthVar then
  157. Alert(AlertLogIDVar, "MemoryPType.MemWrite: Data'length: " & to_string(Data'length) & " /= Memory Data Width: " & to_string(DataWidthVar), FAILURE) ;
  158. return ;
  159. end if ;
  160. if is_X( Addr ) then
  161. Alert(AlertLogIDVar, "MemoryPType.MemWrite: Address X, Write Ignored.") ;
  162. return ;
  163. end if ;
  164. -- Slice out upper address to form block address
  165. if aAddr'high >= BlockkWidthVar then
  166. BlockAddr := to_integer(aAddr(aAddr'high downto BlockkWidthVar)) ;
  167. else
  168. BlockAddr := 0 ;
  169. end if ;
  170. -- If empty, allocate a memory block
  171. if (ArrayPtrVar(BlockAddr) = NULL) then
  172. ArrayPtrVar(BlockAddr) := new MemBlockType(0 to 2**BlockkWidthVar-1) ;
  173. end if ;
  174. -- Address of a word within a block
  175. WordAddr := to_integer(aAddr(BlockkWidthVar -1 downto 0)) ;
  176. -- Write to BlockAddr, WordAddr
  177. if (Is_X(Data)) then
  178. ArrayPtrVar(BlockAddr)(WordAddr) := -1 ;
  179. else
  180. ArrayPtrVar(BlockAddr)(WordAddr) := to_integer( Data ) ;
  181. end if ;
  182. end procedure MemWrite ;
  183. ------------------------------------------------------------
  184. procedure MemRead (
  185. ------------------------------------------------------------
  186. Addr : In std_logic_vector ;
  187. Data : Out std_logic_vector
  188. ) is
  189. variable BlockAddr, WordAddr : integer ;
  190. alias aAddr : std_logic_vector (Addr'length-1 downto 0) is Addr ;
  191. begin
  192. -- Check Bounds of Address and if memory is initialized
  193. if Addr'length /= AddrWidthVar then
  194. if (ArrayPtrVar = NULL) then
  195. Alert(AlertLogIDVar, "MemoryPType.MemRead: Memory not initialized. Returning U", FAILURE) ;
  196. else
  197. Alert(AlertLogIDVar, "MemoryPType.MemRead: Addr'length: " & to_string(Addr'length) & " /= Memory Address Width: " & to_string(AddrWidthVar), FAILURE) ;
  198. end if ;
  199. Data := (Data'range => 'U') ;
  200. return ;
  201. end if ;
  202. -- Check Bounds on Data
  203. if Data'length /= DataWidthVar then
  204. Alert(AlertLogIDVar, "MemoryPType.MemRead: Data'length: " & to_string(Data'length) & " /= Memory Data Width: " & to_string(DataWidthVar), FAILURE) ;
  205. Data := (Data'range => 'U') ;
  206. return ;
  207. end if ;
  208. -- If Addr X, data = X
  209. if is_X( aAddr ) then
  210. Data := (Data'range => 'X') ;
  211. return ;
  212. end if ;
  213. -- Slice out upper address to form block address
  214. if aAddr'high >= BlockkWidthVar then
  215. BlockAddr := to_integer(aAddr(aAddr'high downto BlockkWidthVar)) ;
  216. else
  217. BlockAddr := 0 ;
  218. end if ;
  219. -- Empty Block, return all U
  220. if (ArrayPtrVar(BlockAddr) = NULL) then
  221. Data := (Data'range => 'U') ;
  222. return ;
  223. end if ;
  224. -- Address of a word within a block
  225. WordAddr := to_integer(aAddr(BlockkWidthVar -1 downto 0)) ;
  226. if ArrayPtrVar(BlockAddr)(WordAddr) >= 0 then
  227. -- Get the Word from the Array
  228. Data := to_slv(ArrayPtrVar(BlockAddr)(WordAddr), Data'length) ;
  229. elsif ArrayPtrVar(BlockAddr)(WordAddr) = -1 then
  230. -- X in Word, return all X
  231. Data := (Data'range => 'X') ;
  232. else
  233. -- Location Uninitialized, return all X
  234. Data := (Data'range => 'U') ;
  235. end if ;
  236. end procedure MemRead ;
  237. ------------------------------------------------------------
  238. impure function MemRead ( Addr : std_logic_vector ) return std_logic_vector is
  239. ------------------------------------------------------------
  240. variable BlockAddr, WordAddr : integer ;
  241. alias aAddr : std_logic_vector (Addr'length-1 downto 0) is Addr ;
  242. variable Data : std_logic_vector(DataWidthVar-1 downto 0) ;
  243. begin
  244. MemRead(Addr, Data) ;
  245. return Data ;
  246. end function MemRead ;
  247. ------------------------------------------------------------
  248. procedure MemErase is
  249. -- Deallocate the memory, but not the array of pointers
  250. ------------------------------------------------------------
  251. begin
  252. for BlockAddr in ArrayPtrVar'range loop
  253. if (ArrayPtrVar(BlockAddr) /= NULL) then
  254. deallocate (ArrayPtrVar(BlockAddr)) ;
  255. end if ;
  256. end loop ;
  257. end procedure ;
  258. ------------------------------------------------------------
  259. procedure deallocate is
  260. -- Deallocate all allocated memory
  261. ------------------------------------------------------------
  262. begin
  263. MemErase ;
  264. deallocate(ArrayPtrVar) ;
  265. AddrWidthVar := -1 ;
  266. DataWidthVar := 1 ;
  267. BlockkWidthVar := 0 ;
  268. end procedure ;
  269. ------------------------------------------------------------
  270. procedure SetAlertLogID (A : AlertLogIDType) is
  271. ------------------------------------------------------------
  272. begin
  273. AlertLogIDVar := A ;
  274. end procedure SetAlertLogID ;
  275. ------------------------------------------------------------
  276. procedure SetAlertLogID(Name : string ; ParentID : AlertLogIDType := ALERTLOG_BASE_ID ; CreateHierarchy : Boolean := TRUE) is
  277. ------------------------------------------------------------
  278. begin
  279. AlertLogIDVar := GetAlertLogID(Name, ParentID, CreateHierarchy) ;
  280. end procedure SetAlertLogID ;
  281. ------------------------------------------------------------
  282. impure function GetAlertLogID return AlertLogIDType is
  283. ------------------------------------------------------------
  284. begin
  285. return AlertLogIDVar ;
  286. end function GetAlertLogID ;
  287. ------------------------------------------------------------
  288. -- PT Local
  289. procedure FileReadX (
  290. -- Hexadecimal or Binary File Read
  291. ------------------------------------------------------------
  292. FileName : string ;
  293. DataFormat : FileFormatType ;
  294. StartAddr : std_logic_vector ;
  295. EndAddr : std_logic_vector
  296. ) is
  297. -- Format:
  298. -- @hh..h -- Address in hex
  299. -- hhh_XX_ZZ -- data values in hex - space delimited
  300. -- "--" or "//" -- comments
  301. file MemFile : text open READ_MODE is FileName ;
  302. variable Addr : std_logic_vector(AddrWidthVar - 1 downto 0) ;
  303. variable SmallAddr : std_logic_vector(AddrWidthVar - 1 downto 0) ;
  304. variable BigAddr : std_logic_vector(AddrWidthVar - 1 downto 0) ;
  305. variable Data : std_logic_vector(DataWidthVar - 1 downto 0) ;
  306. variable LineNum : natural ;
  307. variable ItemNum : natural ;
  308. variable AddrInc : std_logic_vector(AddrWidthVar - 1 downto 0) ;
  309. variable buf : line ;
  310. variable ReadValid : boolean ;
  311. variable Empty : boolean ;
  312. variable MultiLineComment : boolean ;
  313. variable NextChar : character ;
  314. variable StrLen : integer ;
  315. begin
  316. MultiLineComment := FALSE ;
  317. if StartAddr'length /= AddrWidthVar and EndAddr'length /= AddrWidthVar then
  318. if (ArrayPtrVar = NULL) then
  319. Alert(AlertLogIDVar, "MemoryPType.FileReadX: Memory not initialized, FileRead Ignored.", FAILURE) ;
  320. else
  321. Alert(AlertLogIDVar, "MemoryPType.FileReadX: Addr'length: " & to_string(Addr'length) & " /= Memory Address Width: " & to_string(AddrWidthVar), FAILURE) ;
  322. end if ;
  323. return ;
  324. end if ;
  325. Addr := StartAddr ;
  326. LineNum := 0 ;
  327. if StartAddr <= EndAddr then
  328. SmallAddr := StartAddr ;
  329. BigAddr := EndAddr ;
  330. AddrInc := (AddrWidthVar -1 downto 0 => '0') + 1 ;
  331. else
  332. SmallAddr := EndAddr ;
  333. BigAddr := StartAddr ;
  334. AddrInc := (others => '1') ; -- -1
  335. end if;
  336. ReadLineLoop : while not EndFile(MemFile) loop
  337. ReadLine(MemFile, buf) ;
  338. LineNum := LineNum + 1 ;
  339. ItemNum := 0 ;
  340. ItemLoop : loop
  341. EmptyOrCommentLine(buf, Empty, MultiLineComment) ;
  342. exit ItemLoop when Empty ;
  343. ItemNum := ItemNum + 1 ;
  344. NextChar := buf.all(buf'left) ;
  345. if (NextChar = '@') then
  346. -- Get Address
  347. read(buf, NextChar) ;
  348. ReadHexToken(buf, Addr, StrLen) ;
  349. exit ReadLineLoop when AlertIf(AlertLogIDVar, StrLen = 0, "MemoryPType.FileReadX: Address length 0 on line: " & to_string(LineNum), FAILURE) ;
  350. exit ItemLoop when AlertIf(AlertLogIDVar, Addr < SmallAddr,
  351. "MemoryPType.FileReadX: Address in file: " & to_hstring(Addr) &
  352. " < StartAddr: " & to_hstring(StartAddr) & " on line: " & to_string(LineNum)) ;
  353. exit ItemLoop when AlertIf(AlertLogIDVar, Addr > BigAddr,
  354. "MemoryPType.FileReadX: Address in file: " & to_hstring(Addr) &
  355. " > EndAddr: " & to_hstring(BigAddr) & " on line: " & to_string(LineNum)) ;
  356. elsif DataFormat = HEX and ishex(NextChar) then
  357. -- Get Hex Data
  358. ReadHexToken(buf, data, StrLen) ;
  359. exit ReadLineLoop when AlertIfNot(AlertLogIDVar, StrLen > 0,
  360. "MemoryPType.FileReadH: Error while reading data on line: " & to_string(LineNum) &
  361. " Item number: " & to_string(ItemNum), FAILURE) ;
  362. log("MemoryPType.FileReadX: MemWrite(Addr => " & to_hstring(Addr) & ", Data => " & to_hstring(Data) & ")", DEBUG) ;
  363. MemWrite(Addr, data) ;
  364. Addr := Addr + AddrInc ;
  365. elsif DataFormat = BINARY and isstd_logic(NextChar) then
  366. -- Get Binary Data
  367. -- read(buf, data, ReadValid) ;
  368. ReadBinaryToken(buf, data, StrLen) ;
  369. -- exit ReadLineLoop when AlertIfNot(AlertLogIDVar, ReadValid,
  370. exit ReadLineLoop when AlertIfNot(AlertLogIDVar, StrLen > 0,
  371. "MemoryPType.FileReadB: Error while reading data on line: " & to_string(LineNum) &
  372. " Item number: " & to_string(ItemNum), FAILURE) ;
  373. log("MemoryPType.FileReadX: MemWrite(Addr => " & to_hstring(Addr) & ", Data => " & to_string(Data) & ")", DEBUG) ;
  374. MemWrite(Addr, data) ;
  375. Addr := Addr + AddrInc ;
  376. else
  377. -- Invalid Text, Issue Warning and skip it
  378. Alert(AlertLogIDVar,
  379. "MemoryPType.FileReadX: Invalid text on line: " & to_string(LineNum) &
  380. " Item: " & to_string(ItemNum) & ". Skipping text: " & buf.all) ;
  381. exit ItemLoop ;
  382. end if ;
  383. end loop ItemLoop ;
  384. end loop ReadLineLoop ;
  385. -- -- must read EndAddr-StartAddr number of words if both start and end specified
  386. -- if (StartAddr /= 0 or (not EndAddr) /= 0) and (Addr /= EndAddr) then
  387. -- Alert("MemoryPType.FileReadH: insufficient data values", WARNING) ;
  388. -- end if ;
  389. file_close(MemFile) ;
  390. end FileReadX ;
  391. ------------------------------------------------------------
  392. procedure FileReadH (
  393. -- Hexadecimal File Read
  394. ------------------------------------------------------------
  395. FileName : string ;
  396. StartAddr : std_logic_vector ;
  397. EndAddr : std_logic_vector
  398. ) is
  399. begin
  400. FileReadX(FileName, HEX, StartAddr, EndAddr) ;
  401. end FileReadH ;
  402. ------------------------------------------------------------
  403. procedure FileReadH (FileName : string ; StartAddr : std_logic_vector) is
  404. -- Hexadecimal File Read
  405. ------------------------------------------------------------
  406. constant EndAddr : std_logic_vector(AddrWidthVar - 1 downto 0) := (others => '1') ;
  407. begin
  408. FileReadX(FileName, HEX, StartAddr, EndAddr) ;
  409. end FileReadH ;
  410. ------------------------------------------------------------
  411. procedure FileReadH (FileName : string) is
  412. -- Hexadecimal File Read
  413. ------------------------------------------------------------
  414. constant StartAddr : std_logic_vector(AddrWidthVar - 1 downto 0) := (others => '0') ;
  415. constant EndAddr : std_logic_vector(AddrWidthVar - 1 downto 0) := (others => '1') ;
  416. begin
  417. FileReadX(FileName, HEX, StartAddr, EndAddr) ;
  418. end FileReadH ;
  419. ------------------------------------------------------------
  420. procedure FileReadB (
  421. -- Binary File Read
  422. ------------------------------------------------------------
  423. FileName : string ;
  424. StartAddr : std_logic_vector ;
  425. EndAddr : std_logic_vector
  426. ) is
  427. begin
  428. FileReadX(FileName, BINARY, StartAddr, EndAddr) ;
  429. end FileReadB ;
  430. ------------------------------------------------------------
  431. procedure FileReadB (FileName : string ; StartAddr : std_logic_vector) is
  432. -- Binary File Read
  433. ------------------------------------------------------------
  434. constant EndAddr : std_logic_vector(AddrWidthVar - 1 downto 0) := (others => '1') ;
  435. begin
  436. FileReadX(FileName, BINARY, StartAddr, EndAddr) ;
  437. end FileReadB ;
  438. ------------------------------------------------------------
  439. procedure FileReadB (FileName : string) is
  440. -- Binary File Read
  441. ------------------------------------------------------------
  442. constant StartAddr : std_logic_vector(AddrWidthVar - 1 downto 0) := (others => '0') ;
  443. constant EndAddr : std_logic_vector(AddrWidthVar - 1 downto 0) := (others => '1') ;
  444. begin
  445. FileReadX(FileName, BINARY, StartAddr, EndAddr) ;
  446. end FileReadB ;
  447. ------------------------------------------------------------
  448. -- PT Local
  449. procedure FileWriteX (
  450. -- Hexadecimal or Binary File Write
  451. ------------------------------------------------------------
  452. FileName : string ;
  453. DataFormat : FileFormatType ;
  454. StartAddr : std_logic_vector ;
  455. EndAddr : std_logic_vector
  456. ) is
  457. -- Format:
  458. -- @hh..h -- Address in hex
  459. -- hhhhh -- data one per line in either hex or binary as specified
  460. file MemFile : text open WRITE_MODE is FileName ;
  461. alias normStartAddr : std_logic_vector(StartAddr'length-1 downto 0) is StartAddr ;
  462. alias normEndAddr : std_logic_vector(EndAddr'length-1 downto 0) is EndAddr ;
  463. variable StartBlockAddr : natural ;
  464. variable EndBlockAddr : natural ;
  465. variable StartWordAddr : natural ;
  466. variable EndWordAddr : natural ;
  467. variable Data : std_logic_vector(DataWidthVar - 1 downto 0) ;
  468. variable FoundData : boolean ;
  469. variable buf : line ;
  470. begin
  471. if StartAddr'length /= AddrWidthVar and EndAddr'length /= AddrWidthVar then
  472. -- Check StartAddr and EndAddr Widths and Memory not initialized
  473. if (ArrayPtrVar = NULL) then
  474. Alert(AlertLogIDVar, "MemoryPType.FileWriteX: Memory not initialized, FileRead Ignored.", FAILURE) ;
  475. else
  476. AlertIf(AlertLogIDVar, StartAddr'length /= AddrWidthVar, "MemoryPType.FileWriteX: StartAddr'length: "
  477. & to_string(StartAddr'length) &
  478. " /= Memory Address Width: " & to_string(AddrWidthVar), FAILURE) ;
  479. AlertIf(AlertLogIDVar, EndAddr'length /= AddrWidthVar, "MemoryPType.FileWriteX: EndAddr'length: "
  480. & to_string(EndAddr'length) &
  481. " /= Memory Address Width: " & to_string(AddrWidthVar), FAILURE) ;
  482. end if ;
  483. return ;
  484. end if ;
  485. if StartAddr > EndAddr then
  486. -- Only support ascending addresses
  487. Alert(AlertLogIDVar, "MemoryPType.FileWriteX: StartAddr: " & to_hstring(StartAddr) &
  488. " > EndAddr: " & to_hstring(EndAddr), FAILURE) ;
  489. return ;
  490. end if ;
  491. -- Slice out upper address to form block address
  492. if AddrWidthVar >= BlockkWidthVar then
  493. StartBlockAddr := to_integer(normStartAddr(AddrWidthVar-1 downto BlockkWidthVar)) ;
  494. EndBlockAddr := to_integer( normEndAddr(AddrWidthVar-1 downto BlockkWidthVar)) ;
  495. else
  496. StartBlockAddr := 0 ;
  497. EndBlockAddr := 0 ;
  498. end if ;
  499. BlockAddrLoop : for BlockAddr in StartBlockAddr to EndBlockAddr loop
  500. next BlockAddrLoop when ArrayPtrVar(BlockAddr) = NULL ;
  501. if BlockAddr = StartBlockAddr then
  502. StartWordAddr := to_integer(normStartAddr(BlockkWidthVar-1 downto 0)) ;
  503. else
  504. StartWordAddr := 0 ;
  505. end if ;
  506. if BlockAddr = EndBlockAddr then
  507. EndWordAddr := to_integer(normEndAddr(BlockkWidthVar-1 downto 0)) ;
  508. else
  509. EndWordAddr := 2**BlockkWidthVar-1 ;
  510. end if ;
  511. FoundData := FALSE ;
  512. WordAddrLoop : for WordAddr in StartWordAddr to EndWordAddr loop
  513. if (ArrayPtrVar(BlockAddr)(WordAddr) < 0) then
  514. -- X in Word, return all X
  515. Data := (Data'range => 'X') ;
  516. FoundData := FALSE ;
  517. else
  518. -- Get the Word from the Array
  519. Data := to_slv(ArrayPtrVar(BlockAddr)(WordAddr), Data'length) ;
  520. if not FoundData then
  521. -- Write Address
  522. write(buf, '@') ;
  523. hwrite(buf, to_slv(BlockAddr, AddrWidthVar-BlockkWidthVar) & to_slv(WordAddr, BlockkWidthVar)) ;
  524. writeline(MemFile, buf) ;
  525. end if ;
  526. FoundData := TRUE ;
  527. end if ;
  528. if FoundData then -- Write Data
  529. if DataFormat = HEX then
  530. hwrite(buf, Data) ;
  531. writeline(MemFile, buf) ;
  532. else
  533. write(buf, Data) ;
  534. writeline(MemFile, buf) ;
  535. end if;
  536. end if ;
  537. end loop WordAddrLoop ;
  538. end loop BlockAddrLoop ;
  539. file_close(MemFile) ;
  540. end FileWriteX ;
  541. ------------------------------------------------------------
  542. procedure FileWriteH (
  543. -- Hexadecimal File Write
  544. ------------------------------------------------------------
  545. FileName : string ;
  546. StartAddr : std_logic_vector ;
  547. EndAddr : std_logic_vector
  548. ) is
  549. begin
  550. FileWriteX(FileName, HEX, StartAddr, EndAddr) ;
  551. end FileWriteH ;
  552. ------------------------------------------------------------
  553. procedure FileWriteH (FileName : string ; StartAddr : std_logic_vector) is
  554. -- Hexadecimal File Write
  555. ------------------------------------------------------------
  556. constant EndAddr : std_logic_vector(AddrWidthVar - 1 downto 0) := (others => '1') ;
  557. begin
  558. FileWriteX(FileName, HEX, StartAddr, EndAddr) ;
  559. end FileWriteH ;
  560. ------------------------------------------------------------
  561. procedure FileWriteH (FileName : string) is
  562. -- Hexadecimal File Write
  563. ------------------------------------------------------------
  564. constant StartAddr : std_logic_vector(AddrWidthVar - 1 downto 0) := (others => '0') ;
  565. constant EndAddr : std_logic_vector(AddrWidthVar - 1 downto 0) := (others => '1') ;
  566. begin
  567. FileWriteX(FileName, HEX, StartAddr, EndAddr) ;
  568. end FileWriteH ;
  569. ------------------------------------------------------------
  570. procedure FileWriteB (
  571. -- Binary File Write
  572. ------------------------------------------------------------
  573. FileName : string ;
  574. StartAddr : std_logic_vector ;
  575. EndAddr : std_logic_vector
  576. ) is
  577. begin
  578. FileWriteX(FileName, BINARY, StartAddr, EndAddr) ;
  579. end FileWriteB ;
  580. ------------------------------------------------------------
  581. procedure FileWriteB (FileName : string ; StartAddr : std_logic_vector) is
  582. -- Binary File Write
  583. ------------------------------------------------------------
  584. constant EndAddr : std_logic_vector(AddrWidthVar - 1 downto 0) := (others => '1') ;
  585. begin
  586. FileWriteX(FileName, BINARY, StartAddr, EndAddr) ;
  587. end FileWriteB ;
  588. ------------------------------------------------------------
  589. procedure FileWriteB (FileName : string) is
  590. -- Binary File Write
  591. ------------------------------------------------------------
  592. constant StartAddr : std_logic_vector(AddrWidthVar - 1 downto 0) := (others => '0') ;
  593. constant EndAddr : std_logic_vector(AddrWidthVar - 1 downto 0) := (others => '1') ;
  594. begin
  595. FileWriteX(FileName, BINARY, StartAddr, EndAddr) ;
  596. end FileWriteB ;
  597. end protected body MemoryPType ;
  598. end MemoryPkg ;