Format the binary file as Intel HEX records and return them as a
        string.

        `number_of_data_bytes` is the number of data bytes in each
        record.

        `address_length_bits` is the number of address bits in each
        record.

        >>> print(binfile.as_ihex())
        :20010000214601360121470136007EFE09D219012146017E17C20001FF5F16002148011979
        :20012000194E79234623965778239EDA3F01B2CA3F0156702B5E712B722B7321460134219F
        :00000001FF

def as_ihex(self, number_of_data_bytes=32, address_length_bits=32):
        """Format the binary file as Intel HEX records and return them as a
        string.

        `number_of_data_bytes` is the number of data bytes in each
        record.

        `address_length_bits` is the number of address bits in each
        record.

        >>> print(binfile.as_ihex())
        :20010000214601360121470136007EFE09D219012146017E17C20001FF5F16002148011979
        :20012000194E79234623965778239EDA3F01B2CA3F0156702B5E712B722B7321460134219F
        :00000001FF

        """

        def i32hex(address, extended_linear_address, data_address):
            if address > 0xffffffff:
                raise Error(
                    'cannot address more than 4 GB in I32HEX files (32 '
                    'bits addresses)')

            address_upper_16_bits = (address >> 16)
            address &= 0xffff

            # All segments are sorted by address. Update the
            # extended linear address when required.
            if address_upper_16_bits > extended_linear_address:
                extended_linear_address = address_upper_16_bits
                packed = pack_ihex(IHEX_EXTENDED_LINEAR_ADDRESS,
                                   0,
                                   2,
                                   binascii.unhexlify('{:04X}'.format(
                                       extended_linear_address)))
                data_address.append(packed)

            return address, extended_linear_address

        def i16hex(address, extended_segment_address, data_address):
            if address > 16 * 0xffff + 0xffff:
                raise Error(
                    'cannot address more than 1 MB in I16HEX files (20 '
                    'bits addresses)')

            address_lower = (address - 16 * extended_segment_address)

            # All segments are sorted by address. Update the
            # extended segment address when required.
            if address_lower > 0xffff:
                extended_segment_address = (4096 * (address >> 16))

                if extended_segment_address > 0xffff:
                    extended_segment_address = 0xffff

                address_lower = (address - 16 * extended_segment_address)
                packed = pack_ihex(IHEX_EXTENDED_SEGMENT_ADDRESS,
                                   0,
                                   2,
                                   binascii.unhexlify('{:04X}'.format(
                                       extended_segment_address)))
                data_address.append(packed)

            return address_lower, extended_segment_address

        def i8hex(address):
            if address > 0xffff:
                raise Error(
                    'cannot address more than 64 kB in I8HEX files (16 '
                    'bits addresses)')

        data_address = []
        extended_segment_address = 0
        extended_linear_address = 0

        for address, data in self._segments.chunks(number_of_data_bytes):
            if address_length_bits == 32:
                address, extended_linear_address = i32hex(address,
                                                          extended_linear_address,
                                                          data_address)
            elif address_length_bits == 24:
                address, extended_segment_address = i16hex(address,
                                                           extended_segment_address,
                                                           data_address)
            elif address_length_bits == 16:
                i8hex(address)
            else:
                raise Error(
                    'expected address length 16, 24 or 32, but got {}'.format(
                        address_length_bits))

            data_address.append(pack_ihex(IHEX_DATA,
                                          address,
                                          len(data),
                                          data))

        footer = []

        if self.execution_start_address is not None:
            if address_length_bits == 24:
                address = binascii.unhexlify(
                    '{:08X}'.format(self.execution_start_address))
                footer.append(pack_ihex(IHEX_START_SEGMENT_ADDRESS,
                                        0,
                                        4,
                                        address))
            elif address_length_bits == 32:
                address = binascii.unhexlify(
                    '{:08X}'.format(self.execution_start_address))
                footer.append(pack_ihex(IHEX_START_LINEAR_ADDRESS,
                                        0,
                                        4,
                                        address))

        footer.append(pack_ihex(IHEX_END_OF_FILE, 0, 0, None))

        return '\n'.join(data_address + footer) + '\n'