Fork of the espurna firmware for `mhsw` switches
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

181 lines
4.7 KiB

  1. #!/usr/bin/env python
  2. import os
  3. import argparse
  4. import logging
  5. from collections import defaultdict
  6. from math import trunc
  7. FORMAT = "%(asctime)-15s %(message)s"
  8. log = logging.getLogger("ldscript-get")
  9. logging.basicConfig(format=FORMAT)
  10. # mapping from esp8266/tools/boards.txt.py:
  11. # sketch | reserved | empty | fs | eeprom | rf-cal | sdk-wifi-settings
  12. # ...... | 4112B | ..... | ...... | ...... | 16 KB
  13. IROM0_SPI_FLASH_START = 0x40200000
  14. IROM0_RESERVED_SKETCH_SIZE = 0x1010
  15. IROM0_RESERVED_SDK_SIZE = 0x4000
  16. SIZE = {512: 0x80000, 1024: 0x100000, 2048: 0x200000, 3072: 0x300000, 4096: 0x400000}
  17. # supported sizes
  18. # flash (bytes), fs (bytes), eeprom (sectors)
  19. VARIANTS = [
  20. [SIZE[512], 0, 1],
  21. [SIZE[1024], 0, 1],
  22. [SIZE[1024], 0, 2],
  23. [SIZE[2048], SIZE[1024], 4],
  24. [SIZE[4096], SIZE[1024], 4],
  25. [SIZE[4096], SIZE[3072], 4],
  26. ]
  27. def size_suffix(size):
  28. if size >= SIZE[1024] or not size:
  29. size = trunc(size / SIZE[1024])
  30. suffix = "m"
  31. else:
  32. size = trunc(size / 1024)
  33. suffix = "k"
  34. return size, suffix
  35. def variant_name(variant):
  36. tmpl = "{flash_size}{flash_suffix}{fs_size}{fs_suffix}{sectors}s"
  37. flash_size, fs_size, sectors = variant
  38. flash_size, flash_suffix = size_suffix(flash_size)
  39. fs_size, fs_suffix = size_suffix(fs_size)
  40. return tmpl.format(
  41. flash_size=flash_size,
  42. flash_suffix=flash_suffix,
  43. fs_size=fs_size,
  44. fs_suffix=fs_suffix,
  45. sectors=sectors,
  46. )
  47. TEMPLATE = """\
  48. /*
  49. sketch: {size_kb}KB
  50. fs: {fs_size_kb}KB
  51. eeprom: {eeprom_size_kb}KB
  52. */
  53. MEMORY
  54. {{
  55. dport0_0_seg : org = 0x3FF00000, len = 0x10
  56. dram0_0_seg : org = 0x3FFE8000, len = 0x14000
  57. iram1_0_seg : org = 0x40100000, len = 0x8000
  58. irom0_0_seg : org = 0x40201010, len = {size:#x}
  59. }}
  60. /*
  61. Provide both _SPIFFS_ and _FS_ to be compatible with 2.3.0...2.6.0+ and
  62. any library that is using old _SPIFFS_...
  63. */
  64. PROVIDE ( _SPIFFS_start = {fs_start:#x} );
  65. PROVIDE ( _SPIFFS_end = {fs_end:#x} );
  66. PROVIDE ( _SPIFFS_page = {fs_page:#x} );
  67. PROVIDE ( _SPIFFS_block = {fs_block:#x} );
  68. PROVIDE ( _FS_start = _SPIFFS_start );
  69. PROVIDE ( _FS_end = _SPIFFS_end );
  70. PROVIDE ( _FS_page = _SPIFFS_page );
  71. PROVIDE ( _FS_block = _SPIFFS_block );
  72. INCLUDE \"{include}\"
  73. """
  74. def flash_map(flashsize, fs, sectors):
  75. reserved = IROM0_RESERVED_SKETCH_SIZE
  76. sdk_reserved = IROM0_RESERVED_SDK_SIZE
  77. eeprom_size = 0x1000 * sectors
  78. fs_end = IROM0_SPI_FLASH_START + (flashsize - sdk_reserved - eeprom_size)
  79. fs_page = 0x100
  80. if flashsize <= SIZE[1024]:
  81. max_upload_size = (flashsize - (fs + eeprom_size + sdk_reserved)) - reserved
  82. fs_start = IROM0_SPI_FLASH_START + fs_end - fs
  83. fs_block = 4096
  84. else:
  85. max_upload_size = 1024 * 1024 - reserved
  86. fs_start = IROM0_SPI_FLASH_START + (flashsize - fs)
  87. if fs < SIZE[512]:
  88. fs_block = 4096
  89. else:
  90. fs_block = 8192
  91. if not fs:
  92. fs_block = 0
  93. fs_page = 0
  94. fs_start = fs_end
  95. # Adjust FS_end to be a multiple of the block size
  96. # ref: https://github.com/esp8266/Arduino/pull/5989
  97. if fs:
  98. fs_end = fs_block * ((fs_end - fs_start) // fs_block) + fs_start
  99. result = {
  100. "size": max_upload_size,
  101. "size_kb": int(max_upload_size / 1024),
  102. "eeprom_size_kb": int(eeprom_size / 1024),
  103. "fs_size_kb": int((fs_end - fs_start) / 1024),
  104. "fs_start": fs_start,
  105. "fs_end": fs_end,
  106. "fs_page": fs_page,
  107. "fs_block": fs_block,
  108. }
  109. return result
  110. def render(variant, legacy):
  111. name = variant_name(variant)
  112. name = "eagle.flash.{}.ld".format(name)
  113. ld_include = "local.eagle.app.v6.common.ld"
  114. ld_dir = "ld/latest"
  115. if legacy:
  116. ld_include = "eagle.app.v6.common.ld"
  117. ld_dir = "ld/pre_2.5.0"
  118. path = os.path.join(ld_dir, name)
  119. log.info("render %s (INCLUDE %s)", name, ld_include)
  120. with open(path, "w") as f:
  121. f.write(TEMPLATE.format(include=ld_include, **flash_map(*variant)))
  122. def render_all():
  123. for variant in VARIANTS:
  124. render(variant, True)
  125. render(variant, False)
  126. if __name__ == "__main__":
  127. variants = {variant_name(x): x for x in VARIANTS}
  128. choices = ["all"]
  129. choices.extend(variants.keys())
  130. parser = argparse.ArgumentParser()
  131. parser.add_argument("--legacy", action="store_true", default=False)
  132. parser.add_argument("--verbose", action="store_true", default=False)
  133. parser.add_argument("variant", choices=choices)
  134. args = parser.parse_args()
  135. if args.verbose:
  136. log.setLevel(logging.DEBUG)
  137. if args.variant == "all":
  138. render_all()
  139. else:
  140. render(variants[args.variant], args.legacy)