def _get_incremental_codewords(config, base_ecc, existing_words): '''Get all possible incremental codewords fulfilling the constraints.''' base_data = base_ecc[config['secded']['ecc_width']:] # We only need to spin through data bits that have not been set yet. # Hence, we first count how many bits are zero (and hence still # modifyable). Then, we enumerate all possible combinations and scatter # the bits of the enumerated values into the correct bit positions using # the scatter_bits() function. incr_cands = [] free_bits = base_data.count('0') for k in range(1, 2**free_bits): # Get incremental dataword by scattering the enumeration bits # into the zero bit positions in base_data. incr_cand = scatter_bits(base_data, format(k, '0' + str(free_bits) + 'b')) incr_cand_ecc = ecc_encode(config, incr_cand) # Dataword is correct by construction, but we need to check whether # the ECC bits are incremental. if _is_incremental_codeword(base_ecc, incr_cand_ecc): # Check whether the candidate fulfills the maximum # Hamming weight constraint. if incr_cand_ecc.count('1') <= config['max_hw']: # Check Hamming distance wrt all existing words. for w in existing_words + [base_ecc]: if get_hd(incr_cand_ecc, w) < config['min_hd']: break else: incr_cands.append(incr_cand_ecc) return incr_cands
def _get_new_state_word_pair(config, existing_words): '''Randomly generate a new incrementally writable word pair''' while 1: # Draw a random number and check whether it is unique and whether # the Hamming weight is in range. width = config['secded']['data_width'] ecc_width = config['secded']['ecc_width'] base = random.getrandbits(width) base = format(base, '0' + str(width) + 'b') base_cand_ecc = ecc_encode(config, base) # disallow all-zero and all-one states pop_cnt = base_cand_ecc.count('1') if pop_cnt >= config['min_hw'] and pop_cnt <= config['max_hw']: # Check Hamming distance wrt all existing words for w in existing_words: if get_hd(base_cand_ecc, w) < config['min_hd']: break else: # Get encoded incremental candidates. incr_cands_ecc = _get_incremental_codewords( config, base_cand_ecc, existing_words) # there are valid candidates, draw one at random. # otherwise we just start over. if incr_cands_ecc: incr_cand_ecc = random.choice(incr_cands_ecc) log.info('word {}: {}|{} -> {}|{}'.format( int(len(existing_words) / 2), base_cand_ecc[ecc_width:], base_cand_ecc[0:ecc_width], incr_cand_ecc[ecc_width:], incr_cand_ecc[0:ecc_width])) existing_words.append(base_cand_ecc) existing_words.append(incr_cand_ecc) return (base_cand_ecc, incr_cand_ecc)
def _to_hexfile_with_ecc(data, annotation, config, data_perm): '''Compute ECC and convert into memory hexfile''' log.info('Convert to HEX file.') data_width = config['secded']['data_width'] ecc_width = config['secded']['ecc_width'] assert data_width % 8 == 0, \ 'OTP data width must be a multiple of 8' assert data_width <= 64, \ 'OTP data width cannot be larger than 64' num_words = len(data) * 8 // data_width bytes_per_word = data_width // 8 # Byte aligned total width after adding ECC bits bytes_per_word_ecc = (data_width + ecc_width + 7) // 8 bit_padding = bytes_per_word_ecc * 8 - data_width - ecc_width bin_format_str = '0' + str(data_width) + 'b' hex_format_str = '0' + str(bytes_per_word_ecc * 2) + 'x' memory_words = '// OTP memory hexfile with {} x {}bit layout\n'.format( num_words, bytes_per_word_ecc * 8) log.info('Memory layout is {} x {}bit (with ECC)'.format( num_words, bytes_per_word_ecc * 8)) for k in range(num_words): # Assemble native OTP word and uniquify annotation for comments word = 0 word_ann = {} for j in range(bytes_per_word): idx = k * bytes_per_word + j word += data[idx] << (j * 8) if annotation[idx] not in word_ann: word_ann.update({annotation[idx]: "1"}) # This prints the byte offset of the corresponding # payload data in the memory map (excluding ECC bits) annotation_str = ' // {:06x}: '.format(k * bytes_per_word) + ', '.join( word_ann.keys()) # ECC encode word_bin = format(word, bin_format_str) word_bin = ecc_encode(config, word_bin) # Pad to word boundary and permute data if needed word_bin = ('0' * bit_padding) + word_bin word_bin = permute_bits(word_bin, data_perm) word_hex = format(int(word_bin, 2), hex_format_str) memory_words += word_hex + annotation_str + '\n' log.info('Done.') return memory_words