#!/usr/bin/env python
|
|
|
|
import os
|
|
import argparse
|
|
import logging
|
|
from collections import defaultdict
|
|
from math import trunc
|
|
|
|
FORMAT = "%(asctime)-15s %(message)s"
|
|
log = logging.getLogger("ldscript-get")
|
|
logging.basicConfig(format=FORMAT)
|
|
|
|
# mapping from esp8266/tools/boards.txt.py:
|
|
# sketch | reserved | empty | fs | eeprom | rf-cal | sdk-wifi-settings
|
|
# ...... | 4112B | ..... | ...... | ...... | 16 KB
|
|
|
|
IROM0_SPI_FLASH_START = 0x40200000
|
|
IROM0_RESERVED_SKETCH_SIZE = 0x1010
|
|
IROM0_RESERVED_SDK_SIZE = 0x4000
|
|
|
|
SIZE = {512: 0x80000, 1024: 0x100000, 2048: 0x200000, 3072: 0x300000, 4096: 0x400000}
|
|
|
|
# supported sizes
|
|
# flash (bytes), fs (bytes), eeprom (sectors)
|
|
VARIANTS = [
|
|
[SIZE[512], 0, 1],
|
|
[SIZE[1024], 0, 1],
|
|
[SIZE[1024], 0, 2],
|
|
[SIZE[2048], SIZE[1024], 4],
|
|
[SIZE[4096], SIZE[1024], 4],
|
|
[SIZE[4096], SIZE[3072], 4],
|
|
]
|
|
|
|
|
|
def size_suffix(size):
|
|
if size >= SIZE[1024] or not size:
|
|
size = trunc(size / SIZE[1024])
|
|
suffix = "m"
|
|
else:
|
|
size = trunc(size / 1024)
|
|
suffix = "k"
|
|
|
|
return size, suffix
|
|
|
|
|
|
def variant_name(variant):
|
|
tmpl = "{flash_size}{flash_suffix}{fs_size}{fs_suffix}{sectors}s"
|
|
|
|
flash_size, fs_size, sectors = variant
|
|
|
|
flash_size, flash_suffix = size_suffix(flash_size)
|
|
fs_size, fs_suffix = size_suffix(fs_size)
|
|
|
|
return tmpl.format(
|
|
flash_size=flash_size,
|
|
flash_suffix=flash_suffix,
|
|
fs_size=fs_size,
|
|
fs_suffix=fs_suffix,
|
|
sectors=sectors,
|
|
)
|
|
|
|
|
|
TEMPLATE = """\
|
|
/*
|
|
sketch: {size_kb}KB
|
|
fs: {fs_size_kb}KB
|
|
eeprom: {eeprom_size_kb}KB
|
|
*/
|
|
|
|
MEMORY
|
|
{{
|
|
dport0_0_seg : org = 0x3FF00000, len = 0x10
|
|
dram0_0_seg : org = 0x3FFE8000, len = 0x14000
|
|
iram1_0_seg : org = 0x40100000, len = 0x8000
|
|
irom0_0_seg : org = 0x40201010, len = {size:#x}
|
|
}}
|
|
|
|
/*
|
|
Provide both _SPIFFS_ and _FS_ to be compatible with 2.3.0...2.6.0+ and
|
|
any library that is using old _SPIFFS_...
|
|
*/
|
|
|
|
PROVIDE ( _SPIFFS_start = {fs_start:#x} );
|
|
PROVIDE ( _SPIFFS_end = {fs_end:#x} );
|
|
PROVIDE ( _SPIFFS_page = {fs_page:#x} );
|
|
PROVIDE ( _SPIFFS_block = {fs_block:#x} );
|
|
|
|
PROVIDE ( _FS_start = _SPIFFS_start );
|
|
PROVIDE ( _FS_end = _SPIFFS_end );
|
|
PROVIDE ( _FS_page = _SPIFFS_page );
|
|
PROVIDE ( _FS_block = _SPIFFS_block );
|
|
|
|
INCLUDE \"{include}\"
|
|
"""
|
|
|
|
|
|
def flash_map(flashsize, fs, sectors):
|
|
reserved = IROM0_RESERVED_SKETCH_SIZE
|
|
sdk_reserved = IROM0_RESERVED_SDK_SIZE
|
|
eeprom_size = 0x1000 * sectors
|
|
|
|
fs_end = IROM0_SPI_FLASH_START + (flashsize - sdk_reserved - eeprom_size)
|
|
fs_page = 0x100
|
|
if flashsize <= SIZE[1024]:
|
|
max_upload_size = (flashsize - (fs + eeprom_size + sdk_reserved)) - reserved
|
|
fs_start = IROM0_SPI_FLASH_START + fs_end - fs
|
|
fs_block = 4096
|
|
else:
|
|
max_upload_size = 1024 * 1024 - reserved
|
|
fs_start = IROM0_SPI_FLASH_START + (flashsize - fs)
|
|
if fs < SIZE[512]:
|
|
fs_block = 4096
|
|
else:
|
|
fs_block = 8192
|
|
|
|
if not fs:
|
|
fs_block = 0
|
|
fs_page = 0
|
|
fs_start = fs_end
|
|
|
|
# Adjust FS_end to be a multiple of the block size
|
|
# ref: https://github.com/esp8266/Arduino/pull/5989
|
|
if fs:
|
|
fs_end = fs_block * ((fs_end - fs_start) // fs_block) + fs_start
|
|
|
|
result = {
|
|
"size": max_upload_size,
|
|
"size_kb": int(max_upload_size / 1024),
|
|
"eeprom_size_kb": int(eeprom_size / 1024),
|
|
"fs_size_kb": int((fs_end - fs_start) / 1024),
|
|
"fs_start": fs_start,
|
|
"fs_end": fs_end,
|
|
"fs_page": fs_page,
|
|
"fs_block": fs_block,
|
|
}
|
|
|
|
return result
|
|
|
|
|
|
def render(variant, legacy):
|
|
name = variant_name(variant)
|
|
name = "eagle.flash.{}.ld".format(name)
|
|
|
|
ld_include = "local.eagle.app.v6.common.ld"
|
|
ld_dir = "ld/latest"
|
|
if legacy:
|
|
ld_include = "eagle.app.v6.common.ld"
|
|
ld_dir = "ld/pre_2.5.0"
|
|
|
|
path = os.path.join(ld_dir, name)
|
|
|
|
log.info("render %s (INCLUDE %s)", name, ld_include)
|
|
|
|
with open(path, "w") as f:
|
|
f.write(TEMPLATE.format(include=ld_include, **flash_map(*variant)))
|
|
|
|
|
|
def render_all():
|
|
for variant in VARIANTS:
|
|
render(variant, True)
|
|
render(variant, False)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
variants = {variant_name(x): x for x in VARIANTS}
|
|
choices = ["all"]
|
|
choices.extend(variants.keys())
|
|
|
|
parser = argparse.ArgumentParser()
|
|
parser.add_argument("--legacy", action="store_true", default=False)
|
|
parser.add_argument("--verbose", action="store_true", default=False)
|
|
parser.add_argument("variant", choices=choices)
|
|
|
|
args = parser.parse_args()
|
|
if args.verbose:
|
|
log.setLevel(logging.DEBUG)
|
|
|
|
if args.variant == "all":
|
|
render_all()
|
|
else:
|
|
render(variants[args.variant], args.legacy)
|