#
# This file is part of LUNA.
#
# Copyright (c) 2023-2025 Great Scott Gadgets <info@greatscottgadgets.com>
# SPDX-License-Identifier: BSD-3-Clause
"""Generate Rust support files for SoC designs."""
import datetime
import logging
from amaranth_soc.memory import MemoryMap
[docs]
class LinkerScript:
def __init__(self, memory_map: MemoryMap, reset_addr: int = 0x00000000):
self.memory_map = memory_map
self.reset_addr = reset_addr
[docs]
def generate(self, file=None):
""" Generate a memory.x file for the given SoC design"""
def emit(content):
""" Utility function that emits a string to the targeted file. """
print(content, file=file)
# TODO this should be determined by introspection
memories = ["ram", "rom", "blockram", "spiflash",
"bootrom", "scratchpad", "mainram"]
# warning header
emit("/*")
emit(" * Automatically generated by LUNA; edits will be discarded on rebuild.")
emit(" * (Most header files phrase this 'Do not edit.'; be warned accordingly.)")
emit(" *")
emit(f" * Generated: {datetime.datetime.now()}.")
emit(" */")
emit("")
# memory regions
regions = set()
emit("MEMORY {")
window: MemoryMap
name: MemoryMap.Name
for window, name, (start, end, ratio) in self.memory_map.windows():
name = name[0]
if name not in memories:
logging.debug("Skipping non-memory resource: {}".format(name))
continue
if self.reset_addr >= start and self.reset_addr < end:
start = self.reset_addr
emit(f" {name} : ORIGIN = 0x{start:08x}, LENGTH = 0x{end-start:08x}")
regions.add(name)
emit("}")
emit("")
# region aliases
ram = "blockram" if "blockram" in regions else "scratchpad"
rom = "spiflash" if "spiflash" in regions else ram
aliases = {
"REGION_TEXT": rom,
"REGION_RODATA": rom,
"REGION_DATA": ram,
"REGION_BSS": ram,
"REGION_HEAP": ram,
"REGION_STACK": ram,
}
for alias, region in aliases.items():
emit(f"REGION_ALIAS(\"{alias}\", {region});")