1# This file describes the common eFuses structures for chips 2# 3# SPDX-FileCopyrightText: 2020-2022 Espressif Systems (Shanghai) CO LTD 4# 5# SPDX-License-Identifier: GPL-2.0-or-later 6 7import binascii 8import re 9import sys 10 11from bitstring import BitArray, BitStream, CreationError 12 13import esptool 14 15from . import util 16 17 18class CheckArgValue(object): 19 def __init__(self, efuses, name): 20 self.efuses = efuses 21 self.name = name 22 23 def __call__(self, new_value_str): 24 def check_arg_value(efuse, new_value): 25 if efuse.efuse_type.startswith("bool"): 26 new_value = 1 if new_value is None else int(new_value, 0) 27 if new_value != 1: 28 raise esptool.FatalError( 29 "New value is not accepted for efuse '{}' " 30 "(will always burn 0->1), given value={}".format( 31 efuse.name, new_value 32 ) 33 ) 34 elif efuse.efuse_type.startswith(("int", "uint")): 35 if efuse.efuse_class == "bitcount": 36 if new_value is None: 37 # find the first unset bit and set it 38 old_value = efuse.get_raw() 39 new_value = old_value 40 bit = 1 41 while new_value == old_value: 42 new_value = bit | old_value 43 bit <<= 1 44 else: 45 new_value = int(new_value, 0) 46 else: 47 if new_value is None: 48 raise esptool.FatalError( 49 "New value required for efuse '{}' (given None)".format( 50 efuse.name 51 ) 52 ) 53 new_value = int(new_value, 0) 54 if new_value == 0: 55 raise esptool.FatalError( 56 "New value should not be 0 for '{}' " 57 "(given value= {})".format(efuse.name, new_value) 58 ) 59 elif efuse.efuse_type.startswith("bytes"): 60 if new_value is None: 61 raise esptool.FatalError( 62 "New value required for efuse '{}' " 63 "(given None)".format(efuse.name) 64 ) 65 if len(new_value) * 8 != efuse.bitarray.len: 66 raise esptool.FatalError( 67 "The length of efuse '{}' ({} bits) " 68 "(given len of the new value= {} bits)".format( 69 efuse.name, efuse.bitarray.len, len(new_value) * 8 70 ) 71 ) 72 else: 73 raise esptool.FatalError( 74 "The '{}' type for the '{}' efuse is not supported yet.".format( 75 efuse.efuse_type, efuse.name 76 ) 77 ) 78 return new_value 79 80 efuse = self.efuses[self.name] 81 new_value = efuse.check_format(new_value_str) 82 return check_arg_value(efuse, new_value) 83 84 85class EfuseProtectBase(object): 86 # This class is used by EfuseBlockBase and EfuseFieldBase 87 88 def get_read_disable_mask(self): 89 mask = 0 90 if isinstance(self.read_disable_bit, list): 91 for i in self.read_disable_bit: 92 mask |= 1 << i 93 else: 94 mask = 1 << self.read_disable_bit 95 return mask 96 97 def is_readable(self): 98 """Return true if the efuse is readable by software""" 99 num_bit = self.read_disable_bit 100 if num_bit is None: 101 return True # read cannot be disabled 102 return (self.parent["RD_DIS"].get() & (self.get_read_disable_mask())) == 0 103 104 def disable_read(self): 105 num_bit = self.read_disable_bit 106 if num_bit is None: 107 raise esptool.FatalError("This efuse cannot be read-disabled") 108 if not self.parent["RD_DIS"].is_writeable(): 109 raise esptool.FatalError( 110 "This efuse cannot be read-disabled due the to RD_DIS field is " 111 "already write-disabled" 112 ) 113 self.parent["RD_DIS"].save(self.get_read_disable_mask()) 114 115 def is_writeable(self): 116 num_bit = self.write_disable_bit 117 if num_bit is None: 118 return True # write cannot be disabled 119 return (self.parent["WR_DIS"].get() & (1 << num_bit)) == 0 120 121 def disable_write(self): 122 num_bit = self.write_disable_bit 123 if not self.parent["WR_DIS"].is_writeable(): 124 raise esptool.FatalError( 125 "This efuse cannot be write-disabled due to the WR_DIS field is " 126 "already write-disabled" 127 ) 128 self.parent["WR_DIS"].save(1 << num_bit) 129 130 def check_wr_rd_protect(self): 131 if not self.is_readable(): 132 error_msg = "\t{} is read-protected.".format(self.name) 133 "The written value can not be read, the efuse/block looks as all 0.\n" 134 error_msg += "\tBurn in this case may damage an already written value." 135 self.parent.print_error_msg(error_msg) 136 if not self.is_writeable(): 137 error_msg = "\t{} is write-protected. Burn is not possible.".format( 138 self.name 139 ) 140 self.parent.print_error_msg(error_msg) 141 142 143class EfuseBlockBase(EfuseProtectBase): 144 def __init__(self, parent, param, skip_read=False): 145 self.parent = parent 146 self.name = param.name 147 self.alias = param.alias 148 self.id = param.id 149 self.rd_addr = param.rd_addr 150 self.wr_addr = param.wr_addr 151 self.write_disable_bit = param.write_disable_bit 152 self.read_disable_bit = param.read_disable_bit 153 self.len = param.len 154 self.key_purpose_name = param.key_purpose 155 bit_block_len = self.get_block_len() * 8 156 self.bitarray = BitStream(bit_block_len) 157 self.bitarray.set(0) 158 self.wr_bitarray = BitStream(bit_block_len) 159 self.wr_bitarray.set(0) 160 self.fail = False 161 self.num_errors = 0 162 if self.id == 0: 163 self.err_bitarray = BitStream(bit_block_len) 164 self.err_bitarray.set(0) 165 else: 166 self.err_bitarray = None 167 168 if not skip_read: 169 self.read() 170 171 def get_block_len(self): 172 coding_scheme = self.get_coding_scheme() 173 if coding_scheme == self.parent.REGS.CODING_SCHEME_NONE: 174 return self.len * 4 175 elif coding_scheme == self.parent.REGS.CODING_SCHEME_34: 176 return (self.len * 3 // 4) * 4 177 elif coding_scheme == self.parent.REGS.CODING_SCHEME_RS: 178 return self.len * 4 179 else: 180 raise esptool.FatalError( 181 "Coding scheme (%d) not supported" % (coding_scheme) 182 ) 183 184 def get_coding_scheme(self): 185 if self.id == 0: 186 return self.parent.REGS.CODING_SCHEME_NONE 187 else: 188 return self.parent.coding_scheme 189 190 def get_raw(self, from_read=True): 191 if from_read: 192 return self.bitarray.bytes 193 else: 194 return self.wr_bitarray.bytes 195 196 def get(self, from_read=True): 197 self.get_bitstring(from_read=from_read) 198 199 def get_bitstring(self, from_read=True): 200 if from_read: 201 return self.bitarray 202 else: 203 return self.wr_bitarray 204 205 def convert_to_bitstring(self, new_data): 206 if isinstance(new_data, BitArray): 207 return new_data 208 else: 209 return BitArray(bytes=new_data, length=len(new_data) * 8) 210 211 def get_words(self): 212 def get_offsets(self): 213 return [x + self.rd_addr for x in range(0, self.get_block_len(), 4)] 214 215 return [self.parent.read_reg(offs) for offs in get_offsets(self)] 216 217 def read(self): 218 words = self.get_words() 219 data = BitArray() 220 for word in reversed(words): 221 data.append("uint:32=%d" % word) 222 self.bitarray.overwrite(data, pos=0) 223 self.print_block(self.bitarray, "read_regs") 224 225 def print_block(self, bit_string, comment, debug=False): 226 if self.parent.debug or debug: 227 bit_string.pos = 0 228 print( 229 "%-15s (%-16s) [%-2d] %s:" 230 % (self.name, " ".join(self.alias)[:16], self.id, comment), 231 " ".join( 232 [ 233 "%08x" % word 234 for word in bit_string.readlist( 235 "%d*uint:32" % (bit_string.len / 32) 236 )[::-1] 237 ] 238 ), 239 ) 240 241 def check_wr_data(self): 242 wr_data = self.wr_bitarray 243 if wr_data.all(False): 244 # nothing to burn 245 if self.parent.debug: 246 print("[{:02}] {:20} nothing to burn".format(self.id, self.name)) 247 return False 248 if len(wr_data.bytes) != len(self.bitarray.bytes): 249 raise esptool.FatalError( 250 "Data does not fit: the block%d size is %d bytes, data is %d bytes" 251 % (self.id, len(self.bitarray.bytes), len(wr_data.bytes)) 252 ) 253 self.check_wr_rd_protect() 254 255 if self.get_bitstring().all(False): 256 print( 257 "[{:02}] {:20} is empty, will burn the new value".format( 258 self.id, self.name 259 ) 260 ) 261 else: 262 # the written block in chip is not empty 263 if self.get_bitstring() == wr_data: 264 print( 265 "[{:02}] {:20} is already written the same value, " 266 "continue with EMPTY_BLOCK".format(self.id, self.name) 267 ) 268 wr_data.set(0) 269 else: 270 print("[{:02}] {:20} is not empty".format(self.id, self.name)) 271 print("\t(written ):", self.get_bitstring()) 272 print("\t(to write):", wr_data) 273 mask = self.get_bitstring() & wr_data 274 if mask == wr_data: 275 print( 276 "\tAll wr_data bits are set in the written block, " 277 "continue with EMPTY_BLOCK." 278 ) 279 wr_data.set(0) 280 else: 281 coding_scheme = self.get_coding_scheme() 282 if coding_scheme == self.parent.REGS.CODING_SCHEME_NONE: 283 print("\t(coding scheme = NONE)") 284 elif coding_scheme == self.parent.REGS.CODING_SCHEME_RS: 285 print("\t(coding scheme = RS)") 286 error_msg = ( 287 "\tBurn into %s is forbidden " 288 "(RS coding scheme does not allow this)." % (self.name) 289 ) 290 self.parent.print_error_msg(error_msg) 291 elif coding_scheme == self.parent.REGS.CODING_SCHEME_34: 292 print("\t(coding scheme = 3/4)") 293 data_can_not_be_burn = False 294 for i in range(0, self.get_bitstring().len, 6 * 8): 295 rd_chunk = self.get_bitstring()[i : i + 6 * 8 :] 296 wr_chunk = wr_data[i : i + 6 * 8 :] 297 if rd_chunk.any(True): 298 if wr_chunk.any(True): 299 print( 300 "\twritten chunk [%d] and wr_chunk " 301 "are not empty. " % (i // (6 * 8)), 302 end="", 303 ) 304 if rd_chunk == wr_chunk: 305 print( 306 "wr_chunk == rd_chunk. " 307 "Countinue with empty chunk." 308 ) 309 wr_data[i : i + 6 * 8 :].set(0) 310 else: 311 print("wr_chunk != rd_chunk. Can not burn.") 312 print("\twritten ", rd_chunk) 313 print("\tto write", wr_chunk) 314 data_can_not_be_burn = True 315 if data_can_not_be_burn: 316 error_msg = ( 317 "\tBurn into %s is forbidden " 318 "(3/4 coding scheme does not allow this)." % (self.name) 319 ) 320 self.parent.print_error_msg(error_msg) 321 else: 322 raise esptool.FatalError( 323 "The coding scheme ({}) is not supported".format( 324 coding_scheme 325 ) 326 ) 327 328 def save(self, new_data): 329 # new_data will be checked by check_wr_data() during burn_all() 330 # new_data (bytes) = [0][1][2] ... [N] (original data) 331 # in string format = [0] [1] [2] ... [N] (util.hexify(data, " ")) 332 # in hex format = 0x[N]....[2][1][0] (from bitstring print(data)) 333 # in reg format = [3][2][1][0] ... [N][][][] (as it will be in the device) 334 # in bitstring = [N] ... [2][1][0] (to get a correct bitstring 335 # need to reverse new_data) 336 # *[x] - means a byte. 337 data = BitStream(bytes=new_data[::-1], length=len(new_data) * 8) 338 if self.parent.debug: 339 print( 340 "\twritten : {} ->\n\tto write: {}".format(self.get_bitstring(), data) 341 ) 342 self.wr_bitarray.overwrite(self.wr_bitarray | data, pos=0) 343 344 def burn_words(self, words): 345 for burns in range(3): 346 self.parent.efuse_controller_setup() 347 if self.parent.debug: 348 print("Write data to BLOCK%d" % (self.id)) 349 write_reg_addr = self.wr_addr 350 for word in words: 351 # for ep32s2: using EFUSE_PGM_DATA[0..7]_REG for writing data 352 # 32 bytes to EFUSE_PGM_DATA[0..7]_REG 353 # 12 bytes to EFUSE_CHECK_VALUE[0..2]_REG. These regs are next after 354 # EFUSE_PGM_DATA_REG 355 # for esp32: 356 # each block has the special regs EFUSE_BLK[0..3]_WDATA[0..7]_REG 357 # for writing data 358 if self.parent.debug: 359 print("Addr 0x%08x, data=0x%08x" % (write_reg_addr, word)) 360 self.parent.write_reg(write_reg_addr, word) 361 write_reg_addr += 4 362 363 self.parent.write_efuses(self.id) 364 for _ in range(5): 365 self.parent.efuse_read() 366 self.parent.get_coding_scheme_warnings(silent=True) 367 if self.fail or self.num_errors: 368 print( 369 "Error in BLOCK%d, re-burn it again (#%d), to fix it. " 370 "fail_bit=%d, num_errors=%d" 371 % (self.id, burns, self.fail, self.num_errors) 372 ) 373 break 374 if not self.fail and self.num_errors == 0: 375 break 376 377 def burn(self): 378 if self.wr_bitarray.all(False): 379 # nothing to burn 380 return 381 before_burn_bitarray = self.bitarray[:] 382 assert before_burn_bitarray is not self.bitarray 383 self.print_block(self.wr_bitarray, "to_write") 384 words = self.apply_coding_scheme() 385 self.burn_words(words) 386 self.read() 387 if not self.is_readable(): 388 print( 389 "{} ({}) is read-protected. " 390 "Read back the burn value is not possible.".format( 391 self.name, self.alias 392 ) 393 ) 394 if self.bitarray.all(False): 395 print("Read all '0'") 396 else: 397 # Should never happen 398 raise esptool.FatalError( 399 "The {} is read-protected but not all '0' ({})".format( 400 self.name, self.bitarray.hex 401 ) 402 ) 403 else: 404 if self.wr_bitarray == self.bitarray: 405 print("BURN BLOCK%-2d - OK (write block == read block)" % self.id) 406 elif ( 407 self.wr_bitarray & self.bitarray == self.wr_bitarray 408 and self.bitarray & before_burn_bitarray == before_burn_bitarray 409 ): 410 print("BURN BLOCK%-2d - OK (all write block bits are set)" % self.id) 411 else: 412 # Happens only when an efuse is written and read-protected 413 # in one command 414 self.print_block(self.wr_bitarray, "Expected") 415 self.print_block(self.bitarray, "Real ") 416 # Read-protected BLK0 values are reported back as zeros, 417 # raise error only for other blocks 418 if self.id != 0: 419 raise esptool.FatalError( 420 "Burn {} ({}) was not successful".format(self.name, self.alias) 421 ) 422 self.wr_bitarray.set(0) 423 424 425class EspEfusesBase(object): 426 """ 427 Wrapper object to manage the efuse fields in a connected ESP bootloader 428 """ 429 430 _esp = None 431 blocks = [] 432 efuses = [] 433 coding_scheme = None 434 force_write_always = None 435 batch_mode_cnt = 0 436 437 def __iter__(self): 438 return self.efuses.__iter__() 439 440 def get_crystal_freq(self): 441 return self._esp.get_crystal_freq() 442 443 def read_efuse(self, n): 444 """Read the nth word of the ESP3x EFUSE region.""" 445 return self._esp.read_efuse(n) 446 447 def read_reg(self, addr): 448 return self._esp.read_reg(addr) 449 450 def write_reg(self, addr, value, mask=0xFFFFFFFF, delay_us=0, delay_after_us=0): 451 return self._esp.write_reg(addr, value, mask, delay_us, delay_after_us) 452 453 def update_reg(self, addr, mask, new_val): 454 return self._esp.update_reg(addr, mask, new_val) 455 456 def efuse_controller_setup(self): 457 pass 458 459 def reconnect_chip(self, esp): 460 print("Re-connecting...") 461 baudrate = esp._port.baudrate 462 port = esp._port.port 463 esp._port.close() 464 return esptool.cmds.detect_chip(port, baudrate) 465 466 def get_index_block_by_name(self, name): 467 for block in self.blocks: 468 if block.name == name or name in block.alias: 469 return block.id 470 return None 471 472 def read_blocks(self): 473 for block in self.blocks: 474 block.read() 475 476 def update_efuses(self): 477 for efuse in self.efuses: 478 efuse.update(self.blocks[efuse.block].bitarray) 479 480 def burn_all(self, check_batch_mode=False): 481 if check_batch_mode: 482 if self.batch_mode_cnt != 0: 483 print( 484 "\nBatch mode is enabled, " 485 "the burn will be done at the end of the command." 486 ) 487 return False 488 print("\nCheck all blocks for burn...") 489 print("idx, BLOCK_NAME, Conclusion") 490 have_wr_data_for_burn = False 491 for block in self.blocks: 492 block.check_wr_data() 493 if not have_wr_data_for_burn and block.get_bitstring(from_read=False).any( 494 True 495 ): 496 have_wr_data_for_burn = True 497 if not have_wr_data_for_burn: 498 print("Nothing to burn, see messages above.") 499 return 500 EspEfusesBase.confirm("", self.do_not_confirm) 501 502 # Burn from BLKn -> BLK0. Because BLK0 can set rd or/and wr protection bits. 503 for block in reversed(self.blocks): 504 old_fail = block.fail 505 old_num_errors = block.num_errors 506 block.burn() 507 if (block.fail and old_fail != block.fail) or ( 508 block.num_errors and block.num_errors > old_num_errors 509 ): 510 raise esptool.FatalError("Error(s) were detected in eFuses") 511 print("Reading updated efuses...") 512 self.read_coding_scheme() 513 self.read_blocks() 514 self.update_efuses() 515 return True 516 517 @staticmethod 518 def confirm(action, do_not_confirm): 519 print( 520 "%s%s\nThis is an irreversible operation!" 521 % (action, "" if action.endswith("\n") else ". ") 522 ) 523 if not do_not_confirm: 524 print("Type 'BURN' (all capitals) to continue.") 525 # required for Pythons which disable line buffering, ie mingw in mintty 526 sys.stdout.flush() 527 yes = input() 528 if yes != "BURN": 529 print("Aborting.") 530 sys.exit(0) 531 532 def print_error_msg(self, error_msg): 533 if self.force_write_always is not None: 534 if not self.force_write_always: 535 error_msg += "(use '--force-write-always' option to ignore it)" 536 if self.force_write_always: 537 print(error_msg, "Skipped because '--force-write-always' option.") 538 else: 539 raise esptool.FatalError(error_msg) 540 541 542class EfuseFieldBase(EfuseProtectBase): 543 def __init__(self, parent, param): 544 self.category = param.category 545 self.parent = parent 546 self.block = param.block 547 self.word = param.word 548 self.pos = param.pos 549 self.write_disable_bit = param.write_disable_bit 550 self.read_disable_bit = param.read_disable_bit 551 self.name = param.name 552 self.efuse_class = param.class_type 553 self.efuse_type = param.type 554 self.description = param.description 555 self.dict_value = param.dictionary 556 self.fail = False 557 self.num_errors = 0 558 if self.efuse_type.startswith("bool"): 559 field_len = 1 560 else: 561 field_len = int(re.search(r"\d+", self.efuse_type).group()) 562 if self.efuse_type.startswith("bytes"): 563 field_len *= 8 564 self.bitarray = BitStream(field_len) 565 self.bit_len = field_len 566 self.bitarray.set(0) 567 self.update(self.parent.blocks[self.block].bitarray) 568 569 def check_format(self, new_value_str): 570 if new_value_str is None: 571 return new_value_str 572 else: 573 if self.efuse_type.startswith("bytes"): 574 if new_value_str.startswith("0x"): 575 # cmd line: 0x0102030405060708 .... 112233ff (hex) 576 # regs: 112233ff ... 05060708 01020304 577 # BLK: ff 33 22 11 ... 08 07 06 05 04 03 02 01 578 return binascii.unhexlify(new_value_str[2:])[::-1] 579 else: 580 # cmd line: 0102030405060708 .... 112233ff (string) 581 # regs: 04030201 08070605 ... ff332211 582 # BLK: 01 02 03 04 05 06 07 08 ... 11 22 33 ff 583 return binascii.unhexlify(new_value_str) 584 else: 585 return new_value_str 586 587 def convert_to_bitstring(self, new_value): 588 if isinstance(new_value, BitArray): 589 return new_value 590 else: 591 if self.efuse_type.startswith("bytes"): 592 # new_value (bytes) = [0][1][2] ... [N] 593 # (original data) 594 # in string format = [0] [1] [2] ... [N] 595 # (util.hexify(data, " ")) 596 # in hex format = 0x[N]....[2][1][0] 597 # (from bitstring print(data)) 598 # in reg format = [3][2][1][0] ... [N][][][] 599 # (as it will be in the device) 600 # in bitstring = [N] ... [2][1][0] 601 # (to get a correct bitstring need to reverse new_value) 602 # *[x] - means a byte. 603 return BitArray(bytes=new_value[::-1], length=len(new_value) * 8) 604 else: 605 try: 606 return BitArray(self.efuse_type + "={}".format(new_value)) 607 except CreationError as err: 608 print( 609 "New value '{}' is not suitable for {} ({})".format( 610 new_value, self.name, self.efuse_type 611 ) 612 ) 613 raise esptool.FatalError(err) 614 615 def check_new_value(self, bitarray_new_value): 616 bitarray_old_value = self.get_bitstring() | self.get_bitstring(from_read=False) 617 if bitarray_new_value.len != bitarray_old_value.len: 618 raise esptool.FatalError( 619 "For {} efuse, the length of the new value is wrong, " 620 "expected {} bits, was {} bits.".format( 621 self.name, bitarray_old_value.len, bitarray_new_value.len 622 ) 623 ) 624 if bitarray_new_value == bitarray_old_value: 625 error_msg = "\tThe same value for {} ".format(self.name) 626 error_msg += "is already burned. Do not change the efuse." 627 print(error_msg) 628 bitarray_new_value.set(0) 629 elif bitarray_new_value == self.get_bitstring(from_read=False): 630 error_msg = "\tThe same value for {} ".format(self.name) 631 error_msg += "is already prepared for the burn operation." 632 print(error_msg) 633 bitarray_new_value.set(0) 634 else: 635 if self.name not in ["WR_DIS", "RD_DIS"]: 636 # WR_DIS, RD_DIS fields can have already set bits. 637 # Do not neeed to check below condition for them. 638 if bitarray_new_value | bitarray_old_value != bitarray_new_value: 639 error_msg = "\tNew value contains some bits that cannot be cleared " 640 error_msg += "(value will be {})".format( 641 bitarray_old_value | bitarray_new_value 642 ) 643 self.parent.print_error_msg(error_msg) 644 self.check_wr_rd_protect() 645 646 def save_to_block(self, bitarray_field): 647 block = self.parent.blocks[self.block] 648 wr_bitarray_temp = block.wr_bitarray.copy() 649 position = wr_bitarray_temp.length - ( 650 self.word * 32 + self.pos + bitarray_field.len 651 ) 652 wr_bitarray_temp.overwrite(bitarray_field, pos=position) 653 block.wr_bitarray |= wr_bitarray_temp 654 655 def save(self, new_value): 656 bitarray_field = self.convert_to_bitstring(new_value) 657 self.check_new_value(bitarray_field) 658 self.save_to_block(bitarray_field) 659 660 def update(self, bit_array_block): 661 if self.word is None or self.pos is None: 662 self.bitarray.overwrite(self.convert_to_bitstring(self.get()), pos=0) 663 return 664 field_len = self.bitarray.len 665 bit_array_block.pos = bit_array_block.length - ( 666 self.word * 32 + self.pos + field_len 667 ) 668 self.bitarray.overwrite(bit_array_block.read(field_len), pos=0) 669 err_bitarray = self.parent.blocks[self.block].err_bitarray 670 if err_bitarray is not None: 671 err_bitarray.pos = err_bitarray.length - ( 672 self.word * 32 + self.pos + field_len 673 ) 674 self.fail = not err_bitarray.read(field_len).all(False) 675 else: 676 self.fail = self.parent.blocks[self.block].fail 677 self.num_errors = self.parent.blocks[self.block].num_errors 678 679 def get_raw(self, from_read=True): 680 """Return the raw (unformatted) numeric value of the efuse bits 681 682 Returns a simple integer or (for some subclasses) a bitstring. 683 type: int or bool -> int 684 type: bytes -> bytearray 685 """ 686 return self.get_bitstring(from_read).read(self.efuse_type) 687 688 def get(self, from_read=True): 689 """Get a formatted version of the efuse value, suitable for display 690 type: int or bool -> int 691 type: bytes -> string "01 02 03 04 05 06 07 08 ... ". 692 Byte order [0] ... [N]. dump regs: 0x04030201 0x08070605 ... 693 """ 694 if self.efuse_type.startswith("bytes"): 695 return util.hexify(self.get_bitstring(from_read).bytes[::-1], " ") 696 else: 697 return self.get_raw(from_read) 698 699 def get_meaning(self, from_read=True): 700 """Get the meaning of efuse from dict if possible, suitable for display""" 701 if self.dict_value: 702 try: 703 return self.dict_value[self.get_raw(from_read)] 704 except KeyError: 705 pass 706 return self.get(from_read) 707 708 def get_bitstring(self, from_read=True): 709 if from_read: 710 self.bitarray.pos = 0 711 return self.bitarray 712 else: 713 field_len = self.bitarray.len 714 block = self.parent.blocks[self.block] 715 block.wr_bitarray.pos = block.wr_bitarray.length - ( 716 self.word * 32 + self.pos + field_len 717 ) 718 return block.wr_bitarray.read(self.bitarray.len) 719 720 def burn(self, new_value): 721 # Burn a efuse. Added for compatibility reason. 722 self.save(new_value) 723 self.parent.burn_all() 724