def _createWriteTransactionElement(self, addrTableItem, dataList, addrOffset=0, isFifo=False): """Returns a Write Request transaction element (i.e. unmasked/block write) addrTableItem: The relevant address table item you want to perform the write transaction on. dataList: The list of 32-bit numbers you want to write (the list size defines the write depth) addrOffset: The offset on the address specified within the address table item, default is 0. isFifo: False gives a normal write transaction; True gives a non-incrementing write transaction (i.e. same addr many times). """ for value in dataList: if not uInt32Compatible(value): raise ChipsException("Write transaction creation error: cannot create a write transaction with data " \ "values (" + hex(value) +") that are not valid 32-bit unsigned integers!") typeId = IPbusHeader.TYPE_ID_WRITE if isFifo: typeId = IPbusHeader.TYPE_ID_NON_INCR_WRITE writeHeader = IPbusHeader.makeHeader(ChipsBusBase.IPBUS_PROTOCOL_VER, self._getTransactionId(), len(dataList), typeId, IPbusHeader.INFO_CODE_REQUEST) writeBody = [addrTableItem.getAddress() + addrOffset] + dataList return TransactionElement.makeFromHeaderAndBody(writeHeader, writeBody)
def _handleReadRequest(self, request): requestHeader = request.getHeader() words = IPbusHeader.getWords(requestHeader) baseAddr = request.getBody()[0] chipsLog.debug("Read requested on Addr=0x" + uInt32HexStr(baseAddr)) # Response header is the request header but with the Info Code field changed to INFO_CODE_RESPONSE responseHeader = IPbusHeader.updateInfoCode( requestHeader, IPbusHeader.INFO_CODE_RESPONSE) # The (baseAddr & 0xffffffff) forces baseAddr to be in unsigned form (i.e. 0xfffffffc, say, rather than -4) if ( baseAddr & 0xffffffff ) == 0xffffffff: # A read on this register is a Dummy Hardware Reset Request. chipsLog.info( "** Dummy Hardware reset request received! Zeroing all registers. **" ) self._registers.clear() responseBody = [] appendToResponseBody = responseBody.append # This is for a speed optimisation for offset in range(words): currentReg = baseAddr + offset # Create these registers if they don't already exist. if currentReg not in self._registers: self._registers[currentReg] = 0 appendToResponseBody(self._registers[currentReg]) return TransactionElement.makeFromHeaderAndBody( responseHeader, responseBody)
def _createByteOrderTransactionElement(self): """Returns a Byte-Order Request transaction element. Note: Byte-order transactions will always and exclusively have transactionId = 0. """ byteOrderHeader = IPbusHeader.makeHeader(ChipsBusBase.IPBUS_PROTOCOL_VER, 0, 0, IPbusHeader.TYPE_ID_BYTE_ORDER, 0, 0) return TransactionElement.makeFromHeaderAndBody(byteOrderHeader)
def _handleGetReservedAddrInfoRequest(self, request): chipsLog.debug("Reserved Address Info transaction requested") # Response header is the request header but with the Info Code field changed to INFO_CODE_RESPONSE responseHeader = IPbusHeader.updateInfoCode(request.getHeader(), IPbusHeader.INFO_CODE_RESPONSE) responseHeader = IPbusHeader.updateWords(responseHeader, 2) # Returning zeros for the response body, as no real idea what else it should be. return TransactionElement.makeFromHeaderAndBody(responseHeader, [0,0])
def _handleGetReservedAddrInfoRequest(self, request): chipsLog.debug("Reserved Address Info transaction requested") # Response header is the request header but with the Info Code field changed to INFO_CODE_RESPONSE responseHeader = IPbusHeader.updateInfoCode( request.getHeader(), IPbusHeader.INFO_CODE_RESPONSE) responseHeader = IPbusHeader.updateWords(responseHeader, 2) # Returning zeros for the response body, as no real idea what else it should be. return TransactionElement.makeFromHeaderAndBody(responseHeader, [0, 0])
def _createReadTransactionElement(self, addrTableItem, readDepth = 1, addrOffset = 0, isFifo = False): """Returns a Read Request transaction element addrTableItem: The relevant address table item you want to perform the write transaction on. readDepth: The depth of the read; default is 1, which would be a single 32-bit register read. addrOffset: The offset on the address specified within the address table item, default is 0. isFifo: False gives a normal read transaction; True gives a non-incrementing read transaction (i.e. same addr many times). """ typeId = IPbusHeader.TYPE_ID_READ if isFifo: typeId = IPbusHeader.TYPE_ID_NON_INCR_READ readHeader = IPbusHeader.makeHeader(ChipsBusBase.IPBUS_PROTOCOL_VER, self._getTransactionId(), readDepth, typeId, IPbusHeader.INFO_CODE_REQUEST) readBody = [addrTableItem.getAddress() + addrOffset] return TransactionElement.makeFromHeaderAndBody(readHeader, readBody)
def _handleWriteRequest(self, request): requestHeader = request.getHeader() words = IPbusHeader.getWords(requestHeader) requestBody = request.getBody() baseAddr = requestBody[0] chipsLog.debug("Write requested on Addr=0x" + uInt32HexStr(baseAddr)) # Response header is the request header with direction bit changed responseHeader = IPbusHeader.updateDirection(requestHeader, 1) for offset in range(words): currentReg = baseAddr + offset self._registers[currentReg] = requestBody[offset + 1] return TransactionElement.makeFromHeaderAndBody(responseHeader)
def _handleWriteRequest(self, request): requestHeader = request.getHeader() words = IPbusHeader.getWords(requestHeader) requestBody = request.getBody() baseAddr = requestBody[0] chipsLog.debug("Write requested on Addr=0x" + uInt32HexStr(baseAddr)) # Response header is the request header but with the Info Code field changed to INFO_CODE_RESPONSE responseHeader = IPbusHeader.updateInfoCode(requestHeader, IPbusHeader.INFO_CODE_RESPONSE) for offset in range(words): currentReg = baseAddr + offset self._registers[currentReg] = requestBody[offset + 1] return TransactionElement.makeFromHeaderAndBody(responseHeader)
def deserialise(self, packetPayloadString): '''Deserialises a packet payload ASCII string into list of transaction elements''' # 1) Unpack the string into unsigned integers try: rawU32Array = array('I', packetPayloadString) # Unpack string to an unsigned 32-bit array except Exception as err: raise ChipsException("Deserialisation error:\n\t" + str(err)) # 2) Debug output of the raw packet if chipsLog.level <= logging.DEBUG: msg = "\nRaw received packet content is:\n" for u32 in rawU32Array: msg += " 0x" + uInt32HexStr(u32) + "\n" chipsLog.debug(msg) # 3) Detect if we need to do a byte-reorder firstWord = rawU32Array[0] firstWordMasked = firstWord & 0xf00000f0 # This selects only the bits relevant for detecting the byte ordering if firstWordMasked == 0x200000f0: chipsLog.debug("Packet header detected: no byte-reorder is required.") elif firstWordMasked == 0xf0000020: chipsLog.debug("Packet header detected: a byte-reorder will be performed.") self._doByteReorder = True else: chipsLog.warn("Warning: No packet header (or unknown protocol version)! First word = 0x" + uInt32HexStr(firstWord) + ". Will hope for the best!...") # 4) Do the byte-reorder if necessary if self._doByteReorder: rawU32Array.byteswap() # 5) Now deserialise into a list of TransactionElements transactionElementList = [] # The list all the deserialised transaction elements will go into appendToTransactionElementList = transactionElementList.append # This is needed for a speed optimisation iU32 = 1 # Index for moving through the rawU32Array # TEMPORARY IPBUS V2.x HACK! Skip the first word which is now a packet ID rawU32ArraySize = len(rawU32Array) while iU32 < rawU32ArraySize: expectedBodySize = getExpectedBodySize(rawU32Array[iU32]) if rawU32ArraySize - iU32 - 1 - expectedBodySize < 0: raise ChipsException("Deserialisation error: packet not correctly formatted " \ "or does not contain the expected amount of data!") appendToTransactionElementList(TransactionElement(rawU32Array[iU32: iU32 + 1 + expectedBodySize])) iU32 += (1 + expectedBodySize) # 6) Debug output of deserialised packet content if chipsLog.level <= logging.DEBUG: msg = "\nDeserialised packet content is:\n" \ + reprTransactionElementList(transactionElementList) chipsLog.debug(msg) return transactionElementList
def _handleWriteRequest(self, request): requestHeader = request.getHeader() words = IPbusHeader.getWords(requestHeader) requestBody = request.getBody() baseAddr = requestBody[0] chipsLog.debug("Write requested on Addr=0x" + uInt32HexStr(baseAddr)) # Response header is the request header but with the Info Code field changed to INFO_CODE_RESPONSE responseHeader = IPbusHeader.updateInfoCode( requestHeader, IPbusHeader.INFO_CODE_RESPONSE) for offset in range(words): currentReg = baseAddr + offset self._registers[currentReg] = requestBody[offset + 1] return TransactionElement.makeFromHeaderAndBody(responseHeader)
def _handleFifoWriteRequest(self, request): requestHeader = request.getHeader() requestBody = request.getBody() fifoAddr = requestBody[0] chipsLog.debug("FIFO write requested on Addr=0x" + uInt32HexStr(fifoAddr)) # Response header is the request header with direction bit changed responseHeader = IPbusHeader.updateDirection(requestHeader, 1) # Obviously we don't really have a FIFO, we just have a single register at the address of the supposed # FIFO. So, whatever the last value written into the FIFO is, this will be the value this register will # take. We ignore all the previous "writes" to the FIFO. self._registers[fifoAddr] = requestBody[-1] return TransactionElement.makeFromHeaderAndBody(responseHeader)
def _handleReadModifyWriteSumRequest(self, request): requestBody = request.getBody() addr = requestBody[0] addend = requestBody[1] # The value we add to the existing value chipsLog.debug("Read/Modify/Write-sum requested on Addr=0x" + uInt32HexStr(addr)) # Create the register if it doesn't already exist. if addr not in self._registers: self._registers[addr] = 0 updatedValue = (self._registers[addr] + addend) & 0xffffffff self._registers[addr] = updatedValue # Response header is the request header with direction bit changed responseHeader = IPbusHeader.updateDirection(request.getHeader(), 1) return TransactionElement.makeFromHeaderAndBody(responseHeader, [updatedValue])
def _handleReadModifyWriteBitsRequest(self, request): requestBody = request.getBody() addr = requestBody[0] andTerm = requestBody[1] # The and term is the bitwise complement of the register mask (i.e. mask = ~andTerm) orTerm = requestBody[2] chipsLog.debug("Read/Modify/Write-bits requested on Addr=0x" + uInt32HexStr(addr)) # Create the register if it doesn't already exist. if addr not in self._registers: self._registers[addr] = 0 updatedValue = (self._registers[addr] & andTerm) | (orTerm) self._registers[addr] = updatedValue # Response header is the request header with direction bit changed responseHeader = IPbusHeader.updateDirection(request.getHeader(), 1) return TransactionElement.makeFromHeaderAndBody(responseHeader, [updatedValue])
def _handleFifoWriteRequest(self, request): requestHeader = request.getHeader() requestBody = request.getBody() fifoAddr = requestBody[0] chipsLog.debug("FIFO write requested on Addr=0x" + uInt32HexStr(fifoAddr)) # Response header is the request header but with the Info Code field changed to INFO_CODE_RESPONSE responseHeader = IPbusHeader.updateInfoCode( requestHeader, IPbusHeader.INFO_CODE_RESPONSE) # Obviously we don't really have a FIFO, we just have a single register at the address of the supposed # FIFO. So, whatever the last value written into the FIFO is, this will be the value this register will # take. We ignore all the previous "writes" to the FIFO. self._registers[fifoAddr] = requestBody[-1] return TransactionElement.makeFromHeaderAndBody(responseHeader)
def _createRMWBitsTransactionElement(self, addrTableItem, dataU32, addrOffset = 0): """Returns a Read/Modify/Write Bits Request transaction element (i.e. masked write) addrTableItem: The relevant address table item you want to perform the RMWBits transaction on. dataU32: The data (32 bits max, or equal in width to the bit-mask). addrOffset: The offset on the address specified within the address table item, default is 0. """ if not uInt32Compatible(dataU32): raise ChipsException("Read-Modify-Write Bits transaction creation error: cannot create a RMW-bits " \ "transaction with data values (" + hex(dataU32) +") that are not valid 32-bit " \ "unsigned integers!") rmwHeader = IPbusHeader.makeHeader(ChipsBus.IPBUS_PROTOCOL_VER, self._getTransactionId(), 1, IPbusHeader.TYPE_ID_RMW_BITS, IPbusHeader.INFO_CODE_REQUEST) rmwBody = [addrTableItem.getAddress() + addrOffset, \ uInt32BitFlip(addrTableItem.getMask()), \ addrTableItem.shiftDataToMask(dataU32)] return TransactionElement.makeFromHeaderAndBody(rmwHeader, rmwBody)
def _createWriteTransactionElement(self, addrTableItem, dataList, addrOffset = 0, isFifo = False): """Returns a Write Request transaction element (i.e. unmasked/block write) addrTableItem: The relevant address table item you want to perform the write transaction on. dataList: The list of 32-bit numbers you want to write (the list size defines the write depth) addrOffset: The offset on the address specified within the address table item, default is 0. isFifo: False gives a normal write transaction; True gives a non-incrementing write transaction (i.e. same addr many times). """ for value in dataList: if not uInt32Compatible(value): raise ChipsException("Write transaction creation error: cannot create a write transaction with data " \ "values (" + hex(value) +") that are not valid 32-bit unsigned integers!") typeId = IPbusHeader.TYPE_ID_WRITE if isFifo: typeId = IPbusHeader.TYPE_ID_NON_INCR_WRITE writeHeader = IPbusHeader.makeHeader(ChipsBusBase.IPBUS_PROTOCOL_VER, self._getTransactionId(), len(dataList), typeId, IPbusHeader.INFO_CODE_REQUEST) writeBody = [addrTableItem.getAddress() + addrOffset] + dataList return TransactionElement.makeFromHeaderAndBody(writeHeader, writeBody)
def _handleFifoReadRequest(self, request): requestHeader = request.getHeader() words = IPbusHeader.getWords(requestHeader) fifoAddr = request.getBody()[0] chipsLog.debug("FIFO read requested on Addr=0x" + uInt32HexStr(fifoAddr)) # Response header is the request header with direction bit changed responseHeader = IPbusHeader.updateDirection(requestHeader, 1) # Create the register if they don't already exist in our memory space if fifoAddr not in self._registers: self._registers[fifoAddr] = 0 # Obviously we don't really have a FIFO, so we'll just have to return the value stored # at the FIFO's address many times... value = self._registers[fifoAddr] responseBody = [value for iReads in range(words)] return TransactionElement.makeFromHeaderAndBody(responseHeader, responseBody)
def _handleReadModifyWriteSumRequest(self, request): requestBody = request.getBody() addr = requestBody[0] addend = requestBody[1] # The value we add to the existing value chipsLog.debug("Read/Modify/Write-sum requested on Addr=0x" + uInt32HexStr(addr)) # Create the register if it doesn't already exist. if addr not in self._registers: self._registers[addr] = 0 updatedValue = (self._registers[addr] + addend) & 0xffffffff self._registers[addr] = updatedValue # Response header is the request header but with the Info Code field changed to INFO_CODE_RESPONSE responseHeader = IPbusHeader.updateInfoCode( request.getHeader(), IPbusHeader.INFO_CODE_RESPONSE) return TransactionElement.makeFromHeaderAndBody( responseHeader, [updatedValue])
def _handleFifoReadRequest(self, request): requestHeader = request.getHeader() words = IPbusHeader.getWords(requestHeader) fifoAddr = request.getBody()[0] chipsLog.debug("FIFO read requested on Addr=0x" + uInt32HexStr(fifoAddr)) # Response header is the request header but with the Info Code field changed to INFO_CODE_RESPONSE responseHeader = IPbusHeader.updateInfoCode( requestHeader, IPbusHeader.INFO_CODE_RESPONSE) # Create the register if they don't already exist in our memory space if fifoAddr not in self._registers: self._registers[fifoAddr] = 0 # Obviously we don't really have a FIFO, so we'll just have to return the value stored # at the FIFO's address many times... value = self._registers[fifoAddr] responseBody = [value for iReads in range(words)] return TransactionElement.makeFromHeaderAndBody( responseHeader, responseBody)
def _handleReadModifyWriteBitsRequest(self, request): requestBody = request.getBody() addr = requestBody[0] andTerm = requestBody[ 1] # The and term is the bitwise complement of the register mask (i.e. mask = ~andTerm) orTerm = requestBody[2] chipsLog.debug("Read/Modify/Write-bits requested on Addr=0x" + uInt32HexStr(addr)) # Create the register if it doesn't already exist. if addr not in self._registers: self._registers[addr] = 0 updatedValue = (self._registers[addr] & andTerm) | (orTerm) self._registers[addr] = updatedValue # Response header is the request header but with the Info Code field changed to INFO_CODE_RESPONSE responseHeader = IPbusHeader.updateInfoCode( request.getHeader(), IPbusHeader.INFO_CODE_RESPONSE) return TransactionElement.makeFromHeaderAndBody( responseHeader, [updatedValue])
def _handleReadRequest(self, request): requestHeader = request.getHeader() words = IPbusHeader.getWords(requestHeader) baseAddr = request.getBody()[0] chipsLog.debug("Read requested on Addr=0x" + uInt32HexStr(baseAddr)) # Response header is the request header with direction bit changed responseHeader = IPbusHeader.updateDirection(requestHeader, 1) # The (baseAddr & 0xffffffff) forces baseAddr to be in unsigned form (i.e. 0xfffffffc, say, rather than -4) if (baseAddr & 0xffffffff) == 0xffffffff: # A read on this register is a Dummy Hardware Reset Request. chipsLog.info("** Dummy Hardware reset request received! Zeroing all registers. **") self._registers.clear() responseBody = [] appendToResponseBody = responseBody.append # This is for a speed optimisation for offset in range(words): currentReg = baseAddr + offset # Create these registers if they don't already exist. if currentReg not in self._registers: self._registers[currentReg] = 0 appendToResponseBody(self._registers[currentReg]) return TransactionElement.makeFromHeaderAndBody(responseHeader, responseBody)
def _handleByteOrderRequest(self, request): chipsLog.debug("Byte-order transaction requested") # Response header is the request header with direction bit changed responseHeader = IPbusHeader.updateDirection(request.getHeader(), 1) return TransactionElement.makeFromHeaderAndBody(responseHeader)
def _handleGetReservedAddrInfoRequest(self, request): # Response header is the request header with direction bit changed responseHeader = IPbusHeader.updateDirection(request.getHeader(), 1) responseHeader = IPbusHeader.updateWords(responseHeader, 2) # Returning zeros for the response body, as no real idea what else it should be. return TransactionElement.makeFromHeaderAndBody(responseHeader, [0,0])
class SerDes(object): '''Class for serialising/deserialising IPbus transaction data Can serialise a list of TransactionElements into a string, or deserialise a string into a list of TransactionElements. The deserialisation stage checks the byte-ordering by looking for a byte-order header, and deals with the byte-reordering as appropriate. If a byte-reorder was required on the deserialisation stage, then the serialisation stage will also perform a reorder in order to respond correctly. Byte-reordering is off by default, as it's obviously a waste of CPU. ''' def __init__(self): '''Constructor - no arguments''' object.__init__(self) self._doByteReorder = False def serialise(self, transactionElementList): '''Serialises a list of transaction elements into an ASCII string for transmission''' if chipsLog.level <= logging.DEBUG: msg = "\nSerialising the following packet content:\n" msg += reprTransactionElementList(transactionElementList) chipsLog.debug(msg) allTransactionsArray = array( 'I', [0x200000f0] ) # TEMPORARY IPBUS V2.x HACK! Add a packet header of [0x200000f0] to the beginning of each packet. extendFunc = allTransactionsArray.extend for element in transactionElementList: extendFunc(element.getAll()) if self._doByteReorder: allTransactionsArray.byteswap() return allTransactionsArray.tostring() def deserialise(self, packetPayloadString): '''Deserialises a packet payload ASCII string into list of transaction elements''' # 1) Unpack the string into unsigned integers try: rawU32Array = array('I', packetPayloadString ) # Unpack string to an unsigned 32-bit array except Exception, err: raise ChipsException("Deserialisation error:\n\t" + str(err)) # 2) Debug output of the raw packet if chipsLog.level <= logging.DEBUG: msg = "\nRaw received packet content is:\n" for u32 in rawU32Array: msg += " 0x" + uInt32HexStr(u32) + "\n" chipsLog.debug(msg) # 3) Detect if we need to do a byte-reorder firstWord = rawU32Array[0] firstWordMasked = firstWord & 0xf00000f0 # This selects only the bits relevant for detecting the byte ordering if firstWordMasked == 0x200000f0: chipsLog.debug( "Packet header detected: no byte-reorder is required.") elif firstWordMasked == 0xf0000020: chipsLog.debug( "Packet header detected: a byte-reorder will be performed.") self._doByteReorder = True else: chipsLog.warn( "Warning: No packet header (or unknown protocol version)! First word = 0x" + uInt32HexStr(firstWord) + ". Will hope for the best!...") # 4) Do the byte-reorder if necessary if self._doByteReorder: rawU32Array.byteswap() # 5) Now deserialise into a list of TransactionElements transactionElementList = [ ] # The list all the deserialised transaction elements will go into appendToTransactionElementList = transactionElementList.append # This is needed for a speed optimisation iU32 = 1 # Index for moving through the rawU32Array # TEMPORARY IPBUS V2.x HACK! Skip the first word which is now a packet ID rawU32ArraySize = len(rawU32Array) while iU32 < rawU32ArraySize: expectedBodySize = getExpectedBodySize(rawU32Array[iU32]) if rawU32ArraySize - iU32 - 1 - expectedBodySize < 0: raise ChipsException("Deserialisation error: packet not correctly formatted " \ "or does not contain the expected amount of data!") appendToTransactionElementList( TransactionElement(rawU32Array[iU32:iU32 + 1 + expectedBodySize])) iU32 += (1 + expectedBodySize) # 6) Debug output of deserialised packet content if chipsLog.level <= logging.DEBUG: msg = "\nDeserialised packet content is:\n" \ + reprTransactionElementList(transactionElementList) chipsLog.debug(msg) return transactionElementList