Files
Diddy-Kong-Racing/tools/python/generate_ld.py
T

264 lines
9.9 KiB
Python
Raw Normal View History

2020-05-27 19:14:56 -05:00
import re
import os
import json
2020-05-27 19:14:56 -05:00
from file_util import FileUtil
VERSION = 'us_1.0'
2020-05-27 19:14:56 -05:00
LD_NAME = 'dkr.ld'
ASM_DIR = './asm'
2020-06-27 20:31:57 -05:00
SRC_DIR = './src'
2020-07-31 15:45:49 -05:00
LIB_ASM_DIR = './lib/asm'
LIB_SRC_DIR = './lib/src'
ASSETS_FILENAME = './asm/assets/assets.s'
ASSETS_LUT_FILENAME = './asm/assets/assets_lut.s'
ASSETS_DIR = './assets/' + VERSION
ASSETS_START = 0x0D8200
UCODE_DIR = './ucode/' + VERSION
UCODE_TEXT_FILENAME = './asm/assets/ucode_text.s'
UCODE_DATA_FILENAME = './asm/assets/ucode_data.s'
BUILD_DIR = 'build/' + VERSION
2020-05-27 19:14:56 -05:00
class LD:
def __init__(self, file):
print('Generating linker file...')
self.generate_assets_file()
self.generate_ucode_files()
2020-06-27 20:31:57 -05:00
self.files = self.get_code_files()
2020-05-27 19:14:56 -05:00
self.indentLevel = 0
self.file = file
self.gen_comment('linker script generated by generate_ld.py')
self.gen_newline()
self.gen_line('OUTPUT_ARCH (mips)')
self.gen_newline()
self.gen_sections()
print('New linker file created!')
def gen_sections(self):
self.gen_line('SECTIONS')
self.gen_open_block()
self.gen_line('romPos = 0x0;')
self.gen_boot_section()
self.gen_main_section()
self.gen_ucode_text_section()
self.gen_data_section()
self.gen_ucode_data_section()
2020-05-27 19:14:56 -05:00
self.gen_assets_section()
self.gen_discard()
self.gen_close_block()
def gen_boot_section(self):
self.gen_line('.boot 0 : AT(romPos)')
self.gen_open_block()
self.gen_line(BUILD_DIR + '/asm/boot/rom_header.o(.text);')
self.gen_line(BUILD_DIR + '/asm/boot/rom_boot.o(.text);')
2020-05-27 19:14:56 -05:00
self.gen_close_block()
self.gen_line('romPos += SIZEOF(.boot);')
self.gen_newline()
def gen_main_section(self):
self.gen_line('.main 0x80000400 : AT(romPos) SUBALIGN(16)')
self.gen_open_block()
2020-07-29 09:30:04 -05:00
for file in self.files:
self.gen_line(file[0] + '(.text);')
2020-05-27 19:14:56 -05:00
self.gen_close_block()
self.gen_line('romPos += SIZEOF(.main);')
self.gen_newline()
def gen_ucode_text_section(self):
self.gen_line('.ucodeText 0 : AT(romPos)')
self.gen_open_block()
self.gen_line(BUILD_DIR + '/asm/assets/ucode_text.o(.text);')
self.gen_close_block()
self.gen_line('romPos += SIZEOF(.ucodeText);')
self.gen_newline()
def gen_data_section(self):
self.gen_line('.main_data 0x80000400 : AT(romPos) SUBALIGN(16)')
self.gen_open_block()
self.gen_line(BUILD_DIR + '/data/dkr.data.o(.data);')
self.gen_close_block()
self.gen_line('romPos += SIZEOF(.main_data);')
self.gen_newline()
def gen_ucode_data_section(self):
self.gen_line('.ucodeData 0 : AT(romPos)')
self.gen_open_block()
self.gen_line(BUILD_DIR + '/asm/assets/ucode_data.o(.text);')
self.gen_close_block()
self.gen_line('romPos += SIZEOF(.ucodeData);')
self.gen_newline()
2020-05-27 19:14:56 -05:00
def gen_assets_section(self):
self.gen_line('__ASSETS_LUT_START = romPos;');
self.gen_newline()
self.gen_line('.assets_lut 0 : AT(romPos)')
self.gen_open_block()
self.gen_line(BUILD_DIR + '/asm/assets/assets_lut.o(.text);')
self.gen_close_block()
self.gen_line('romPos += SIZEOF(.assets_lut);')
self.gen_newline()
self.gen_line('__ASSETS_LUT_END = romPos;');
self.gen_newline()
2020-05-27 19:14:56 -05:00
self.gen_line('.assets 0 : AT(romPos)')
self.gen_open_block()
self.gen_line(BUILD_DIR + '/asm/assets/assets.o(.text);')
2020-05-27 19:14:56 -05:00
self.gen_close_block()
self.gen_line('romPos += SIZEOF(.assets);')
self.gen_newline()
def gen_discard(self):
self.gen_comment('Discard everything not specifically mentioned above.')
self.gen_line('/DISCARD/ :')
self.gen_open_block()
self.gen_line('*(*);')
self.gen_close_block()
def increase_indent(self):
self.indentLevel += 1
def decrease_indent(self):
self.indentLevel -= 1
def gen_open_block(self):
self.gen_line('{')
self.increase_indent()
def gen_close_block(self):
self.decrease_indent()
self.gen_line('}')
def gen_line(self, text):
spaces = 4 * self.indentLevel
while spaces > 0:
self.file.write(' ')
spaces -= 1
self.file.write(text)
self.gen_newline()
def gen_comment(self, text):
spaces = 4 * self.indentLevel
while spaces > 0:
self.file.write(' ')
spaces -= 1
self.file.write('/* ' + text + ' */')
self.gen_newline()
def gen_newline(self):
self.file.write('\n')
2020-07-31 15:45:49 -05:00
def append_files(self, files, extensions, directory, outputDir):
filenames = FileUtil.get_filenames_from_directory(directory, extensions)
regex = r'[\/][*]+\s*RAM_POS:\s*0x([0-9a-fA-F]+)\s*[*]+[\/]'
for filename in filenames:
with open(directory + '/' + filename, 'r') as inFile:
notDone = True
line = inFile.readline()
while line:
matches = re.match(regex, line)
if matches is None:
line = inFile.readline()
continue
matchedGroups = matches.groups()
files.append((outputDir + filename[:-2] + '.o', '', matchedGroups[0], 0))
break
2020-06-27 20:31:57 -05:00
def get_code_files(self):
files = []
self.append_files(files, ('.s',), ASM_DIR, BUILD_DIR + '/asm/')
self.append_files(files, ('.c',), SRC_DIR, BUILD_DIR + '/src/')
self.append_files(files, ('.s',), LIB_ASM_DIR, BUILD_DIR + '/lib/asm/')
self.append_files(files, ('.c',), LIB_SRC_DIR, BUILD_DIR + '/lib/src/')
2020-06-27 20:31:57 -05:00
files.sort(key = lambda x: (x[2], x[3])) # Sort tuples by RAM address and prioritize src files first.
return files
def get_asset_files(self):
assetFiles = []
mainLUT = ''
with open(ASSETS_DIR + '/assets.json') as jsonFile:
data = json.load(jsonFile)
for asset in data['assets']:
if asset['category'] == 'main':
if mainLUT != '':
raise Exception('Category "main" was expected to only have 1 item. Please update generate_ld.py.')
mainLUT = BUILD_DIR + '/' + asset['filename']
continue
filename, extension = os.path.splitext(asset['filename'])
if extension == '.cbin' or extension == '.ebin':
filename += extension
else:
filename += '.bin'
assetFiles.append((BUILD_DIR + '/' + filename, extension))
return assetFiles, mainLUT
def generate_assets_file(self):
assets, mainLUT = self.get_asset_files()
assetsText = '# This file was generated by generate_ld.py\n\n'
assetsText += '.macro .incbinaligned filename\n .balign 16\n .incbin "\\filename"\n.endm\n\n'
prevAssetMadeAlignment = False
for asset in assets:
if 'lut' in asset[0]:
#assetsText += '.balign 16\n'
prevAssetMadeAlignment = True
if prevAssetMadeAlignment:
assetsText += '.incbinaligned "./' + asset[0] + '"\n'
else:
assetsText += '.incbin "./' + asset[0] + '"\n'
if asset[1] == '.png' or asset[1] == '.cbin' or 'lut' in asset[0]: # Make sure that compressed data ends on a 16-byte boundary
#assetsText += '.balign 16\n'
prevAssetMadeAlignment = True
else:
prevAssetMadeAlignment = False
with open(ASSETS_FILENAME, "w") as assetsFile:
assetsFile.write(assetsText)
assetsLutText = '# This file was generated by generate_ld.py\n\n'
assetsLutText += '.incbin "./' + mainLUT + '"\n'
with open(ASSETS_LUT_FILENAME, "w") as assetsLutFile:
assetsLutFile.write(assetsLutText)
def get_ucode_files(self):
ucode_files = [[], []]
assetFilenames = FileUtil.getListOfFiles(UCODE_DIR)
regex = r'[.][\/]ucode[\/][^\/]*[\/](([^\/]*[\/])?[^.]*)[.](([.]?[^.]*)+)([.][A-Za-z0-9_]*)'
for filename in assetFilenames:
matches = re.match(regex, filename)
if matches is None:
raise Exception('Invalid filename: \"' + filename + '"')
matchedGroups = matches.groups()
fileExtension = matchedGroups[4]
fileProperties = matchedGroups[2].split('.')
ramAddress = fileProperties[0]
outFilename = BUILD_DIR + '/ucode/' + matchedGroups[0] + '.' + matchedGroups[2] + '.bin'
if matchedGroups[0].startswith('ucode_'):
ucode_files[0].append((outFilename, ramAddress, fileExtension))
else:
ucode_files[1].append((outFilename, ramAddress, fileExtension))
ucode_files[0].sort(key = lambda x: x[1]) # Sort tuples by RAM address
ucode_files[1].sort(key = lambda x: x[1]) # Sort tuples by RAM address
return ucode_files
def generate_ucode_files(self):
ucodeFiles = self.get_ucode_files()
assetsUCodeText = '# This file was generated by generate_ld.py\n\n'
assetsUCodeData = '# This file was generated by generate_ld.py\n\n'
for file in ucodeFiles[0]:
assetsUCodeText += '.incbin "./' + file[0] + '"\n'
for file in ucodeFiles[1]:
assetsUCodeData += '.incbin "./' + file[0] + '"\n'
with open(UCODE_TEXT_FILENAME, "w") as assetsFile:
assetsFile.write(assetsUCodeText)
with open(UCODE_DATA_FILENAME, "w") as assetsFile:
assetsFile.write(assetsUCodeData)
2020-05-27 19:14:56 -05:00
with open(LD_NAME, 'w') as ldFile:
LD(ldFile)