test_generation.py 52 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277
  1. #!/usr/bin/env python
  2. #
  3. # Copyright 2021 Espressif Systems (Shanghai) CO LTD
  4. #
  5. # Licensed under the Apache License, Version 2.0 (the "License");
  6. # you may not use this file except in compliance with the License.
  7. # You may obtain a copy of the License at
  8. #
  9. # http://www.apache.org/licenses/LICENSE-2.0
  10. #
  11. # Unless required by applicable law or agreed to in writing, software
  12. # distributed under the License is distributed on an "AS IS" BASIS,
  13. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. # See the License for the specific language governing permissions and
  15. # limitations under the License.
  16. #
  17. import collections
  18. import fnmatch
  19. import os
  20. import sys
  21. import tempfile
  22. import unittest
  23. try:
  24. from generation import Generation, GenerationException
  25. except ImportError:
  26. sys.path.append('../')
  27. from generation import Generation, GenerationException
  28. from io import StringIO
  29. from entity import Entity, EntityDB
  30. from fragments import FragmentFile
  31. from linker_script import LinkerScript
  32. from output_commands import InputSectionDesc
  33. from sdkconfig import SDKConfig
  34. ROOT = Entity('*')
  35. FREERTOS = Entity('libfreertos.a')
  36. CROUTINE = Entity('libfreertos.a', 'croutine')
  37. TIMERS = Entity('libfreertos.a', 'timers')
  38. FREERTOS2 = Entity('libfreertos2.a')
  39. class GenerationTest(unittest.TestCase):
  40. def setUp(self):
  41. self.generation = Generation()
  42. self.entities = None
  43. self.linker_script = None
  44. with tempfile.NamedTemporaryFile(delete=False) as f:
  45. self.kconfigs_source_file = os.path.join(tempfile.gettempdir(), f.name)
  46. self.addCleanup(os.remove, self.kconfigs_source_file)
  47. with tempfile.NamedTemporaryFile(delete=False) as f:
  48. self.kconfig_projbuilds_source_file = os.path.join(tempfile.gettempdir(), f.name)
  49. self.addCleanup(os.remove, self.kconfig_projbuilds_source_file)
  50. os.environ['COMPONENT_KCONFIGS_SOURCE_FILE'] = self.kconfigs_source_file
  51. os.environ['COMPONENT_KCONFIGS_PROJBUILD_SOURCE_FILE'] = self.kconfig_projbuilds_source_file
  52. os.environ['COMPONENT_KCONFIGS'] = ''
  53. os.environ['COMPONENT_KCONFIGS_PROJBUILD'] = ''
  54. # prepare_kconfig_files.py doesn't have to be called because COMPONENT_KCONFIGS and
  55. # COMPONENT_KCONFIGS_PROJBUILD are empty
  56. self.sdkconfig = SDKConfig('data/Kconfig', 'data/sdkconfig')
  57. with open('data/base.lf') as fragment_file_obj:
  58. fragment_file = FragmentFile(fragment_file_obj, self.sdkconfig)
  59. self.generation.add_fragments_from_file(fragment_file)
  60. self.entities = EntityDB()
  61. with open('data/libfreertos.a.txt') as objdump:
  62. self.entities.add_sections_info(objdump)
  63. with open('data/linker_script.ld') as linker_script:
  64. self.linker_script = LinkerScript(linker_script)
  65. @staticmethod
  66. def create_fragment_file(contents, name='test_fragment.lf'):
  67. f = StringIO(contents)
  68. f.name = name
  69. return f
  70. def add_fragments(self, text):
  71. fragment_file = self.create_fragment_file(text)
  72. fragment_file = FragmentFile(fragment_file, self.sdkconfig)
  73. self.generation.add_fragments_from_file(fragment_file)
  74. def write(self, expected, actual):
  75. self.linker_script.fill(expected)
  76. self.linker_script.write(open('expected.ld', 'w'))
  77. self.linker_script.fill(actual)
  78. self.linker_script.write(open('actual.ld', 'w'))
  79. def generate_default_rules(self):
  80. rules = collections.defaultdict(list)
  81. rules['dram0_data'].append(InputSectionDesc(ROOT, ['.data', '.data.*'], []))
  82. rules['dram0_data'].append(InputSectionDesc(ROOT, ['.dram', '.dram.*'], []))
  83. rules['dram0_bss'].append(InputSectionDesc(ROOT, ['.bss', '.bss.*'], []))
  84. rules['dram0_bss'].append(InputSectionDesc(ROOT, ['COMMON'], []))
  85. rules['flash_text'].append(InputSectionDesc(ROOT, ['.literal', '.literal.*', '.text', '.text.*'], []))
  86. rules['flash_rodata'].append(InputSectionDesc(ROOT, ['.rodata', '.rodata.*'], []))
  87. rules['iram0_text'].append(InputSectionDesc(ROOT, ['.iram', '.iram.*'], []))
  88. rules['rtc_bss'].append(InputSectionDesc(ROOT, ['.rtc.bss'], []))
  89. rules['rtc_data'].append(InputSectionDesc(ROOT, ['.rtc.data'], []))
  90. rules['rtc_data'].append(InputSectionDesc(ROOT, ['.rtc.rodata'], []))
  91. rules['rtc_text'].append(InputSectionDesc(ROOT, ['.rtc.text', '.rtc.literal'], []))
  92. return rules
  93. def compare_rules(self, expected, actual):
  94. self.assertEqual(expected, actual)
  95. def get_default(self, target, rules):
  96. return rules[target][0]
  97. def test_rule_generation_default(self):
  98. # Checks that default rules are generated from
  99. # the default scheme properly and even if no mappings
  100. # are defined.
  101. actual = self.generation.generate_rules(self.entities)
  102. expected = self.generate_default_rules()
  103. self.compare_rules(expected, actual)
  104. class DefaultMappingTest(GenerationTest):
  105. def test_default_mapping_lib(self):
  106. # Mapping a library with default mapping. This should not emit additional rules,
  107. # other than the default ones.
  108. mapping = u"""
  109. [mapping:test]
  110. archive: libfreertos.a
  111. entries:
  112. * (default)
  113. """
  114. self.add_fragments(mapping)
  115. self.test_rule_generation_default()
  116. def test_default_mapping_obj(self):
  117. # Mapping an object with default mapping. This should not emit additional rules,
  118. # other than the default ones.
  119. mapping = u"""
  120. [mapping:test]
  121. archive: libfreertos.a
  122. entries:
  123. croutine (default)
  124. """
  125. self.add_fragments(mapping)
  126. self.test_rule_generation_default()
  127. def test_default_mapping_symbol(self):
  128. # Mapping a symbol with default mapping. This should not emit additional rules,
  129. # other than the default ones.
  130. mapping = u"""
  131. [mapping:test]
  132. archive: libfreertos.a
  133. entries:
  134. croutine:prvCheckPendingReadyList (default) #1
  135. """
  136. self.add_fragments(mapping)
  137. self.test_rule_generation_default()
  138. def test_default_mapping_all(self):
  139. # Mapping a library, object, and symbol with default mapping. This should not emit additional rules,
  140. # other than the default ones.
  141. mapping = u"""
  142. [mapping:test]
  143. archive: libfreertos.a
  144. entries:
  145. * (default) #1
  146. croutine (default) #2
  147. croutine:prvCheckPendingReadyList (default) #3
  148. """
  149. self.add_fragments(mapping)
  150. self.test_rule_generation_default()
  151. def test_default_mapping_lib_symbol(self):
  152. # Mapping a library, and symbol with default mapping. This should not emit additional rules,
  153. # other than the default ones.
  154. #
  155. # This is a check needed to make sure generation does not generate
  156. # intermediate commands due to presence of symbol mapping.
  157. mapping = u"""
  158. [mapping:test]
  159. archive: libfreertos.a
  160. entries:
  161. * (default) #1
  162. croutine:prvCheckPendingReadyList (default) #2
  163. """
  164. self.add_fragments(mapping)
  165. self.test_rule_generation_default()
  166. def test_default_mapping_obj_symbol(self):
  167. # Mapping a library, and symbol with default mapping. This should not emit additional rules,
  168. # other than the default ones.
  169. #
  170. # This is a check needed to make sure generation does not generate
  171. # intermediate commands due to presence of symbol mapping.
  172. mapping = u"""
  173. [mapping:test]
  174. archive: libfreertos.a
  175. entries:
  176. croutine (default) #1
  177. croutine:prvCheckPendingReadyList (default) #2
  178. """
  179. self.add_fragments(mapping)
  180. self.test_rule_generation_default()
  181. class BasicTest(GenerationTest):
  182. # Test basic and fundamental interactions between typical
  183. # entries.
  184. def test_nondefault_mapping_lib(self, alt=None):
  185. # Test mapping entry different from default for a library.
  186. # There should be exclusions in the default commands for flash_text and flash_rodata:
  187. #
  188. # flash_text
  189. # *((EXCLUDE_FILE(libfreertos.a)) .literal ...) A
  190. #
  191. # Commands placing the entire library in iram, dram should be generated:
  192. #
  193. # iram0_text
  194. # *(.iram ...)
  195. # *libfreertos.a(.literal ...) B
  196. mapping = u"""
  197. [mapping:test]
  198. archive: libfreertos.a
  199. entries:
  200. * (noflash) #1
  201. """
  202. self.add_fragments(alt if alt else mapping)
  203. actual = self.generation.generate_rules(self.entities)
  204. expected = self.generate_default_rules()
  205. flash_text = expected['flash_text']
  206. flash_rodata = expected['flash_rodata']
  207. iram0_text = expected['iram0_text']
  208. dram0_data = expected['dram0_data']
  209. # Generate exclusions in flash_text and flash_rodata A
  210. flash_text[0].exclusions.add(FREERTOS)
  211. flash_rodata[0].exclusions.add(FREERTOS)
  212. # Input section commands in iram_text and dram0_data for #1 B
  213. iram0_text.append(InputSectionDesc(FREERTOS, flash_text[0].sections, []))
  214. dram0_data.append(InputSectionDesc(FREERTOS, flash_rodata[0].sections, []))
  215. self.compare_rules(expected, actual)
  216. def test_nondefault_mapping_obj(self, alt=None):
  217. # Test mapping entry different from default for an object.
  218. # There should be exclusions in the default commands for flash_text and flash_rodata:
  219. #
  220. # flash_text
  221. # *((EXCLUDE_FILE(libfreertos.a:croutine)) .literal ...) A
  222. #
  223. # Commands placing the entire library in iram, dram should be generated:
  224. #
  225. # iram0_text
  226. # *(.iram ...)
  227. # *libfreertos.a:croutine(.literal ...) B
  228. mapping = u"""
  229. [mapping:test]
  230. archive: libfreertos.a
  231. entries:
  232. croutine (noflash) #1
  233. """
  234. self.add_fragments(alt if alt else mapping)
  235. actual = self.generation.generate_rules(self.entities)
  236. expected = self.generate_default_rules()
  237. flash_text = expected['flash_text']
  238. flash_rodata = expected['flash_rodata']
  239. iram0_text = expected['iram0_text']
  240. dram0_data = expected['dram0_data']
  241. # Generate exclusions in flash_text and flash_rodata A
  242. flash_text[0].exclusions.add(CROUTINE)
  243. flash_rodata[0].exclusions.add(CROUTINE)
  244. # Input section commands in iram_text and dram0_data for #1 B
  245. iram0_text.append(InputSectionDesc(CROUTINE, flash_text[0].sections, []))
  246. dram0_data.append(InputSectionDesc(CROUTINE, flash_rodata[0].sections, []))
  247. self.compare_rules(expected, actual)
  248. def test_nondefault_mapping_symbol(self):
  249. # Test mapping entry different from default for symbol.
  250. # There should be exclusions in the default commands for flash_text, as well as the implicit intermediate object command
  251. # with an exclusion from default:
  252. #
  253. # flash_text
  254. # *((EXCLUDE_FILE(libfreertos.a:croutine)) .literal ...) A
  255. # *libfreertos.a:croutine(.literal .literal.prvCheckDelayedList ...) B
  256. #
  257. # Commands placing the entire library in iram should be generated:
  258. #
  259. # iram0_text
  260. # *(.iram ...)
  261. # *libfreertos.a:croutine(.text.prvCheckPendingReadyList .literal.prvCheckPendingReadyList) C
  262. mapping = u"""
  263. [mapping:test]
  264. archive: libfreertos.a
  265. entries:
  266. croutine:prvCheckPendingReadyList (noflash) #1
  267. """
  268. self.add_fragments(mapping)
  269. actual = self.generation.generate_rules(self.entities)
  270. expected = self.generate_default_rules()
  271. flash_text = expected['flash_text']
  272. iram0_text = expected['iram0_text']
  273. # Generate exclusion in flash_text A
  274. flash_text[0].exclusions.add(CROUTINE)
  275. # Generate intermediate command B
  276. # List all relevant sections except the symbol
  277. # being mapped
  278. croutine_sections = self.entities.get_sections('libfreertos.a', 'croutine')
  279. filtered_sections = fnmatch.filter(croutine_sections, '.literal.*')
  280. filtered_sections.extend(fnmatch.filter(croutine_sections, '.text.*'))
  281. filtered_sections = [s for s in filtered_sections if not s.endswith('prvCheckPendingReadyList')]
  282. filtered_sections.append('.text')
  283. flash_text.append(InputSectionDesc(CROUTINE, set(filtered_sections), []))
  284. # Input section commands in iram_text for #1 C
  285. iram0_text.append(InputSectionDesc(CROUTINE, set(['.text.prvCheckPendingReadyList', '.literal.prvCheckPendingReadyList']), []))
  286. self.compare_rules(expected, actual)
  287. def test_default_symbol_nondefault_lib(self):
  288. # Test default symbol mapping with different lib mapping. This should create an implicit intermediate object command.
  289. # The significant targets are flash_text, flash_rodata, iram0_text, dram0_data.
  290. #
  291. # flash_text
  292. # *(EXCLUDE_FILE(libfreertos.a) .text ...) A
  293. # libfreertos.a:croutine (.text.prvCheckPendingReadyList .literal.prvCheckPendingReadyList) B
  294. #
  295. # flash_rodata
  296. # *(EXCLUDE_FILE(libfreertos.a) .rodata ...) A
  297. #
  298. # iram0_text
  299. # * ( .iram ...)
  300. # libfreertos.a (EXCLUDE_FILE(libfreertos:croutine) .text ...) C.1
  301. # *libfreertos.a:croutine(.literal .literal.prvCheckDelayedList ...) D
  302. #
  303. # dram0_data
  304. # * ( .dram ...)
  305. # libfreertos.a ( .rodata ...) C.2
  306. #
  307. # Only default commands are in the other targets.
  308. mapping = u"""
  309. [mapping:test]
  310. archive: libfreertos.a
  311. entries:
  312. * (noflash) #1
  313. croutine:prvCheckPendingReadyList (default) #2
  314. """
  315. self.add_fragments(mapping)
  316. actual = self.generation.generate_rules(self.entities)
  317. expected = self.generate_default_rules()
  318. flash_text = expected['flash_text']
  319. flash_rodata = expected['flash_rodata']
  320. iram0_text = expected['iram0_text']
  321. dram0_data = expected['dram0_data']
  322. # Exclusions for #1 A
  323. flash_text[0].exclusions.add(FREERTOS)
  324. flash_rodata[0].exclusions.add(FREERTOS)
  325. # Commands for #1 C.1 & C.2
  326. # C.1 excludes intermediate command for #2
  327. iram0_text.append(InputSectionDesc(FREERTOS, flash_text[0].sections, [CROUTINE]))
  328. dram0_data.append(InputSectionDesc(FREERTOS, flash_rodata[0].sections, []))
  329. # Intermediate command for excluding #2 D
  330. croutine_sections = self.entities.get_sections('libfreertos.a', 'croutine')
  331. filtered_sections = fnmatch.filter(croutine_sections, '.literal.*')
  332. filtered_sections.extend(fnmatch.filter(croutine_sections, '.text.*'))
  333. filtered_sections = [s for s in filtered_sections if not s.endswith('prvCheckPendingReadyList')]
  334. filtered_sections.append('.text')
  335. iram0_text.append(InputSectionDesc(CROUTINE, set(filtered_sections), []))
  336. # Command for #2 B
  337. flash_text.append(InputSectionDesc(CROUTINE, set(['.text.prvCheckPendingReadyList', '.literal.prvCheckPendingReadyList']), []))
  338. self.compare_rules(expected, actual)
  339. def test_default_symbol_nondefault_obj(self):
  340. # Test default symbol mapping with different obj mapping. Since there is an explicit entry for the object,
  341. # the sections for that object should just be expanded and the symbol section subtracted, to be placed
  342. # using another command.
  343. #
  344. # flash_text
  345. # *(EXCLUDE_FILE(libfreertos.a:croutine) .text ...) A
  346. # libfreertos.a:croutine (.text.prvCheckPendingReadyList .literal.prvCheckPendingReadyList) B
  347. #
  348. # flash_rodata
  349. # *(EXCLUDE_FILE(libfreertos.a:croutine) .rodata ...) A
  350. #
  351. # iram0_text
  352. # *( .iram ...)
  353. # *libfreertos.a:croutine(.literal .literal.prvCheckDelayedList ...) C.1
  354. #
  355. # dram0_data
  356. # *(.data ..)
  357. # *libfreertos.a:croutine(.rodata ....) C.2
  358. #
  359. # Only default commands are in the other targets
  360. mapping = u"""
  361. [mapping:test]
  362. archive: libfreertos.a
  363. entries:
  364. croutine (noflash) #1
  365. croutine:prvCheckPendingReadyList (default) #2
  366. """
  367. self.add_fragments(mapping)
  368. actual = self.generation.generate_rules(self.entities)
  369. expected = self.generate_default_rules()
  370. flash_text = expected['flash_text']
  371. flash_rodata = expected['flash_rodata']
  372. iram0_text = expected['iram0_text']
  373. dram0_data = expected['dram0_data']
  374. # Exclusions for #1 A
  375. flash_text[0].exclusions.add(CROUTINE)
  376. flash_rodata[0].exclusions.add(CROUTINE)
  377. # Commands for #1 C.1 & C.2
  378. # C.1 list relevant sections for libfreertos.a:croutine to
  379. # exclude symbol to map
  380. croutine_sections = self.entities.get_sections('libfreertos.a', 'croutine')
  381. filtered_sections = fnmatch.filter(croutine_sections, '.literal.*')
  382. filtered_sections.extend(fnmatch.filter(croutine_sections, '.text.*'))
  383. filtered_sections = [s for s in filtered_sections if not s.endswith('prvCheckPendingReadyList')]
  384. filtered_sections.append('.text')
  385. iram0_text.append(InputSectionDesc(CROUTINE, set(filtered_sections), []))
  386. dram0_data.append(InputSectionDesc(CROUTINE, flash_rodata[0].sections, []))
  387. # Command for #2 B
  388. flash_text.append(InputSectionDesc(CROUTINE, set(['.text.prvCheckPendingReadyList', '.literal.prvCheckPendingReadyList']), []))
  389. self.compare_rules(expected, actual)
  390. def test_default_nondefault_alternating(self):
  391. # Here, each of the entries map sections to something different
  392. # than its one-level-up entry.
  393. #
  394. # * text -> flash, rodata -> flash
  395. # libfreertos.a text -> iram, rodata -> dram
  396. # libfreertos.a:croutine text -> flash, rodata -> flash
  397. # croutine:prvCheckPendingReadyList text -> iram
  398. #
  399. # The significant targets are flash_text, flash_rodata, iram0_text, and dram0_data.
  400. #
  401. # flash_text
  402. # *(EXCLUDE_FILE(libfreertos.a) .text ...) A
  403. # *libfreertos.a:croutine(.literal .literal.prvCheckDelayedList ...) B.1
  404. #
  405. # flash_rodata
  406. # *(EXCLUDE_FILE(libfreertos.a) .rodata ...) A
  407. # *libfreertos.a:croutine(.rodata .rodata.*) B.2
  408. #
  409. # iram0_text
  410. # * ( .iram ...)
  411. # libfreertos.a (EXCLUDE_FILE(libfreertos:croutine) .text ...) C
  412. # libfreertos.a:croutine (.text.prvCheckPendingReadyList .literal.prvCheckPendingReadyList) D
  413. #
  414. # dram0_data
  415. # * ( .dram ...)
  416. # libfreertos.a (EXCLUDE_FILE(libfreertos:croutine) .rodata ...) C
  417. #
  418. # For the other targets only the default commands should be present.
  419. mapping = u"""
  420. [mapping:test]
  421. archive: libfreertos.a
  422. entries:
  423. * (noflash) #1
  424. croutine (default) #2
  425. croutine:prvCheckPendingReadyList (noflash) #3
  426. """
  427. self.add_fragments(mapping)
  428. actual = self.generation.generate_rules(self.entities)
  429. expected = self.generate_default_rules()
  430. flash_text = expected['flash_text']
  431. flash_rodata = expected['flash_rodata']
  432. iram0_text = expected['iram0_text']
  433. dram0_data = expected['dram0_data']
  434. # Exclusions for #1 A
  435. # Only for flash_text and flash_rodata
  436. flash_text[0].exclusions.add(FREERTOS)
  437. flash_rodata[0].exclusions.add(FREERTOS)
  438. # Commands for #1 C
  439. # with exclusions for #2
  440. iram0_text.append(InputSectionDesc(FREERTOS, flash_text[0].sections, [CROUTINE]))
  441. dram0_data.append(InputSectionDesc(FREERTOS, flash_rodata[0].sections, [CROUTINE]))
  442. # Commands for #2 B.1
  443. flash_rodata.append(InputSectionDesc(CROUTINE, flash_rodata[0].sections, []))
  444. # List all relevant sections in case of flash_text B.2
  445. # as exclusion for #3
  446. croutine_sections = self.entities.get_sections('libfreertos.a', 'croutine')
  447. filtered_sections = fnmatch.filter(croutine_sections, '.literal.*')
  448. filtered_sections.extend(fnmatch.filter(croutine_sections, '.text.*'))
  449. filtered_sections = [s for s in filtered_sections if not s.endswith('prvCheckPendingReadyList')]
  450. filtered_sections.append('.text')
  451. flash_text.append(InputSectionDesc(CROUTINE, set(filtered_sections), []))
  452. # Command for #3 D
  453. iram0_text.append(InputSectionDesc(CROUTINE, set(['.text.prvCheckPendingReadyList', '.literal.prvCheckPendingReadyList']), []))
  454. self.compare_rules(expected, actual)
  455. def test_nondefault_but_same_lib_and_obj(self):
  456. # Extension of DefaultMappingTest. Commands should not be generated for #2, since it does similar mapping
  457. # to #1. Output is similar to test_different_mapping_lib.
  458. mapping = u"""
  459. [mapping:test]
  460. archive: libfreertos.a
  461. entries:
  462. * (noflash) #1
  463. croutine (noflash) #2
  464. """
  465. self.test_nondefault_mapping_lib(mapping)
  466. def test_nondefault_but_same_lib_and_sym(self):
  467. # Extension of DefaultMappingTest. Commands should not be generated for #2, since it does similar mapping
  468. # to #1. Output is similar to test_different_mapping_lib.
  469. mapping = u"""
  470. [mapping:test]
  471. archive: libfreertos.a
  472. entries:
  473. * (noflash) #1
  474. croutine:prvCheckPendingReadyList (noflash) #2
  475. """
  476. self.test_nondefault_mapping_lib(mapping)
  477. def test_nondefault_but_same_obj_and_sym(self):
  478. # Commands should not be generated for #2, since it does similar mapping
  479. # to #1. Output is similar to test_different_mapping_obj.
  480. mapping = u"""
  481. [mapping:test]
  482. archive: libfreertos.a
  483. entries:
  484. croutine (noflash) #1
  485. croutine:prvCheckPendingReadyList (noflash) #2
  486. """
  487. self.test_nondefault_mapping_obj(mapping)
  488. def test_multiple_symbols_excluded_from_intermediate_command(self):
  489. # Test mapping multiple symbols from the same object.
  490. # All these symbols must be succesfully excluded from
  491. # the intermediate command.
  492. #
  493. # flash_text
  494. # * (EXCLUDE_FILE(libfreertos.a:croutine) .text ...) A
  495. # libfreertos:croutine(.text ...) B
  496. #
  497. # iram0_text
  498. #
  499. #
  500. mapping = u"""
  501. [mapping:test]
  502. archive: libfreertos.a
  503. entries:
  504. croutine:prvCheckPendingReadyList (noflash) #1
  505. croutine:prvCheckDelayedList (noflash) #2
  506. """
  507. self.add_fragments(mapping)
  508. actual = self.generation.generate_rules(self.entities)
  509. expected = self.generate_default_rules()
  510. flash_text = expected['flash_text']
  511. iram0_text = expected['iram0_text']
  512. # Exclusions for #1 & #2 intermediate command A
  513. flash_text[0].exclusions.add(CROUTINE)
  514. # Intermediate command for #1 & #2 which lists B
  515. # all relevant sections in croutine except prvCheckPendingReadyList
  516. # and prvCheckDelayedList
  517. croutine_sections = self.entities.get_sections('libfreertos.a', 'croutine')
  518. filtered_sections = fnmatch.filter(croutine_sections, '.literal.*')
  519. filtered_sections.extend(fnmatch.filter(croutine_sections, '.text.*'))
  520. filtered_sections = [s for s in filtered_sections if not s.endswith('prvCheckPendingReadyList')]
  521. filtered_sections = [s for s in filtered_sections if not s.endswith('prvCheckDelayedList')]
  522. filtered_sections.append('.text')
  523. flash_text.append(InputSectionDesc(CROUTINE, set(filtered_sections), []))
  524. # Commands for #1 & 2
  525. iram0_text.append(InputSectionDesc(CROUTINE, set(['.text.prvCheckDelayedList', '.literal.prvCheckDelayedList']), []))
  526. iram0_text.append(InputSectionDesc(CROUTINE, set(['.text.prvCheckPendingReadyList', '.literal.prvCheckPendingReadyList']), []))
  527. self.compare_rules(expected, actual)
  528. class AdvancedTest(GenerationTest):
  529. # Test valid but quirky cases, corner cases, failure cases, and
  530. # cases involving interaction between schemes, other mapping
  531. # fragments.
  532. def test_same_entity_no_scheme_common(self):
  533. # Test same entity being mapped by schemes that have nothing in common.
  534. #
  535. # noflash_data: rodata -> dram0_data
  536. # noflash_text: text -> iram0_text
  537. #
  538. # This operation should succeed with the following commands:
  539. #
  540. # flash_text
  541. # *(EXCLUDE_FILE(libfreertos.a:croutine) .text ...) A
  542. #
  543. # flash_rodata
  544. # *(EXCLUDE_FILE(libfreertos.a:croutine) .rodata ...) B
  545. #
  546. # iram0_text
  547. # *(.iram ...)
  548. # *libfreertos.a:croutine(.text .text.* ...) C
  549. #
  550. # dram0_data
  551. # *(.data ..)
  552. # *(.dram ...)
  553. # *libfreertos.a:croutine(.rodata .rodata.*) D
  554. mapping = u"""
  555. [mapping:test]
  556. archive: libfreertos.a
  557. entries:
  558. croutine (noflash_text) #1
  559. croutine (noflash_data) #2
  560. """
  561. self.add_fragments(mapping)
  562. actual = self.generation.generate_rules(self.entities)
  563. expected = self.generate_default_rules()
  564. flash_text = expected['flash_text']
  565. flash_rodata = expected['flash_rodata']
  566. iram0_text = expected['iram0_text']
  567. dram0_data = expected['dram0_data']
  568. # Exclusions for #1 A
  569. flash_text[0].exclusions.add(CROUTINE)
  570. # Exclusions for #2 B
  571. flash_rodata[0].exclusions.add(CROUTINE)
  572. # Command for #1 C
  573. iram0_text.append(InputSectionDesc(CROUTINE, flash_text[0].sections, []))
  574. # Command for #2 D
  575. dram0_data.append(InputSectionDesc(CROUTINE, flash_rodata[0].sections, []))
  576. self.compare_rules(expected, actual)
  577. def test_same_entity_sub_scheme(self):
  578. # Test same entity being mapped by scheme that is a subset of the other.
  579. #
  580. # noflash: text -> iram0_text, rodata -> dram0_data
  581. # noflash_text: text -> iram0_text
  582. #
  583. # `text -> iram0_text` is common between the two schemes.
  584. #
  585. # This operation should succeed with the following commands:
  586. #
  587. # flash_text
  588. # *(EXCLUDE_FILE(libfreertos.a:croutine) .text ...) A
  589. #
  590. # flash_rodata
  591. # *(EXCLUDE_FILE(libfreertos.a:croutine) .rodata ...) B
  592. #
  593. # iram0_text
  594. # *(.iram ...)
  595. # *libfreertos.a:croutine(.text .text.* ...) C
  596. #
  597. # dram0_data
  598. # *(.data ..)
  599. # *(.dram ...)
  600. # *libfreertos.a:croutine(.rodata .rodata.*) D
  601. mapping = u"""
  602. [mapping:test]
  603. archive: libfreertos.a
  604. entries:
  605. croutine (noflash) #1
  606. croutine (noflash_data) #2
  607. """
  608. self.add_fragments(mapping)
  609. actual = self.generation.generate_rules(self.entities)
  610. expected = self.generate_default_rules()
  611. flash_text = expected['flash_text']
  612. flash_rodata = expected['flash_rodata']
  613. iram0_text = expected['iram0_text']
  614. dram0_data = expected['dram0_data']
  615. # Exclusions for #1 A
  616. flash_text[0].exclusions.add(CROUTINE)
  617. # Exclusions for #1 & #2 B
  618. flash_rodata[0].exclusions.add(CROUTINE)
  619. # Command for #1 C
  620. iram0_text.append(InputSectionDesc(CROUTINE, flash_text[0].sections, []))
  621. # Command for #1 & #2 D
  622. dram0_data.append(InputSectionDesc(CROUTINE, flash_rodata[0].sections, []))
  623. self.compare_rules(expected, actual)
  624. def test_same_entity_conflicting_scheme(self, alt=None):
  625. # Test same entity being mapped by scheme conflicting with another.
  626. #
  627. # rtc = text -> rtc_text, rodata -> rtc_data
  628. # noflash = text -> iram0_text, rodata -> dram0_data
  629. #
  630. # This operation should fail.
  631. mapping = u"""
  632. [mapping:test]
  633. archive: libfreertos.a
  634. entries:
  635. croutine (noflash) #1
  636. croutine (rtc) #2
  637. """
  638. self.add_fragments(alt if alt else mapping)
  639. with self.assertRaises(GenerationException):
  640. self.generation.generate_rules(self.entities)
  641. def test_complex_mapping_case(self, alt=None):
  642. # Test a complex case where an object is mapped using
  643. # one scheme, but a specific symbol in that object is mapped
  644. # using another. Another object and symbol is mapped the other way around.
  645. #
  646. # flash_text
  647. # *(EXCLUDE_FILE(libfreertos.a:croutine libfreertos.a:timers) .text ...) A, B
  648. #
  649. # flash_rodata
  650. # *(EXCLUDE_FILE(libfreertos.a:croutine libfreertos.a:timers) .rodata ...) A, B
  651. #
  652. # dram0_data
  653. # *(EXCLUDE_FILES(libfreertos.a:timers) .data ..) B
  654. # *(.dram ...)
  655. # *libfreertos.a:croutine(.rodata .rodata.*) C
  656. # *libfreertos.a:timers(.rodata.prvProcessReceivedCommands ...) E
  657. #
  658. # dram0_bss
  659. # *(EXCLUDE_FILE(libfreertos.a:timers) .bss .bss.* ...) B
  660. # *(EXCLUDE_FILE(libfreertos.a:timers) COMMON) B
  661. #
  662. # iram0_text
  663. # *(.iram ...)
  664. # *libfreertos.a:croutine(.literal .literal.prvCheckDelayedList ...) C
  665. # *libfreertos.a:timers(.literal .literal.prvProcessReceivedCommands ...) E
  666. #
  667. # rtc_text
  668. # *(rtc.text .rtc.literal)
  669. # libfreertos.a:croutine (.text.prvCheckPendingReadyList .literal.prvCheckPendingReadyList) F
  670. # libfreertos.a:timers (.text .text.prvCheckForValidListAndQueue ...) D.2
  671. #
  672. # rtc_data
  673. # *(rtc.data)
  674. # *(rtc.rodata)
  675. # libfreertos.a:timers (.data .data.*) D
  676. # libfreertos.a:timers (.rodata ...) D.2
  677. #
  678. # rtc_bss
  679. # *(rtc.bss .rtc.bss)
  680. # libfreertos.a:timers (.bss .bss.*) D
  681. # libfreertos.a:timers (COMMON) D
  682. mapping = u"""
  683. [mapping:test]
  684. archive: libfreertos.a
  685. entries:
  686. croutine (noflash) #1
  687. timers (rtc) #2
  688. timers:prvProcessReceivedCommands (noflash) #3
  689. croutine:prvCheckPendingReadyList (rtc) #4
  690. """
  691. self.add_fragments(alt if alt else mapping)
  692. actual = self.generation.generate_rules(self.entities)
  693. expected = self.generate_default_rules()
  694. flash_text = expected['flash_text']
  695. flash_rodata = expected['flash_rodata']
  696. dram0_data = expected['dram0_data']
  697. iram0_text = expected['iram0_text']
  698. dram0_bss = expected['dram0_bss']
  699. rtc_text = expected['rtc_text']
  700. rtc_data = expected['rtc_data']
  701. rtc_bss = expected['rtc_bss']
  702. # Exclusions for #1 A
  703. flash_text[0].exclusions.add(CROUTINE)
  704. flash_rodata[0].exclusions.add(CROUTINE)
  705. # Exclusions for #2 B
  706. flash_text[0].exclusions.add(TIMERS)
  707. flash_rodata[0].exclusions.add(TIMERS)
  708. dram0_data[0].exclusions.add(TIMERS)
  709. dram0_bss[0].exclusions.add(TIMERS)
  710. dram0_bss[1].exclusions.add(TIMERS)
  711. # Commands for #1 C
  712. # List all relevant sections excluding #4 for text -> iram0_text
  713. croutine_sections = self.entities.get_sections('libfreertos.a', 'croutine')
  714. filtered_sections = fnmatch.filter(croutine_sections, '.literal.*')
  715. filtered_sections.extend(fnmatch.filter(croutine_sections, '.text.*'))
  716. filtered_sections = [s for s in filtered_sections if not s.endswith('prvCheckPendingReadyList')]
  717. filtered_sections.append('.text')
  718. iram0_text.append(InputSectionDesc(CROUTINE, set(filtered_sections), []))
  719. dram0_data.append(InputSectionDesc(CROUTINE, flash_rodata[0].sections, []))
  720. # Commands for #4 F
  721. # Processed first due to alphabetical ordering
  722. rtc_text.append(InputSectionDesc(CROUTINE, set(['.text.prvCheckPendingReadyList', '.literal.prvCheckPendingReadyList']), []))
  723. # Commands for #2 D
  724. # List all relevant sections excluding #3 for text -> rtc_text and D.2
  725. # rodata -> rtc_data
  726. timers_sections = self.entities.get_sections('libfreertos.a', 'timers')
  727. filtered_sections = fnmatch.filter(timers_sections, '.literal.*')
  728. filtered_sections.extend(fnmatch.filter(timers_sections, '.text.*'))
  729. filtered_sections = [s for s in filtered_sections if not s.endswith('prvProcessReceivedCommands')]
  730. filtered_sections.append('.text')
  731. rtc_text.append(InputSectionDesc(TIMERS, set(filtered_sections), []))
  732. rtc_data.append(InputSectionDesc(TIMERS, dram0_data[0].sections, []))
  733. filtered_sections = fnmatch.filter(timers_sections, '.rodata.*')
  734. filtered_sections = [s for s in filtered_sections if not s.endswith('prvProcessReceivedCommands')]
  735. rtc_data.append(InputSectionDesc(TIMERS, set(filtered_sections), []))
  736. rtc_bss.append(InputSectionDesc(TIMERS, dram0_bss[0].sections, []))
  737. rtc_bss.append(InputSectionDesc(TIMERS, dram0_bss[1].sections, []))
  738. # Commands for #3 E
  739. iram0_text.append(InputSectionDesc(TIMERS, set(['.text.prvProcessReceivedCommands', '.literal.prvProcessReceivedCommands']), []))
  740. dram0_data.append(InputSectionDesc(TIMERS, set(['.rodata.prvProcessReceivedCommands']), []))
  741. self.compare_rules(expected, actual)
  742. def test_multiple_mapping_fragments(self):
  743. # Test mapping multiple fragments succeeds, particularly
  744. # generating exclusions from the default command of archive
  745. # and object specificity.
  746. #
  747. # flash_text
  748. # * (EXCLUDE_FILE(libfreertos.a libfreertos.a:croutine) .text ...)
  749. #
  750. # flash_rodata
  751. # * (EXCLUDE_FILE(libfreertos.a libfreertos.a:croutine) .text ...)
  752. #
  753. # iram0_text
  754. mapping = u"""
  755. [mapping:test_1]
  756. archive: libfreertos.a
  757. entries:
  758. croutine (noflash) #1
  759. [mapping:test_2]
  760. archive: libfreertos2.a
  761. entries:
  762. * (noflash) #2
  763. """
  764. self.add_fragments(mapping)
  765. actual = self.generation.generate_rules(self.entities)
  766. expected = self.generate_default_rules()
  767. flash_text = expected['flash_text']
  768. flash_rodata = expected['flash_rodata']
  769. iram0_text = expected['iram0_text']
  770. dram0_data = expected['dram0_data']
  771. # Exclusions for #1 A
  772. flash_text[0].exclusions.add(CROUTINE)
  773. flash_rodata[0].exclusions.add(CROUTINE)
  774. # Exclusions for #1 & #2 B
  775. flash_text[0].exclusions.add(FREERTOS2)
  776. flash_rodata[0].exclusions.add(FREERTOS2)
  777. # Command for #1 C
  778. iram0_text.append(InputSectionDesc(CROUTINE, flash_text[0].sections, []))
  779. dram0_data.append(InputSectionDesc(CROUTINE, flash_rodata[0].sections, []))
  780. # Command for #1 & #2 D
  781. iram0_text.append(InputSectionDesc(FREERTOS2, flash_text[0].sections, []))
  782. dram0_data.append(InputSectionDesc(FREERTOS2, flash_rodata[0].sections, []))
  783. self.compare_rules(expected, actual)
  784. def test_mapping_same_lib_in_multiple_fragments_no_conflict(self):
  785. # Test mapping fragments operating on the same archive.
  786. # In these cases, the entries are taken together.
  787. #
  788. # Uses the same entries as C_05 but spreads them across
  789. # two fragments. The output should still be the same.
  790. mapping = u"""
  791. [mapping:test_1]
  792. archive: libfreertos.a
  793. entries:
  794. croutine (noflash) #1
  795. timers:prvProcessReceivedCommands (noflash) #3
  796. [mapping:test_2]
  797. archive: libfreertos.a
  798. entries:
  799. timers (rtc) #2
  800. croutine:prvCheckPendingReadyList (rtc) #4
  801. """
  802. self.test_complex_mapping_case(mapping)
  803. def test_mapping_same_lib_in_multiple_fragments_conflict(self):
  804. # Test mapping fragments operating on the same archive
  805. # with conflicting mappings.
  806. mapping = u"""
  807. [mapping:test_1]
  808. archive: libfreertos.a
  809. entries:
  810. croutine (noflash) #1
  811. [mapping:test_2]
  812. archive: libfreertos.a
  813. entries:
  814. croutine (rtc) #2
  815. """
  816. self.test_same_entity_conflicting_scheme(mapping)
  817. def test_command_order(self):
  818. # Test command order sorting: the commands should be sorted by specificity, then
  819. # alphabetically. This contributes to deterministic output given
  820. # the same input mapping entries.
  821. #
  822. # This ordering is also tested in other tests as a side-effect.
  823. #
  824. # flash_text
  825. # * (EXCLUDE_FILE(libfreertos.a:croutine libfreertos.a:croutine2)) A
  826. # libfreertos.a:croutine(.text ....) B
  827. #
  828. # iram0_text
  829. #
  830. # * (.iram .iram.*)
  831. # libfreertos:croutine(.text .literal ...) C
  832. # libfreertos:croutine(.text.prvCheckDelayedList .literal.prvCheckDelayedList) F
  833. # libfreertos:croutine(.text.prvCheckPendingReadyList .literal.prvCheckPendingReadyList) G
  834. # libfreertos2:croutine(.text .literal ...) D
  835. # libfreertos2:croutine2(.text .literal ...) E
  836. mapping = u"""
  837. [mapping:freertos2]
  838. archive: libfreertos2.a
  839. entries:
  840. croutine2 (noflash_text) #1
  841. croutine (noflash_text) #2
  842. [mapping:freertos]
  843. archive: libfreertos.a
  844. entries:
  845. croutine:prvCheckPendingReadyList (noflash_text) #3
  846. croutine:prvCheckDelayedList (noflash_text) #4
  847. """
  848. self.add_fragments(mapping)
  849. actual = self.generation.generate_rules(self.entities)
  850. expected = self.generate_default_rules()
  851. flash_text = expected['flash_text']
  852. iram0_text = expected['iram0_text']
  853. # Exclusions for #1 A
  854. flash_text[0].exclusions.add(CROUTINE)
  855. flash_text[0].exclusions.add(Entity(FREERTOS2.archive, 'croutine2'))
  856. flash_text[0].exclusions.add(Entity(FREERTOS2.archive, 'croutine'))
  857. # Intermediate command for #3 and #4 B
  858. croutine_sections = self.entities.get_sections('libfreertos.a', 'croutine')
  859. filtered_sections = fnmatch.filter(croutine_sections, '.literal.*')
  860. filtered_sections.extend(fnmatch.filter(croutine_sections, '.text.*'))
  861. filtered_sections = [s for s in filtered_sections if not s.endswith('prvCheckPendingReadyList')]
  862. filtered_sections = [s for s in filtered_sections if not s.endswith('prvCheckDelayedList')]
  863. filtered_sections.append('.text')
  864. flash_text.append(InputSectionDesc(CROUTINE, set(filtered_sections), []))
  865. # Command for
  866. iram0_text.append(InputSectionDesc(CROUTINE, set(['.text.prvCheckDelayedList', '.literal.prvCheckDelayedList']), []))
  867. iram0_text.append(InputSectionDesc(CROUTINE, set(['.text.prvCheckPendingReadyList', '.literal.prvCheckPendingReadyList']), []))
  868. iram0_text.append(InputSectionDesc(Entity(FREERTOS2.archive, 'croutine'), flash_text[0].sections, []))
  869. iram0_text.append(InputSectionDesc(Entity(FREERTOS2.archive, 'croutine2'), flash_text[0].sections, []))
  870. self.compare_rules(expected, actual)
  871. def test_ambigious_obj(self):
  872. # Command generation for ambiguous entry should fail.
  873. mapping = u"""
  874. [mapping:test]
  875. archive: libfreertos.a
  876. entries:
  877. port:xPortGetTickRateHz (noflash) #1
  878. """
  879. self.add_fragments(mapping)
  880. with self.assertRaises(GenerationException):
  881. self.generation.generate_rules(self.entities)
  882. def test_disambiguated_obj(self):
  883. # Test command generation for disambiguated entry. Should produce similar
  884. # results to test_nondefault_mapping_symbol.
  885. mapping = u"""
  886. [mapping:test]
  887. archive: libfreertos.a
  888. entries:
  889. port.c:xPortGetTickRateHz (noflash) #1
  890. """
  891. port = Entity('libfreertos.a', 'port.c')
  892. self.add_fragments(mapping)
  893. actual = self.generation.generate_rules(self.entities)
  894. expected = self.generate_default_rules()
  895. flash_text = expected['flash_text']
  896. iram0_text = expected['iram0_text']
  897. # Generate exclusion in flash_text A
  898. flash_text[0].exclusions.add(port)
  899. # Generate intermediate command B
  900. # List all relevant sections except the symbol
  901. # being mapped
  902. port_sections = self.entities.get_sections('libfreertos.a', 'port.c')
  903. filtered_sections = fnmatch.filter(port_sections, '.literal.*')
  904. filtered_sections.extend(fnmatch.filter(port_sections, '.text.*'))
  905. filtered_sections = [s for s in filtered_sections if not s.endswith('xPortGetTickRateHz')]
  906. filtered_sections.append('.text')
  907. flash_text.append(InputSectionDesc(port, set(filtered_sections), []))
  908. # Input section commands in iram_text for #1 C
  909. iram0_text.append(InputSectionDesc(port, set(['.text.xPortGetTickRateHz', '.literal.xPortGetTickRateHz']), []))
  910. self.compare_rules(expected, actual)
  911. class ConfigTest(GenerationTest):
  912. # Test command generation with conditions
  913. def _test_conditional_on_scheme(self, perf, alt=None):
  914. # Test that proper commands are generated if using
  915. # schemes with conditional entries.
  916. scheme = u"""
  917. [sections:cond_text_data]
  918. entries:
  919. if PERFORMANCE_LEVEL >= 1:
  920. .text+
  921. .literal+
  922. else:
  923. .rodata+
  924. [scheme:cond_noflash]
  925. entries:
  926. if PERFORMANCE_LEVEL >= 1:
  927. cond_text_data -> iram0_text
  928. else:
  929. cond_text_data -> dram0_data
  930. """
  931. mapping = u"""
  932. [mapping:test]
  933. archive: lib.a
  934. entries:
  935. * (cond_noflash)
  936. """
  937. self.sdkconfig.config.syms['PERFORMANCE_LEVEL'].set_value(str(perf))
  938. self.add_fragments(scheme)
  939. self.add_fragments(alt if alt else mapping)
  940. actual = self.generation.generate_rules(self.entities)
  941. expected = self.generate_default_rules()
  942. if perf >= 1:
  943. flash_text = expected['flash_text']
  944. iram0_text = expected['iram0_text']
  945. flash_text[0].exclusions.add(Entity('lib.a'))
  946. iram0_text.append(InputSectionDesc(Entity('lib.a'), flash_text[0].sections, []))
  947. else:
  948. flash_rodata = expected['flash_rodata']
  949. dram0_data = expected['dram0_data']
  950. flash_rodata[0].exclusions.add(Entity('lib.a'))
  951. dram0_data.append(InputSectionDesc(Entity('lib.a'), flash_rodata[0].sections, []))
  952. self.compare_rules(expected, actual)
  953. def test_conditional_on_scheme_00(self):
  954. self._test_conditional_on_scheme(0)
  955. def test_conditional_on_scheme_01(self):
  956. self._test_conditional_on_scheme(1)
  957. def test_conditional_mapping(self, alt=None):
  958. # Test that proper commands are generated
  959. # in conditional mapping entries.
  960. mapping = u"""
  961. [mapping:test]
  962. archive: lib.a
  963. entries:
  964. if PERFORMANCE_LEVEL = 1:
  965. obj1 (noflash)
  966. elif PERFORMANCE_LEVEL = 2:
  967. obj1 (noflash)
  968. obj2 (noflash)
  969. elif PERFORMANCE_LEVEL = 3:
  970. obj1 (noflash)
  971. obj2 (noflash)
  972. obj3 (noflash)
  973. """
  974. for perf_level in range(0, 4):
  975. self.sdkconfig.config.syms['PERFORMANCE_LEVEL'].set_value(str(perf_level))
  976. self.generation.mappings = {}
  977. self.add_fragments(alt if alt else mapping)
  978. actual = self.generation.generate_rules(self.entities)
  979. expected = self.generate_default_rules()
  980. if perf_level < 4 and perf_level > 0:
  981. for append_no in range(1, perf_level + 1):
  982. flash_text = expected['flash_text']
  983. flash_rodata = expected['flash_rodata']
  984. iram0_text = expected['iram0_text']
  985. dram0_data = expected['dram0_data']
  986. obj_str = 'obj' + str(append_no)
  987. flash_text[0].exclusions.add(Entity('lib.a', obj_str))
  988. flash_rodata[0].exclusions.add(Entity('lib.a', obj_str))
  989. iram0_text.append(InputSectionDesc(Entity('lib.a', obj_str), flash_text[0].sections, []))
  990. dram0_data.append(InputSectionDesc(Entity('lib.a', obj_str), flash_rodata[0].sections, []))
  991. self.compare_rules(expected, actual)
  992. def test_conditional_on_scheme_legacy_mapping_00(self):
  993. # Test use of conditional scheme on legacy mapping fragment grammar.
  994. mapping = u"""
  995. [mapping]
  996. archive: lib.a
  997. entries:
  998. * (cond_noflash)
  999. """
  1000. self._test_conditional_on_scheme(0, mapping)
  1001. def test_conditional_on_scheme_legacy_mapping_01(self):
  1002. # Test use of conditional scheme on legacy mapping fragment grammar.
  1003. mapping = u"""
  1004. [mapping]
  1005. archive: lib.a
  1006. entries:
  1007. * (cond_noflash)
  1008. """
  1009. self._test_conditional_on_scheme(0, mapping)
  1010. def test_conditional_entries_legacy_mapping_fragment(self):
  1011. # Test conditional entries on legacy mapping fragment grammar.
  1012. mapping = u"""
  1013. [mapping]
  1014. archive: lib.a
  1015. entries:
  1016. : PERFORMANCE_LEVEL = 0
  1017. : PERFORMANCE_LEVEL = 1
  1018. obj1 (noflash)
  1019. : PERFORMANCE_LEVEL = 2
  1020. obj1 (noflash)
  1021. obj2 (noflash)
  1022. : PERFORMANCE_LEVEL = 3
  1023. obj1 (noflash)
  1024. obj2 (noflash)
  1025. obj3 (noflash)
  1026. """
  1027. self.test_conditional_mapping(mapping)
  1028. def test_multiple_fragment_same_lib_conditional_legacy(self):
  1029. # Test conditional entries on legacy mapping fragment grammar
  1030. # across multiple fragments.
  1031. mapping = u"""
  1032. [mapping]
  1033. archive: lib.a
  1034. entries:
  1035. : PERFORMANCE_LEVEL = 0
  1036. : PERFORMANCE_LEVEL = 1
  1037. obj1 (noflash)
  1038. : PERFORMANCE_LEVEL = 2
  1039. obj1 (noflash)
  1040. : PERFORMANCE_LEVEL = 3
  1041. obj1 (noflash)
  1042. [mapping]
  1043. archive: lib.a
  1044. entries:
  1045. : PERFORMANCE_LEVEL = 1
  1046. obj1 (noflash) # ignore duplicate definition
  1047. : PERFORMANCE_LEVEL = 2
  1048. obj2 (noflash)
  1049. : PERFORMANCE_LEVEL = 3
  1050. obj2 (noflash)
  1051. obj3 (noflash)
  1052. """
  1053. self.test_conditional_mapping(mapping)
  1054. def test_multiple_fragment_same_lib_conditional(self):
  1055. # Test conditional entries on new mapping fragment grammar.
  1056. # across multiple fragments.
  1057. mapping = u"""
  1058. [mapping:base]
  1059. archive: lib.a
  1060. entries:
  1061. if PERFORMANCE_LEVEL = 1:
  1062. obj1 (noflash)
  1063. elif PERFORMANCE_LEVEL = 2:
  1064. obj1 (noflash)
  1065. elif PERFORMANCE_LEVEL = 3:
  1066. obj1 (noflash)
  1067. [mapping:extra]
  1068. archive: lib.a
  1069. entries:
  1070. if PERFORMANCE_LEVEL = 1:
  1071. obj1 (noflash) # ignore duplicate definition
  1072. elif PERFORMANCE_LEVEL = 2:
  1073. obj2 (noflash)
  1074. elif PERFORMANCE_LEVEL = 3:
  1075. obj2 (noflash)
  1076. obj3 (noflash)
  1077. """
  1078. self.test_conditional_mapping(mapping)
  1079. if __name__ == '__main__':
  1080. unittest.main()