test_generation.py 52 KB

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