def generate_cheader(fields, input_dir, output_dir): """ Generates C header file from the `template_file`. It produces a list of tuples with a field name and the `MemoryRegion` object, which is used in the `template_path`. The resulting header file is placed into `output_path`. """ template_path = input_dir / 'manifest.h.tpl' output_path = output_dir / 'manifest.h' base_name = Name.from_snake_case("ROM_EXT") regions = [] offsets = [] current_offset_bytes = 0 for field in fields: required_alignment_bits = field.get("alignment", 32) assert required_alignment_bits % 8 == 0 required_alignment_bytes = required_alignment_bits // 8 # The 8-byte two-step https://zinascii.com/2014/the-8-byte-two-step.html # This ends up aligning `current_offset_bytes` to `required_alignment_bytes` # that is greater than or equal to `current_offset_bytes`. current_offset_bytes = (current_offset_bytes + required_alignment_bytes - 1) \ & ~(required_alignment_bytes - 1) if field['type'] == "offset": offset_name = base_name + Name.from_snake_case(field['name']) offset = MemoryOffset(offset_name, current_offset_bytes) offsets.append((field['name'], offset)) else: assert field['size'] % 8 == 0 size_bytes = field['size'] // 8 if field['type'] == "field": region_name = base_name + Name.from_snake_case(field['name']) region = MemoryRegion(region_name, current_offset_bytes, size_bytes) regions.append((field['name'], region)) current_offset_bytes += size_bytes with template_path.open('r') as f: template = Template(f.read()) header = template.render(regions=regions, offsets=offsets) with output_path.open('w') as f: f.write(header) print('Template sucessfuly written to {}.'.format(output_path))
def generate_defines(fields): """ Generates manifest defines. This produces two lists of tuples. One with a field name and the `MemoryRegion` object, and one with `MemoryOffset` object. Please see the description at the top for more information on the differences between these objects. """ base_name = Name.from_snake_case("ROM_EXT") regions = [] offsets = [] current_offset_bytes = 0 for field in fields: required_alignment_bits = field.get("alignment", 32) assert required_alignment_bits % 8 == 0 required_alignment_bytes = required_alignment_bits // 8 # The 8-byte two-step https://zinascii.com/2014/the-8-byte-two-step.html # This ends up aligning `current_offset_bytes` to `required_alignment_bytes` # that is greater than or equal to `current_offset_bytes`. current_offset_bytes = (current_offset_bytes + required_alignment_bytes - 1) \ & ~(required_alignment_bytes - 1) if field['type'] == "offset": offset_name = base_name + Name.from_snake_case(field['name']) offset = MemoryOffset(offset_name, current_offset_bytes) offsets.append((field['name'], offset)) else: assert field['size'] % 8 == 0 size_bytes = field['size'] // 8 if field['type'] == "field": region_name = base_name + Name.from_snake_case(field['name']) region = MemoryRegion(region_name, current_offset_bytes, size_bytes) regions.append((field['name'], region)) current_offset_bytes += size_bytes return (regions, offsets)
def generate_defines(fields, verbose=False): """ Generates manifest defines. This produces two lists of tuples. One with a field name and the `MemoryRegion` object, and one with `MemoryOffset` object. Please see the description at the top for more information on the differences between these objects. """ def print_field_info(name, offset, size, alignment, required_alignment): if verbose: print("0x{:04x} - 0x{:04x}: {} (alignment: {} reqd: {})".format( offset, offset + size, name, alignment, required_alignment)) def print_offset_info(name, offset, alignment, required_alignment): if verbose: print(" @ 0x{:04x}: {} (alignment: {} reqd: {})".format( offset, name, alignment, required_alignment)) base_name = Name.from_snake_case("ROM_EXT") regions = [] offsets = [] current_offset_bytes = 0 for field in fields: required_alignment_bits = field.get("alignment", 32) assert required_alignment_bits % 8 == 0 required_alignment_bytes = required_alignment_bits // 8 # The 8-byte two-step https://zinascii.com/2014/the-8-byte-two-step.html # This ends up aligning `new_offset_bytes` to `required_alignment_bytes` # that is greater than or equal to `current_offset_bytes`. new_offset_bytes = (current_offset_bytes + required_alignment_bytes - 1) \ & ~(required_alignment_bytes - 1) if new_offset_bytes != current_offset_bytes and verbose: print("0x{:04x} - 0x{:04x}: - (realignment) -".format( current_offset_bytes, new_offset_bytes)) current_offset_bytes = new_offset_bytes # This works becuase e.g. 6 is `0b0...00110` and ~(6-1) is `0b1..11010`, # giving a result of `0b0...010`, or 2. current_offset_alignment = current_offset_bytes \ & ~(current_offset_bytes - 1) if field['type'] == "offset": offset_name = base_name + Name.from_snake_case(field['name']) offset = MemoryOffset(offset_name, current_offset_bytes) offsets.append((field['name'], offset)) print_offset_info(field['name'], current_offset_bytes, current_offset_alignment, required_alignment_bytes) else: assert field['size'] % 8 == 0 size_bytes = field['size'] // 8 if field['type'] == "field": region_name = base_name + Name.from_snake_case(field['name']) region = MemoryRegion(region_name, current_offset_bytes, size_bytes) regions.append((field['name'], region)) print_field_info(field['name'], current_offset_bytes, size_bytes, current_offset_alignment, required_alignment_bytes) elif field['type'] == 'reserved' and verbose: print_field_info('- reserved -', current_offset_bytes, size_bytes, current_offset_alignment, 0) current_offset_bytes += size_bytes return (regions, offsets)