2020-05-27 19:14:56 -05:00
|
|
|
import re
|
2020-06-12 17:09:01 -05:00
|
|
|
import os
|
2020-05-27 19:14:56 -05:00
|
|
|
|
|
|
|
|
from file_util import FileUtil
|
|
|
|
|
|
2020-06-12 17:09:01 -05:00
|
|
|
# Possible TODO: Move generating assets.s into a seperate python script.
|
|
|
|
|
|
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'
|
2020-06-12 17:09:01 -05:00
|
|
|
ASSETS_S_FILENAME = './asm/assets/assets.s'
|
2020-07-16 02:52:53 -05:00
|
|
|
ASSETS_UCODE_S_FILENAME = './asm/assets/ucode.s'
|
2020-06-12 17:09:01 -05:00
|
|
|
ASSETS_DIR = './assets/us_1.0'
|
|
|
|
|
ASSETS_START = 0x0D8200
|
2020-08-04 15:00:36 -05:00
|
|
|
BUILD_DIR = 'build/us_1.0'
|
2020-05-27 19:14:56 -05:00
|
|
|
|
|
|
|
|
class LD:
|
|
|
|
|
def __init__(self, file):
|
|
|
|
|
print('Generating linker file...')
|
2020-06-12 17:09:01 -05:00
|
|
|
self.generate_assets_file()
|
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_macros()
|
|
|
|
|
self.gen_sections()
|
|
|
|
|
print('New linker file created!')
|
2020-06-12 17:09:01 -05:00
|
|
|
|
2020-05-27 19:14:56 -05:00
|
|
|
def gen_macros(self):
|
|
|
|
|
self.gen_line('#define BEGIN_SEG(name, addr) \\')
|
|
|
|
|
self.increase_indent()
|
|
|
|
|
self.gen_line('_##name##SegmentStart = ADDR(.name); \\')
|
|
|
|
|
self.gen_line('_##name##SegmentRomStart = __romPos; \\')
|
|
|
|
|
self.gen_line('.name addr : AT(__romPos)')
|
|
|
|
|
self.decrease_indent()
|
|
|
|
|
self.gen_newline()
|
|
|
|
|
self.gen_line('#define END_SEG(name) \\')
|
|
|
|
|
self.increase_indent()
|
|
|
|
|
self.gen_line('_##name##SegmentEnd = ADDR(.name) + SIZEOF(.name); \\')
|
|
|
|
|
self.gen_line('_##name##SegmentRomEnd = __romPos + SIZEOF(.name); \\')
|
|
|
|
|
self.gen_line('__romPos += SIZEOF(.name);')
|
|
|
|
|
self.decrease_indent()
|
|
|
|
|
self.gen_newline()
|
|
|
|
|
|
|
|
|
|
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()
|
2020-07-16 02:52:53 -05:00
|
|
|
self.gen_ucode_section()
|
|
|
|
|
self.gen_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()
|
2020-08-04 15:00:36 -05:00
|
|
|
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()
|
|
|
|
|
|
2020-07-16 02:52:53 -05:00
|
|
|
def gen_ucode_section(self):
|
|
|
|
|
self.gen_line('.ucode 0 : AT(romPos)')
|
|
|
|
|
self.gen_open_block()
|
2020-08-04 15:00:36 -05:00
|
|
|
self.gen_line(BUILD_DIR + '/asm/assets/ucode.o(.text);')
|
2020-07-16 02:52:53 -05:00
|
|
|
self.gen_close_block()
|
|
|
|
|
self.gen_line('romPos += SIZEOF(.ucode);')
|
|
|
|
|
self.gen_newline()
|
|
|
|
|
|
|
|
|
|
def gen_data_section(self):
|
|
|
|
|
self.gen_line('.main_data 0x80000400 : AT(romPos) SUBALIGN(16)')
|
|
|
|
|
self.gen_open_block()
|
2020-08-04 15:00:36 -05:00
|
|
|
self.gen_line(BUILD_DIR + '/data/dkr.data.o(.data);')
|
2020-07-16 02:52:53 -05:00
|
|
|
self.gen_close_block()
|
|
|
|
|
self.gen_line('romPos += SIZEOF(.main_data);')
|
|
|
|
|
self.gen_newline()
|
|
|
|
|
|
2020-05-27 19:14:56 -05:00
|
|
|
def gen_assets_section(self):
|
|
|
|
|
self.gen_line('.assets 0 : AT(romPos)')
|
|
|
|
|
self.gen_open_block()
|
2020-08-04 15:00:36 -05:00
|
|
|
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-12 17:09:01 -05:00
|
|
|
|
2020-06-27 20:31:57 -05:00
|
|
|
def get_code_files(self):
|
|
|
|
|
files = []
|
2020-08-04 15:00:36 -05:00
|
|
|
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
|
2020-06-12 17:09:01 -05:00
|
|
|
|
|
|
|
|
def get_asset_files(self):
|
|
|
|
|
assetFiles = []
|
|
|
|
|
assetFilenames = FileUtil.getListOfFiles(ASSETS_DIR)
|
|
|
|
|
regex = r'[.][\/]assets[\/][^\/]*[\/]([^\/]*[\/][^.]*)[.](([.]?[^.]*)+)([.][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()
|
2020-07-16 02:52:53 -05:00
|
|
|
isMicrocode = False
|
|
|
|
|
if matchedGroups[0].startswith('ucode/ucode_'):
|
|
|
|
|
isMicrocode = True
|
2020-06-12 17:09:01 -05:00
|
|
|
fileExtension = matchedGroups[3]
|
|
|
|
|
fileProperties = matchedGroups[1].split('.')
|
|
|
|
|
ramAddress = fileProperties[0]
|
2020-06-15 09:30:56 -05:00
|
|
|
if fileExtension == '.cbin' or fileExtension == '.ebin':
|
|
|
|
|
outFileExtension = fileExtension
|
|
|
|
|
else:
|
|
|
|
|
outFileExtension = '.bin'
|
2020-08-04 15:00:36 -05:00
|
|
|
outFilename = BUILD_DIR + '/' + matchedGroups[0] + '.' + matchedGroups[1] + outFileExtension
|
2020-06-12 17:09:01 -05:00
|
|
|
if int(ramAddress, 16) >= ASSETS_START:
|
2020-07-16 02:52:53 -05:00
|
|
|
assetFiles.append((outFilename, ramAddress, fileExtension, isMicrocode))
|
2020-06-12 17:09:01 -05:00
|
|
|
assetFiles.sort(key = lambda x: x[1]) # Sort tuples by RAM address
|
|
|
|
|
return assetFiles
|
|
|
|
|
|
|
|
|
|
def generate_assets_file(self):
|
|
|
|
|
assets = self.get_asset_files()
|
|
|
|
|
assetsText = '# This file was generated by generate_ld.py\n\n'
|
2020-06-24 14:33:15 -05:00
|
|
|
assetsText += '.macro .incbinaligned filename\n .balign 16\n .incbin "\\filename"\n.endm\n\n'
|
2020-07-16 02:52:53 -05:00
|
|
|
assetsUCodeText = '# This file was generated by generate_ld.py\n\n'
|
2020-06-13 08:14:27 -05:00
|
|
|
prevAssetMadeAlignment = False
|
2020-06-12 17:09:01 -05:00
|
|
|
for asset in assets:
|
2020-06-24 14:33:15 -05:00
|
|
|
if 'lut' in asset[0]:
|
|
|
|
|
#assetsText += '.balign 16\n'
|
|
|
|
|
prevAssetMadeAlignment = True
|
|
|
|
|
if prevAssetMadeAlignment:
|
|
|
|
|
assetsText += '.incbinaligned "./' + asset[0] + '"\n'
|
|
|
|
|
else:
|
2020-07-16 02:52:53 -05:00
|
|
|
if asset[3]:
|
|
|
|
|
assetsUCodeText += '.incbin "./' + asset[0] + '"\n'
|
|
|
|
|
else:
|
|
|
|
|
assetsText += '.incbin "./' + asset[0] + '"\n'
|
|
|
|
|
|
2020-06-24 14:33:15 -05:00
|
|
|
if asset[2] == '.png' or asset[2] == '.cbin' or 'lut' in asset[0]: # Make sure that compressed data ends on a 16-byte boundary
|
|
|
|
|
#assetsText += '.balign 16\n'
|
2020-06-13 08:14:27 -05:00
|
|
|
prevAssetMadeAlignment = True
|
|
|
|
|
else:
|
|
|
|
|
prevAssetMadeAlignment = False
|
2020-06-12 17:09:01 -05:00
|
|
|
with open(ASSETS_S_FILENAME, "w") as assetsFile:
|
|
|
|
|
assetsFile.write(assetsText)
|
2020-07-16 02:52:53 -05:00
|
|
|
with open(ASSETS_UCODE_S_FILENAME, "w") as assetsFile:
|
|
|
|
|
assetsFile.write(assetsUCodeText)
|
|
|
|
|
|
2020-05-27 19:14:56 -05:00
|
|
|
|
|
|
|
|
|
|
|
|
|
with open(LD_NAME, 'w') as ldFile:
|
|
|
|
|
LD(ldFile)
|