def _rawWrite(self, offset, data, base=pr.UInt, stride=4, wordBitSize=32, tryCount=1, posted=False): if not isinstance(base, pr.Model): base = base(wordBitSize) with self._memLock: if posted: txn = rim.Post else: txn = rim.Write for _ in range(tryCount): self._clearError() self._rawTxnChunker(offset, data, base, stride, wordBitSize, txn) self._waitTransaction(0) if self._getError() == "": return elif posted: break self._log.warning("Retrying raw write transaction") # If we get here an error has occurred raise pr.MemoryError(name=self.name, address=offset | self.address, msg=self._getError())
def _rawTxnChunker(self, offset, data, base=pr.UInt, stride=4, wordBitSize=32, txnType=rim.Write, numWords=1): if not isinstance(base, pr.Model): base = base(wordBitSize) if offset + (numWords * stride) > self._size: raise pr.MemoryError(name=self.name, address=offset | self.address, msg='Raw transaction outside of device size') if base.bitSize > stride * 8: raise pr.MemoryError( name=self.name, address=offset | self.address, msg='Called raw memory access with wordBitSize > stride') if txnType == rim.Write or txnType == rim.Post: if isinstance(data, bytearray): ldata = data elif isinstance(data, collections.abc.Iterable): ldata = b''.join( base.toBytes(word).ljust(stride, b'\0') for word in data) else: ldata = base.toBytes(data) else: if data is not None: ldata = data else: ldata = bytearray(numWords * stride) with self._memLock: for i in range(offset, offset + len(ldata), self._reqMaxAccess()): sliceOffset = i | self.offset txnSize = min(self._reqMaxAccess(), len(ldata) - (i - offset)) #print(f'sliceOffset: {sliceOffset:#x}, ldata: {ldata}, txnSize: {txnSize}, buffOffset: {i-offset}') self._reqTransaction(sliceOffset, ldata, txnSize, i - offset, txnType) return ldata
def _rawRead(self, offset, numWords=1, base=pr.UInt, stride=4, wordBitSize=32, data=None, tryCount=1): if not isinstance(base, pr.Model): base = base(wordBitSize) with self._memLock: for _ in range(tryCount): self._clearError() ldata = self._rawTxnChunker(offset, data, base, stride, wordBitSize, txnType=rim.Read, numWords=numWords) self._waitTransaction(0) if self._getError() == "": if numWords == 1: return base.fromBytes(ldata) else: return [ base.fromBytes(ldata[i:i + stride]) for i in range(0, len(ldata), stride) ] self._log.warning("Retrying raw read transaction") # If we get here an error has occurred raise pr.MemoryError(name=self.name, address=offset | self.address, msg=self._getError())
def _buildBlocks(self): remVars = [] # Use min block size, larger blocks can be pre-created blkSize = self._blkMinAccess() # Process all of the variables for k, n in self.nodes.items(): # Local variables have a 1:1 block association if isinstance(n, pr.LocalVariable): self._blocks.append(n._block) # Align to min access, create list of remote variables elif isinstance(n, pr.RemoteVariable) and n.offset is not None: n._updatePath(n.path) n._shiftOffsetDown(n.offset % blkSize, blkSize) remVars += [n] # Sort var list by offset, size remVars.sort(key=lambda x: (x.offset, x.varBytes)) blocks = [] blk = None # Go through sorted variable list, look for overlaps, group into blocks for n in remVars: if blk is not None and ((blk['offset'] + blk['size']) > n.offset): self._log.info( "Overlap detected var offset={} block offset={} block bytes={}" .format(n.offset, blk['offset'], blk['size'])) n._shiftOffsetDown(n.offset - blk['offset'], blkSize) blk['vars'].append(n) if n.varBytes > blk['size']: blk['size'] = n.varBytes # We need a new block for this variable else: blk = None # Look for pre-made block which overlaps for b in self._custBlocks: if ((n.offset >= b.offset) and ((b.offset + b.size) > n.offset)): # Just in case a variable extends past the end of pre-made block, user mistake if n.varBytes > b.size: msg = 'Failed to add variable {n.name} to pre-made block with offset {b.offset} and size {b.size}' raise pr.MemoryError(name=self.path, address=self.address, msg=msg) blk = { 'offset': b.offset, 'size': b.size, 'vars': [n], 'block': b } break # Block not found if blk is None: blk = { 'offset': n.offset, 'size': n.varBytes, 'vars': [n], 'block': None } blocks.append(blk) # Clear pre-made list self._custBlocks = [] # Create new blocks and add new and pre-made blocks to device # Add variables to the block for b in blocks: # Create new block if b['block'] is None: newBlock = rim.Block(b['offset'], b['size']) self._log.debug( "Adding new block at offset {:#02x}, size {}".format( b['offset'], b['size'])) else: newBlock = b['block'] # Set memory slave newBlock._setSlave(self) # Verify the block is not too small or large for the memory interface if newBlock.size > self._reqMaxAccess( ) or newBlock.size < self._reqMinAccess(): msg = f'Block size {newBlock.size} is not in the range: {self._reqMinAccess()} - {self._reqMaxAccess()}' raise pr.MemoryError(name=self.path, address=self.address, msg=msg) # Add variables to the block newBlock.addVariables(b['vars']) # Set varible block links for v in b['vars']: v._block = newBlock # Add to device self._blocks.append(newBlock) newBlock.setEnable(self.enable.value() is True)
def TestMemoryException(arg): raise pr.MemoryError(name='blah', address=0)