Commit 921963cf authored by Michael Büsch's avatar Michael Büsch

Add file ident to instruction state dump

Signed-off-by: Michael Büsch's avatarMichael Buesch <m@bues.ch>
parent b4c576f8
......@@ -158,6 +158,7 @@ class S7CPU(object):
try:
insn = AwlInsnTranslator.fromRawInsn(self, rawInsn)
insn.setIP(ip)
insn.setFileNr(self.__currentAwlFileNr)
except AwlSimError as e:
if e.getRawInsn() is None:
e.setRawInsn(rawInsn)
......@@ -540,18 +541,16 @@ class S7CPU(object):
db = self.__translateDB(rawDB)
self.dbs[dbNumber] = db
self.__currentAwlFileNr += 1
def loadSymbolTable(self, symbolTable):
self.symbolTable.merge(symbolTable)
def reallocate(self, force=False):
if force or (self.specs.nrAccus == 4) != self.is4accu:
self.accu1, self.accu2 = Accu(), Accu()
if self.specs.nrAccus == 2:
self.accu3, self.accu4 = None, None
elif self.specs.nrAccus == 4:
self.accu3, self.accu4 = Accu(), Accu()
else:
assert(0)
self.accu1, self.accu2, self.accu3, self.accu4 =\
Accu(), Accu(), Accu(), Accu()
self.is4accu = (self.specs.nrAccus == 4)
if force or self.specs.nrTimers != len(self.timers):
self.timers = [ Timer(self, i)
for i in range(self.specs.nrTimers) ]
......@@ -567,6 +566,7 @@ class S7CPU(object):
CallStackElem.resetCache()
def reset(self):
self.__currentAwlFileNr = 0
self.dbs = {
# DBs
0 : DB(0, permissions = 0), # read/write-protected system-DB
......@@ -590,6 +590,7 @@ class S7CPU(object):
# System SFBs
}
self.symbolTable = SymbolTable()
self.is4accu = False
self.reallocate(force=True)
self.ar1 = Adressregister()
self.ar2 = Adressregister()
......@@ -647,10 +648,6 @@ class S7CPU(object):
if self.cbScreenUpdate:
self.cbScreenUpdate(self.cbScreenUpdateData)
@property
def is4accu(self):
return self.accu4 is not None
def __runOB(self, block):
# Update timekeeping
self.updateTimestamp()
......
......@@ -430,10 +430,11 @@ class AwlInsn(object):
type2name_english = pivotDict(name2type_english)
def __init__(self, cpu, type, rawInsn):
self.cpu = cpu
self.type = type
self.rawInsn = rawInsn
self.cpu = cpu
self.ip = None
self.fileNr = -1 # AWL file number
self.ip = None # Instruction pointer (IP)
self.ops = [] # Operators
self.params = [] # Parameter assignments (for CALL)
......@@ -461,6 +462,9 @@ class AwlInsn(object):
def setIP(self, newIp):
self.ip = newIp
def setFileNr(self, newFileNr):
self.fileNr = newFileNr
def getCpu(self):
return self.cpu
......
......@@ -355,11 +355,27 @@ class AwlSimClient(object):
# Set instruction state dumping.
# fromLine, toLine is the range of AWL line numbers for which
# dumping is enabled.
# If fromLine=0, dumping is disabled.
def setInsnStateDump(self, fromLine=1, toLine=0x7FFFFFFF, sync=True):
return self.__setOption("insn_state_dump",
"%d-%d" % (fromLine, toLine),
sync = sync)
def setInsnStateDump(self, enable=True,
fileNr=0, fromLine=1, toLine=0x7FFFFFFF,
sync=True):
if not self.transceiver:
return None
msg = AwlSimMessage_INSNSTATE_CONFIG(
flags = 0,
fileNr = fileNr,
fromLine = fromLine,
toLine = toLine)
if enable:
msg.flags |= msg.FLG_CLEAR
else:
msg.flags |= msg.FLG_CLEAR_ONLY
if sync:
msg.flags |= msg.FLG_SYNC
status = self.__sendAndWaitFor_REPLY(msg)
if status != AwlSimMessage_REPLY.STAT_OK:
raise AwlSimError("AwlSimClient: Failed to set insn state dump")
else:
self.transceiver.send(msg)
def getCpuSpecs(self):
if not self.transceiver:
......
......@@ -68,6 +68,7 @@ class AwlSimMessage(object):
MSG_ID_REQ_MEMORY = EnumGen.item
MSG_ID_MEMORY = EnumGen.item
MSG_ID_INSNSTATE = EnumGen.item
MSG_ID_INSNSTATE_CONFIG = EnumGen.item
EnumGen.end
_bytesLenStruct = struct.Struct(str(">I"))
......@@ -536,45 +537,88 @@ class AwlSimMessage_MEMORY(AwlSimMessage):
class AwlSimMessage_INSNSTATE(AwlSimMessage):
# Payload data struct:
# AWL file ident number (32 bit)
# AWL line number (32 bit)
# Serial number. Reset to 0 on cycle exit. (32 bit)
# Flags (16 bit)
# Flags (16 bit) (currently unused. Set to 0)
# CPU status word (16 bit)
# CPU ACCU 1 (32 bit)
# CPU ACCU 2 (32 bit)
# CPU ACCU 3 (32 bit)
# CPU ACCU 4 (32 bit)
# CPU AR 1 (32 bit)
# CPU AR 2 (32 bit)
# CPU DB register (16 bit)
# CPU DI register (16 bit)
plDataStruct = struct.Struct(str(">IIHHIIIIHH"))
plDataStruct = struct.Struct(str(">IIIHHIIIIIIHH"))
def __init__(self, lineNr, serial, flags, stw, accu1, accu2, ar1, ar2, db, di):
def __init__(self, fileNr, lineNr, serial, flags, stw, accu1, accu2, accu3, accu4, ar1, ar2, db, di):
AwlSimMessage.__init__(self, AwlSimMessage.MSG_ID_INSNSTATE)
self.fileNr = fileNr
self.lineNr = lineNr
self.serial = serial
self.flags = flags
self.stw = stw
self.accu1 = accu1
self.accu2 = accu2
self.accu3 = accu3
self.accu4 = accu4
self.ar1 = ar1
self.ar2 = ar2
self.db = db
self.di = di
def toBytes(self):
pl = self.plDataStruct.pack(self.lineNr, self.serial,
pl = self.plDataStruct.pack(
self.fileNr, self.lineNr, self.serial,
self.flags, self.stw, self.accu1, self.accu2,
self.ar1, self.ar2, self.db, self.di)
self.accu3, self.accu4, self.ar1, self.ar2,
self.db, self.di)
return AwlSimMessage.toBytes(self, len(pl)) + pl
@classmethod
def fromBytes(cls, payload):
try:
lineNr, serial, flags, stw, accu1, accu2, ar1, ar2, db, di =\
fileNr, lineNr, serial, flags, stw, accu1, accu2, accu3, accu4, ar1, ar2, db, di =\
cls.plDataStruct.unpack_from(payload, 0)
except (struct.error, IndexError) as e:
raise TransferError("INSNSTATE: Invalid data format")
return cls(lineNr, serial, flags, stw, accu1, accu2, ar1, ar2, db, di)
return cls(fileNr, lineNr, serial, flags, stw, accu1, accu2, accu3, accu4, ar1, ar2, db, di)
class AwlSimMessage_INSNSTATE_CONFIG(AwlSimMessage):
# Payload data struct:
# Flags (32 bit)
# AWL file ident number (32 bit)
# From AWL line (32 bit)
# To AWL line (32 bit)
plDataStruct = struct.Struct(str(">IIII"))
# Flags:
FLG_SYNC = 1 << 0 # Synchronous status reply.
FLG_CLEAR_ONLY = 1 << 1 # Just clear current settings.
FLG_CLEAR = 1 << 2 # Clear, then apply settings.
def __init__(self, flags, fileNr, fromLine, toLine):
AwlSimMessage.__init__(self, AwlSimMessage.MSG_ID_INSNSTATE_CONFIG)
self.flags = flags
self.fileNr = fileNr
self.fromLine = fromLine
self.toLine = toLine
def toBytes(self):
pl = self.plDataStruct.pack(
self.flags, self.fileNr,
self.fromLine, self.toLine)
return AwlSimMessage.toBytes(self, len(pl)) + pl
@classmethod
def fromBytes(cls, payload):
try:
flags, fileNr, fromLine, toLine =\
cls.plDataStruct.unpack_from(payload, 0)
except (struct.error, IndexError) as e:
raise TransferError("INSNSTATE_CONFIG: Invalid data format")
return cls(flags, fileNr, fromLine, toLine)
class AwlSimMessageTransceiver(object):
class RemoteEndDied(Exception): pass
......@@ -598,6 +642,7 @@ class AwlSimMessageTransceiver(object):
AwlSimMessage.MSG_ID_REQ_MEMORY : AwlSimMessage_REQ_MEMORY,
AwlSimMessage.MSG_ID_MEMORY : AwlSimMessage_MEMORY,
AwlSimMessage.MSG_ID_INSNSTATE : AwlSimMessage_INSNSTATE,
AwlSimMessage.MSG_ID_INSNSTATE_CONFIG : AwlSimMessage_INSNSTATE_CONFIG,
}
def __init__(self, sock, peerInfoString):
......
......@@ -70,9 +70,11 @@ class AwlSimServer(object):
# CPU-dump
self.dumpInterval = 0
self.nextDump = 0
# Instruction state dump
self.insnStateDump_fromLine = 0
self.insnStateDump_toLine = 0
# Instruction state dump: Enabled lines.
# dict key: AWL file number.
# dict values: range() of AWL line numbers.
self.insnStateDump_enabledLines = {}
# Memory read requests
self.memReadRequestMsg = None
......@@ -262,20 +264,24 @@ class AwlSimServer(object):
insn = cpu.getCurrentInsn()
if not insn:
return
lineNr, msg = insn.getLineNr(), None
fileNr, lineNr, msg = insn.fileNr, insn.getLineNr(), None
for client in self.clients:
if client.insnStateDump_fromLine == 0 or\
lineNr < client.insnStateDump_fromLine or\
lineNr > client.insnStateDump_toLine:
try:
if lineNr not in client.insnStateDump_enabledLines[fileNr]:
continue
except KeyError:
continue
if not msg:
msg = AwlSimMessage_INSNSTATE(
fileNr & 0xFFFFFFFF,
lineNr & 0xFFFFFFFF,
self.__insnSerial,
0,
cpu.statusWord.getWord(),
cpu.accu1.get(),
cpu.accu2.get(),
cpu.accu3.get(),
cpu.accu4.get(),
cpu.ar1.get(),
cpu.ar2.get(),
cpu.dbRegister.index & 0xFFFF,
......@@ -293,13 +299,13 @@ class AwlSimServer(object):
self.sim.cpu.setBlockExitCallback(None)
def __updateCpuPostInsnCallback(self):
if any(c.insnStateDump_fromLine != 0 for c in self.clients):
if any(c.insnStateDump_enabledLines for c in self.clients):
self.sim.cpu.setPostInsnCallback(self.__cpuPostInsnCallback, None)
else:
self.sim.cpu.setPostInsnCallback(None)
def __updateCpuCycleExitCallback(self):
if any(c.insnStateDump_fromLine != 0 for c in self.clients):
if any(c.insnStateDump_enabledLines for c in self.clients):
self.sim.cpu.setCycleExitCallback(self.__cpuCycleExitCallback, None)
else:
self.sim.cpu.setCycleExitCallback(None)
......@@ -378,19 +384,6 @@ class AwlSimServer(object):
self.__updateCpuBlockExitCallback()
elif msg.name == "cycle_time_limit":
self.sim.cpu.setCycleTimeLimit(msg.getFloatValue())
elif msg.name == "insn_state_dump":
val = msg.getStrValue().split("-")
try:
if len(val) != 2:
raise ValueError
fromLine = int(val[0])
toLine = int(val[1])
except ValueError as e:
raise AwlSimError("insn_state_dump: invalid value")
client.insnStateDump_fromLine = fromLine
client.insnStateDump_toLine = toLine
self.__updateCpuPostInsnCallback()
self.__updateCpuCycleExitCallback()
else:
status = AwlSimMessage_REPLY.STAT_FAIL
......@@ -432,6 +425,18 @@ class AwlSimServer(object):
if msg.flags & msg.FLG_SYNC:
client.transceiver.send(AwlSimMessage_REPLY.make(msg, status))
def __rx_INSNSTATE_CONFIG(self, client, msg):
status = AwlSimMessage_REPLY.STAT_OK
if msg.flags & (msg.FLG_CLEAR | msg.FLG_CLEAR_ONLY):
client.insnStateDump_enabledLines = {}
if not (msg.flags & msg.FLG_CLEAR_ONLY):
rnge = range(msg.fromLine, msg.toLine + 1)
client.insnStateDump_enabledLines[msg.fileNr] = rnge
self.__updateCpuPostInsnCallback()
self.__updateCpuCycleExitCallback()
if msg.flags & msg.FLG_SYNC:
client.transceiver.send(AwlSimMessage_REPLY.make(msg, status))
__msgRxHandlers = {
AwlSimMessage.MSG_ID_PING : __rx_PING,
AwlSimMessage.MSG_ID_PONG : __rx_PONG,
......@@ -446,6 +451,7 @@ class AwlSimServer(object):
AwlSimMessage.MSG_ID_CPUSPECS : __rx_CPUSPECS,
AwlSimMessage.MSG_ID_REQ_MEMORY : __rx_REQ_MEMORY,
AwlSimMessage.MSG_ID_MEMORY : __rx_MEMORY,
AwlSimMessage.MSG_ID_INSNSTATE_CONFIG : __rx_INSNSTATE_CONFIG,
}
def __handleClientComm(self, client):
......
......@@ -309,11 +309,13 @@ class CpuWidget(QWidget):
onlineDiagEn = self.onlineViewCheckBox.checkState() == Qt.Checked
try:
client = self.mainWidget.getSimClient()
#TODO also send source identity to client
if onlineDiagEn and source:
client.setInsnStateDump(fromLine, toLine, sync=False)
client.setInsnStateDump(enable=True,
fileNr=0,#TODO
fromLine=fromLine, toLine=toLine,
sync=False)
else:
client.setInsnStateDump(0, 0, sync=False)
client.setInsnStateDump(enable=False, sync=False)
except AwlSimError as e:
MessageBox.handleAwlSimError(self,
"Failed to setup instruction dumping", e)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment