1#------------------------------------------------------------------------------- 2# Copyright (c) 2023, Arm Limited. All rights reserved. 3# 4# SPDX-License-Identifier: BSD-3-Clause 5# 6#------------------------------------------------------------------------------- 7import yaml 8import logging, logging.handlers 9import os 10import argparse 11 12from yaml.loader import SafeLoader 13 14# logging setup 15logging.basicConfig(level=logging.WARNING, format='%(name)s - %(levelname)s - %(message)s') 16 17parser = argparse.ArgumentParser() 18parser.add_argument("--input_file", help="DMA programs high level yaml file", required=True) 19parser.add_argument("--output_dir", help="Output directory", required=True) 20args = parser.parse_args() 21 22class Loader(yaml.SafeLoader): 23 def __init__(self, stream): 24 self._root = os.path.split(stream.name)[0] 25 super(Loader, self).__init__(stream) 26 27 # load nested yaml files (if any) 28 def include(self, node): 29 filepath = os.path.join(self._root, self.construct_scalar(node)) 30 command_name = os.path.basename(self.construct_scalar(node)).replace('.yaml', '') 31 32 with open(filepath, 'r') as f: 33 child_node = yaml.load(f, Loader) 34 child_node['command_name'] = command_name 35 return child_node 36 37Loader.add_constructor('!include', Loader.include) 38 39# calculate header word from bit fields 40def calculate_header_word(header): 41 final_val=0 42 for i in range(len(header)): 43 for key in header[i]: 44 val=header[i][key] 45 final_val = final_val + (val << i) 46 return final_val 47 48 49def parse_store(command, key, reference_string): 50 return command_storage_locations[reference_string] 51 52def parse_exec(command, key, reference_string): 53 command_location = command_execution_locations[reference_string] 54 # Need to set bit 0 if the link should be executed 55 if key != 'SRCADDR' and key != 'DESADDR': 56 try: 57 if command['execute_link']: 58 command_location += 1 59 except KeyError: 60 # Default to performing the link 61 command_location += 1 62 return command_location 63 64def parse_size(command, key, reference_string): 65 size = sizes[reference_string] 66 if key == 'XSIZE': 67 size = size // 4 68 size &= 0xFFFF 69 size |= size << 16 70 elif key != 'SRCADDR' and key != 'DESADDR': 71 # Convert size to words 72 size = size // 4 73 return size 74 75def parse_base_address(command, key, reference_string): 76 return location_base_addresses[reference_string] 77 78def parse(command, key, reference_string): 79 if "-" in reference_string: 80 split = reference_string.split(" - ", maxsplit=1) 81 return parse(command, key, split[0].lstrip()) - parse(command, key, split[1]) 82 83 if "+" in reference_string: 84 split = reference_string.split(" + ", maxsplit=1) 85 return parse(command, key, split[0].lstrip()) + parse(command, key, split[1]) 86 87 if "/" in reference_string: 88 split = reference_string.split(" / ", maxsplit=1) 89 return parse(command, key, split[0].lstrip()) // parse(command, key, split[1]) 90 91 if "*" in reference_string: 92 split = reference_string.split(" * ", maxsplit=1) 93 return parse(command, key, split[0].lstrip()) * parse(command, key, split[1]) 94 95 if "_store_addr" in reference_string: 96 value = parse_store(command, key, reference_string.replace("_store_addr", "")) 97 elif "_exec_addr" in reference_string: 98 value = parse_exec(command, key, reference_string.replace("_exec_addr", "")) 99 elif "_size" in reference_string: 100 value = parse_size(command, key, reference_string.replace("_size", "")) 101 elif "_base_address" in reference_string: 102 value = parse_base_address(command, key, reference_string.replace("_base_address", "")) 103 else: 104 value = int(reference_string, 0) 105 106 logging.debug('resolving reference {} as {}'.format(reference_string, hex(value))) 107 return value 108 109# load top level input config file 110with open(args.input_file, 'r') as f: 111 data = yaml.load(f, Loader) 112 113program_count = len(data["program"]) 114 115location_base_addresses={} 116location_next_addresses={} 117location_word_arrays={} 118output_locations={} 119 120command_storage_locations = {} 121command_execution_locations = {} 122sizes = {} 123 124reserved_keys=['command_name', 'execute_link'] 125 126# Setup locations 127for location in data['locations']: 128 location_word_arrays[location] = [] 129 location_base_addresses[location] = data['locations'][location]['base_address'] 130 try: 131 reserved_size = data['locations'][location]['reserved'] 132 except KeyError: 133 reserved_size = 0 134 location_next_addresses[location] = data['locations'][location]['base_address'] + reserved_size 135 try: 136 sizes[location] = data['locations'][location]['size'] 137 size = sizes[location] 138 except KeyError: 139 size = 'unknown' 140 pass 141 logging.info('Location {} at {}, size {}, first usable address {}'.format( 142 location, 143 hex(location_base_addresses[location]), 144 size, 145 hex(location_next_addresses[location]))) 146 147for program in data['program']: 148 commands = program['commands'] 149 sizes[program['name']] = 0 150 for command in commands: 151 command_size = sum([1 for key in command if key not in reserved_keys]) * 4 152 sizes[command['command_name']] = command_size 153 sizes[program['name']] += command_size 154 command_storage_locations[command['command_name']] = location_next_addresses[program['storage_location']] 155 command_execution_locations[command['command_name']] = location_next_addresses[program['execution_location']] 156 location_next_addresses[program['storage_location']] += command_size 157 # don't increment twice if the storage location is the same as the 158 # execution location 159 if location_next_addresses[program['storage_location']] != location_next_addresses[program['execution_location']]: 160 location_next_addresses[program['execution_location']] += command_size 161 output_locations[program['storage_location']] = True 162 logging.info('Command {} stored at {}, executed from {}, size {}'.format( 163 command['command_name'], 164 hex(command_storage_locations[command['command_name']]), 165 hex(command_execution_locations[command['command_name']]), 166 sizes[command['command_name']], 167 )) 168 logging.info('Program {} stored at {}, executed from {}, size {}'.format( 169 program['name'], 170 hex(location_next_addresses[program['storage_location']] - sizes[program['name']]), 171 hex(location_next_addresses[program['execution_location']] - sizes[program['name']]), 172 sizes[program['name']], 173 )) 174 175for program in data['program']: 176 commands = program['commands'] 177 for command in commands: 178 command["Header"] = calculate_header_word(command["Header"]) 179 command_array = [] 180 for key in command: 181 if key in reserved_keys: 182 continue 183 try: 184 command_array.append(int(command[key])) 185 except ValueError: 186 command_array.append(int(parse(command, key, command[key]))) 187 location_word_arrays[program['storage_location']] += command_array 188 189for location in output_locations: 190 try: 191 reserved_size = data['locations'][location]['reserved'] 192 except KeyError: 193 reserved_size = 0 194 if len(location_word_arrays[location]) * 4 + reserved_size > sizes[location]: 195 raise Exception 196 with open(os.path.join(args.output_dir, location + "_dma_ics.bin"), mode="wb") as bin_file: 197 with open(os.path.join(args.output_dir, location + "_dma_ics.hex"), mode="wt") as hex_file: 198 logging.info('Writing output binary for location {} to file {} of size {}'.format( 199 location, os.path.join(args.output_dir, location + "_dma_ics.bin"), 200 len(location_word_arrays[location]) * 4)) 201 logging.info('Writing output hex for location {} to file {} of size {}'.format( 202 location, os.path.join(args.output_dir, location + "_dma_ics.hex"), 203 len(location_word_arrays[location]) * 4)) 204 for word in location_word_arrays[location]: 205 bin_file.write(word.to_bytes(4, byteorder='little')) 206 hex_file.write(word.to_bytes(4, byteorder='big').hex() + '\n') 207