cpu.py 85 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376
  1. # -*- coding: utf-8 -*-
  2. #
  3. # AWL simulator - CPU
  4. #
  5. # Copyright 2012-2017 Michael Buesch <m@bues.ch>
  6. #
  7. # This program is free software; you can redistribute it and/or modify
  8. # it under the terms of the GNU General Public License as published by
  9. # the Free Software Foundation; either version 2 of the License, or
  10. # (at your option) any later version.
  11. #
  12. # This program is distributed in the hope that it will be useful,
  13. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. # GNU General Public License for more details.
  16. #
  17. # You should have received a copy of the GNU General Public License along
  18. # with this program; if not, write to the Free Software Foundation, Inc.,
  19. # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  20. #
  21. from __future__ import division, absolute_import, print_function, unicode_literals
  22. from awlsim.common.compat import *
  23. import time
  24. import datetime
  25. import random
  26. from awlsim.common.util import *
  27. from awlsim.common.cpuspecs import * #+cimport
  28. from awlsim.common.cpuconfig import *
  29. from awlsim.common.blockinfo import *
  30. from awlsim.common.datatypehelpers import * #+cimport
  31. from awlsim.common.exceptions import *
  32. from awlsim.common.env import *
  33. from awlsim.common.version import *
  34. from awlsim.library.libentry import *
  35. from awlsim.core.symbolparser import *
  36. from awlsim.core.memory import * #+cimport
  37. from awlsim.core.instructions.all_insns import * #+cimport
  38. from awlsim.core.systemblocks.tables import *
  39. from awlsim.core.operatortypes import * #+cimport
  40. from awlsim.core.operators import * #+cimport
  41. from awlsim.core.blocks import * #+cimport
  42. from awlsim.core.datablocks import * #+cimport
  43. from awlsim.core.userdefinedtypes import * #+cimport
  44. from awlsim.core.statusword import * #+cimport
  45. from awlsim.core.labels import *
  46. from awlsim.core.timers import * #+cimport
  47. from awlsim.core.counters import * #+cimport
  48. from awlsim.core.callstack import * #+cimport
  49. from awlsim.core.lstack import * #+cimport
  50. from awlsim.core.offset import * #+cimport
  51. from awlsim.core.obtemp import *
  52. from awlsim.core.util import *
  53. from awlsim.awlcompiler.translator import *
  54. class ParenStackElem(object): #+cdef
  55. "Parenthesis stack element"
  56. def __init__(self, cpu, insnType, statusWord): #@nocy
  57. #@cy def __cinit__(self, S7CPU cpu, uint32_t insnType, S7StatusWord statusWord):
  58. self.cpu = cpu
  59. self.insnType = insnType
  60. self.NER = statusWord.NER
  61. self.VKE = statusWord.VKE
  62. self.OR = statusWord.OR
  63. def __repr__(self):
  64. mnemonics = self.cpu.getMnemonics()
  65. type2name = {
  66. S7CPUConfig.MNEMONICS_EN : AwlInsn.type2name_english,
  67. S7CPUConfig.MNEMONICS_DE : AwlInsn.type2name_german,
  68. }[mnemonics]
  69. return '(insn="%s" VKE=%s OR=%d)' %\
  70. (type2name[self.insnType],
  71. self.VKE, self.OR)
  72. class S7Prog(object):
  73. "S7 CPU program management"
  74. def __init__(self, cpu):
  75. self.cpu = cpu
  76. self.pendingRawDBs = []
  77. self.pendingRawFBs = []
  78. self.pendingRawFCs = []
  79. self.pendingRawOBs = []
  80. self.pendingRawUDTs = []
  81. self.pendingLibSelections = []
  82. self.symbolTable = SymbolTable()
  83. self.reset()
  84. def reset(self):
  85. for rawBlock in itertools.chain(self.pendingRawDBs,
  86. self.pendingRawFBs,
  87. self.pendingRawFCs,
  88. self.pendingRawOBs,
  89. self.pendingRawUDTs):
  90. rawBlock.destroySourceRef()
  91. self.pendingRawDBs = []
  92. self.pendingRawFBs = []
  93. self.pendingRawFCs = []
  94. self.pendingRawOBs = []
  95. self.pendingRawUDTs = []
  96. self.pendingLibSelections = []
  97. self.symbolTable.clear()
  98. def addRawDB(self, rawDB):
  99. assert(isinstance(rawDB, RawAwlDB))
  100. self.pendingRawDBs.append(rawDB)
  101. def addRawFB(self, rawFB):
  102. assert(isinstance(rawFB, RawAwlFB))
  103. self.pendingRawFBs.append(rawFB)
  104. def addRawFC(self, rawFC):
  105. assert(isinstance(rawFC, RawAwlFC))
  106. self.pendingRawFCs.append(rawFC)
  107. def addRawOB(self, rawOB):
  108. assert(isinstance(rawOB, RawAwlOB))
  109. self.pendingRawOBs.append(rawOB)
  110. def addRawUDT(self, rawUDT):
  111. assert(isinstance(rawUDT, RawAwlUDT))
  112. self.pendingRawUDTs.append(rawUDT)
  113. def addLibrarySelection(self, libSelection):
  114. assert(isinstance(libSelection, AwlLibEntrySelection))
  115. self.pendingLibSelections.append(libSelection)
  116. def loadSymbolTable(self, symbolTable):
  117. self.symbolTable.merge(symbolTable)
  118. def __detectMnemonics(self):
  119. conf = self.cpu.getConf()
  120. if conf.getConfiguredMnemonics() != S7CPUConfig.MNEMONICS_AUTO:
  121. return
  122. detected = None
  123. errorCounts = {}
  124. rawBlocks = list(itertools.chain(self.pendingRawOBs,
  125. self.pendingRawFBs,
  126. self.pendingRawFCs))
  127. if not rawBlocks:
  128. if conf.getMnemonics() != S7CPUConfig.MNEMONICS_AUTO:
  129. # It was already set. We are Ok.
  130. return
  131. # There are no blocks and we didn't detect anything, yet.
  132. # Just set it to EN.
  133. detected = S7CPUConfig.MNEMONICS_EN
  134. if detected is None:
  135. for mnemonics in (S7CPUConfig.MNEMONICS_EN,
  136. S7CPUConfig.MNEMONICS_DE):
  137. errorCount = 0
  138. for rawBlock in rawBlocks:
  139. for rawInsn in rawBlock.insns:
  140. ret = AwlInsnTranslator.name2type(rawInsn.getName(),
  141. mnemonics)
  142. if ret is None:
  143. errorCount += 1
  144. try:
  145. optrans = AwlOpTranslator(mnemonics=mnemonics)
  146. optrans.translateFromRawInsn(rawInsn)
  147. except AwlSimError:
  148. errorCount += 1
  149. if errorCount == 0:
  150. # No error. Use these mnemonics.
  151. detected = mnemonics
  152. break
  153. errorCounts[mnemonics] = errorCount
  154. if detected is None:
  155. # Select the mnemonics with the lower error count.
  156. if errorCounts[S7CPUConfig.MNEMONICS_EN] <= errorCounts[S7CPUConfig.MNEMONICS_DE]:
  157. detected = S7CPUConfig.MNEMONICS_EN
  158. else:
  159. detected = S7CPUConfig.MNEMONICS_DE
  160. if conf.getMnemonics() not in {S7CPUConfig.MNEMONICS_AUTO, detected}:
  161. # Autodetected mnemonics were already set before
  162. # to something different.
  163. raise AwlSimError("Cannot mix multiple AWL files with "\
  164. "distinct mnemonics. This error may be caused by "\
  165. "incorrect autodetection. "\
  166. "Force mnemonics to EN or DE to avoid this error.")
  167. conf.setDetectedMnemonics(detected)
  168. def __loadLibraries(self):
  169. for libSelection in self.pendingLibSelections:
  170. # Get the block class from the library.
  171. libEntryCls = AwlLib.getEntryBySelection(libSelection)
  172. assert(not libEntryCls._isSystemBlock)
  173. # Get the effective block index.
  174. effIndex = libSelection.getEffectiveEntryIndex()
  175. if effIndex < 0:
  176. effIndex = libSelection.getEntryIndex()
  177. # Create and translate the block
  178. translator = AwlTranslator(self.cpu)
  179. if libEntryCls._isFC:
  180. block = libEntryCls(index = effIndex)
  181. if block.index in self.cpu.fcs and\
  182. not self.cpu.fcs[block.index].isLibraryBlock:
  183. raise AwlSimError("Error while loading library "
  184. "block FC %d: Block FC %d is already "
  185. "loaded as user defined block." %\
  186. (block.index, block.index))
  187. block = translator.translateLibraryCodeBlock(block)
  188. self.cpu.fcs[block.index] = block
  189. elif libEntryCls._isFB:
  190. block = libEntryCls(index = effIndex)
  191. if block.index in self.cpu.fbs and\
  192. not self.cpu.fbs[block.index].isLibraryBlock:
  193. raise AwlSimError("Error while loading library "
  194. "block FB %d: Block FB %d is already "
  195. "loaded as user defined block." %\
  196. (block.index, block.index))
  197. block = translator.translateLibraryCodeBlock(block)
  198. self.cpu.fbs[block.index] = block
  199. else:
  200. assert(0)
  201. self.pendingLibSelections = []
  202. def __checkCallParamTypeCompat(self, block):
  203. for insn, calledCodeBlock, calledDataBlock in self.cpu.allCallInsns(block):
  204. try:
  205. for param in insn.params:
  206. # Get the interface field for this variable
  207. field = calledCodeBlock.interface.getFieldByName(param.lvalueName)
  208. # Check type compatibility
  209. param.rvalueOp.checkDataTypeCompat(self.cpu, field.dataType)
  210. except AwlSimError as e:
  211. e.setInsn(insn)
  212. raise e
  213. # Assign call parameter interface reference.
  214. def __assignParamInterface(self, block):
  215. for insn, calledCodeBlock, calledDataBlock in self.cpu.allCallInsns(block):
  216. try:
  217. for param in insn.params:
  218. # Add interface references to the parameter assignment.
  219. param.setInterface(calledCodeBlock.interface)
  220. except AwlSimError as e:
  221. e.setInsn(insn)
  222. raise e
  223. # Resolve all symbols (global and local) on all blocks, as far as possible.
  224. def __resolveSymbols(self):
  225. resolver = AwlSymResolver(self.cpu)
  226. for block in self.cpu.allCodeBlocks():
  227. # Add interface references to the parameter assignment.
  228. self.__assignParamInterface(block)
  229. # Check type compatibility between formal and
  230. # actual parameter of calls.
  231. self.__checkCallParamTypeCompat(block)
  232. # Resolve all symbols
  233. resolver.resolveSymbols_block(block)
  234. # Check type compatibility between formal and
  235. # actual parameter of calls again, with resolved symbols.
  236. self.__checkCallParamTypeCompat(block)
  237. def __finalizeCodeBlock(self, block):
  238. translator = AwlTranslator(self.cpu)
  239. # Finalize call instructions
  240. for insn, calledCodeBlock, calledDataBlock in self.cpu.allCallInsns(block):
  241. try:
  242. for param in insn.params:
  243. # Final translation of parameter assignment operand.
  244. translator.translateParamAssignOper(param)
  245. except AwlSimError as e:
  246. e.setInsn(insn)
  247. raise e
  248. # Run the final setup of all instructions.
  249. for insn in block.insns:
  250. insn.finalSetup()
  251. # Check and account for direct L stack allocations and
  252. # interface L stack allocations.
  253. block.accountTempAllocations()
  254. def __finalizeCodeBlocks(self):
  255. for block in self.cpu.allUserCodeBlocks():
  256. self.__finalizeCodeBlock(block)
  257. # Run static error checks for code block
  258. def __staticSanityChecks_block(self, block):
  259. for insn in block.insns:
  260. insn.staticSanityChecks()
  261. # Run static error checks
  262. def staticSanityChecks(self):
  263. # The main cycle expects OB 1 to be present.
  264. if 1 not in self.cpu.obs:
  265. raise AwlSimError("OB 1 is not present in the CPU.")
  266. # Run the user code checks.
  267. for block in self.cpu.allUserCodeBlocks():
  268. self.__staticSanityChecks_block(block)
  269. def build(self):
  270. """Translate the loaded sources into their executable forms.
  271. """
  272. from awlsim.core.datatypes import AwlDataType
  273. translator = AwlTranslator(self.cpu)
  274. resolver = AwlSymResolver(self.cpu)
  275. self.__loadLibraries()
  276. # Mnemonics autodetection
  277. self.__detectMnemonics()
  278. # Translate UDTs
  279. udts = {}
  280. for rawUDT in self.pendingRawUDTs:
  281. udtNumber, sym = resolver.resolveBlockName({AwlDataType.TYPE_UDT_X},
  282. rawUDT.index)
  283. if udtNumber in udts:
  284. raise AwlSimError("Multiple definitions of "\
  285. "UDT %d." % udtNumber)
  286. rawUDT.index = udtNumber
  287. udt = UDT.makeFromRaw(rawUDT)
  288. if udtNumber in self.cpu.udts:
  289. self.cpu.udts[udtNumber].destroySourceRef()
  290. udts[udtNumber] = udt
  291. self.cpu.udts[udtNumber] = udt
  292. self.pendingRawUDTs = []
  293. # Build all UDTs (Resolve sizes of all fields)
  294. for udt in dictValues(udts):
  295. udt.buildDataStructure(self.cpu)
  296. # Translate OBs
  297. obs = {}
  298. for rawOB in self.pendingRawOBs:
  299. obNumber, sym = resolver.resolveBlockName({AwlDataType.TYPE_OB_X},
  300. rawOB.index)
  301. if obNumber in obs:
  302. raise AwlSimError("Multiple definitions of "\
  303. "OB %d." % obNumber)
  304. rawOB.index = obNumber
  305. ob = translator.translateCodeBlock(rawOB, OB)
  306. if obNumber in self.cpu.obs:
  307. self.cpu.obs[obNumber].destroySourceRef()
  308. obs[obNumber] = ob
  309. self.cpu.obs[obNumber] = ob
  310. # Create the TEMP-preset handler table
  311. try:
  312. presetHandlerClass = OBTempPresets_table[obNumber]
  313. except KeyError:
  314. presetHandlerClass = OBTempPresets_dummy
  315. self.cpu.obTempPresetHandlers[obNumber] = presetHandlerClass(self.cpu)
  316. self.pendingRawOBs = []
  317. # Translate FBs
  318. fbs = {}
  319. for rawFB in self.pendingRawFBs:
  320. fbNumber, sym = resolver.resolveBlockName({AwlDataType.TYPE_FB_X},
  321. rawFB.index)
  322. if fbNumber in fbs:
  323. raise AwlSimError("Multiple definitions of "\
  324. "FB %d." % fbNumber)
  325. if fbNumber in self.cpu.fbs and\
  326. self.cpu.fbs[fbNumber].isLibraryBlock:
  327. raise AwlSimError("Multiple definitions of FB %d.\n"
  328. "FB %d is already defined by an "
  329. "imported library block (%s)." % (
  330. fbNumber, fbNumber,
  331. self.cpu.fbs[fbNumber].libraryName))
  332. rawFB.index = fbNumber
  333. fb = translator.translateCodeBlock(rawFB, FB)
  334. if fbNumber in self.cpu.fbs:
  335. self.cpu.fbs[fbNumber].destroySourceRef()
  336. fbs[fbNumber] = fb
  337. self.cpu.fbs[fbNumber] = fb
  338. self.pendingRawFBs = []
  339. # Translate FCs
  340. fcs = {}
  341. for rawFC in self.pendingRawFCs:
  342. fcNumber, sym = resolver.resolveBlockName({AwlDataType.TYPE_FC_X},
  343. rawFC.index)
  344. if fcNumber in fcs:
  345. raise AwlSimError("Multiple definitions of "\
  346. "FC %d." % fcNumber)
  347. if fcNumber in self.cpu.fcs and\
  348. self.cpu.fcs[fcNumber].isLibraryBlock:
  349. raise AwlSimError("Multiple definitions of FC %d.\n"
  350. "FC %d is already defined by an "
  351. "imported library block (%s)." % (
  352. fcNumber, fcNumber,
  353. self.cpu.fcs[fcNumber].libraryName))
  354. rawFC.index = fcNumber
  355. fc = translator.translateCodeBlock(rawFC, FC)
  356. if fcNumber in self.cpu.fcs:
  357. self.cpu.fcs[fcNumber].destroySourceRef()
  358. fcs[fcNumber] = fc
  359. self.cpu.fcs[fcNumber] = fc
  360. self.pendingRawFCs = []
  361. if not self.cpu.sfbs:
  362. # Create the SFB tables
  363. for sfbNumber in dictKeys(SFB_table):
  364. if sfbNumber < 0 and not self.cpu.extendedInsnsEnabled():
  365. continue
  366. sfb = SFB_table[sfbNumber](self.cpu)
  367. self.cpu.sfbs[sfbNumber] = sfb
  368. if not self.cpu.sfcs:
  369. # Create the SFC tables
  370. for sfcNumber in dictKeys(SFC_table):
  371. if sfcNumber < 0 and not self.cpu.extendedInsnsEnabled():
  372. continue
  373. sfc = SFC_table[sfcNumber](self.cpu)
  374. self.cpu.sfcs[sfcNumber] = sfc
  375. # Build the data structures of code blocks.
  376. for block in self.cpu.allCodeBlocks():
  377. block.interface.buildDataStructure(self.cpu)
  378. # Translate DBs
  379. dbs = {}
  380. for rawDB in self.pendingRawDBs:
  381. dbNumber, sym = resolver.resolveBlockName({AwlDataType.TYPE_DB_X,
  382. AwlDataType.TYPE_FB_X,
  383. AwlDataType.TYPE_SFB_X},
  384. rawDB.index)
  385. if dbNumber in dbs:
  386. raise AwlSimError("Multiple definitions of "\
  387. "DB %d." % dbNumber)
  388. rawDB.index = dbNumber
  389. db = translator.translateDB(rawDB)
  390. if dbNumber in self.cpu.dbs:
  391. self.cpu.dbs[dbNumber].destroySourceRef()
  392. dbs[dbNumber] = db
  393. self.cpu.dbs[dbNumber] = db
  394. self.pendingRawDBs = []
  395. # Resolve symbolic instructions and operators
  396. self.__resolveSymbols()
  397. # Do some finalizations
  398. self.__finalizeCodeBlocks()
  399. # Run some static sanity checks on the code
  400. self.staticSanityChecks()
  401. def getBlockInfos(self, getOBInfo = False, getFCInfo = False,
  402. getFBInfo = False, getDBInfo = False):
  403. """Returns a list of BlockInfo()."""
  404. blkInfos = []
  405. for block in itertools.chain(
  406. sorted(dictValues(self.cpu.obs) if getOBInfo else [],
  407. key = lambda blk: blk.index),
  408. sorted(dictValues(self.cpu.fcs) if getFCInfo else [],
  409. key = lambda blk: blk.index),
  410. sorted(dictValues(self.cpu.fbs) if getFBInfo else [],
  411. key = lambda blk: blk.index),
  412. sorted(dictValues(self.cpu.dbs) if getDBInfo else [],
  413. key = lambda blk: blk.index)):
  414. blkInfo = block.getBlockInfo()
  415. assert(blkInfo)
  416. blkInfos.append(blkInfo)
  417. return blkInfos
  418. def removeBlock(self, blockInfo, sanityChecks = True):
  419. """Remove a block from the CPU.
  420. """
  421. try:
  422. if blockInfo.blockType == BlockInfo.TYPE_OB:
  423. block = self.cpu.obs.pop(blockInfo.blockIndex)
  424. self.cpu.obTempPresetHandlers.pop(blockInfo.blockIndex)
  425. elif blockInfo.blockType == BlockInfo.TYPE_FC:
  426. block = self.cpu.fcs.pop(blockInfo.blockIndex)
  427. elif blockInfo.blockType == BlockInfo.TYPE_FB:
  428. block = self.cpu.fbs.pop(blockInfo.blockIndex)
  429. elif blockInfo.blockType == BlockInfo.TYPE_DB:
  430. block = self.cpu.dbs[blockInfo.blockIndex]
  431. if (block.permissions & DB.PERM_WRITE) == 0:
  432. raise AwlSimError("Remove block: Cannot delete "
  433. "write protected %s." % \
  434. blockInfo.blockName)
  435. block = self.cpu.dbs.pop(blockInfo.blockIndex)
  436. else:
  437. raise AwlSimError("Remove block: Unknown bock type %d." % \
  438. blockInfo.blockType)
  439. block.destroySourceRef()
  440. except KeyError as e:
  441. raise AwlSimError("Remove block: Block %s not found." % \
  442. blockInfo.blockName)
  443. if sanityChecks:
  444. # Re-run sanity checks to detect missing blocks.
  445. self.staticSanityChecks()
  446. class S7CPU(object): #+cdef
  447. "STEP 7 CPU"
  448. def __init__(self):
  449. from awlsim.core.datatypes import AwlDataType
  450. self.__setAffinity()
  451. self.__fetchTypeMethods = self.__fetchTypeMethodsDict #@nocy
  452. self.__storeTypeMethods = self.__storeTypeMethodsDict #@nocy
  453. self.__callHelpers = self.__callHelpersDict #@nocy
  454. self.__rawCallHelpers = self.__rawCallHelpersDict #@nocy
  455. self.__clockMemByteOffset = None
  456. self.specs = S7CPUSpecs(self)
  457. self.conf = S7CPUConfig(self)
  458. self.prog = S7Prog(self)
  459. self.setCycleTimeLimit(5.0)
  460. self.setMaxCallStackDepth(256)
  461. self.setCycleExitCallback(None)
  462. self.setBlockExitCallback(None)
  463. self.setPostInsnCallback(None)
  464. self.setPeripheralReadCallback(None)
  465. self.setPeripheralWriteCallback(None)
  466. self.setScreenUpdateCallback(None)
  467. self.udts = {}
  468. self.dbs = {}
  469. self.obs = {}
  470. self.fcs = {}
  471. self.fbs = {}
  472. self.activeLStack = None
  473. self.reset()
  474. self.enableExtendedInsns(False)
  475. self.enableObTempPresets(False)
  476. self.__dateAndTimeWeekdayMap = AwlDataType.dateAndTimeWeekdayMap
  477. def __setAffinity(self):
  478. """Set the host CPU affinity that what is set via AWLSIM_AFFINITY
  479. environment variable.
  480. """
  481. affinity = AwlSimEnv.getAffinity()
  482. if affinity:
  483. if hasattr(os, "sched_setaffinity"):
  484. try:
  485. os.sched_setaffinity(0, affinity)
  486. except (OSError, ValueError) as e:
  487. raise AwlSimError("Failed to set host CPU "
  488. "affinity to %s: %s" % (
  489. affinity, str(e)))
  490. else:
  491. printError("Cannot set CPU affinity "
  492. "on this version of Python. "
  493. "os.sched_setaffinity is not available.")
  494. def getMnemonics(self):
  495. return self.conf.getMnemonics()
  496. def enableObTempPresets(self, en=True):
  497. self.__obTempPresetsEnabled = bool(en)
  498. def obTempPresetsEnabled(self):
  499. return self.__obTempPresetsEnabled
  500. def enableExtendedInsns(self, en=True):
  501. self.__extendedInsnsEnabled = bool(en)
  502. def extendedInsnsEnabled(self):
  503. return self.__extendedInsnsEnabled
  504. def setCycleTimeLimit(self, newLimit):
  505. self.cycleTimeLimit = float(newLimit)
  506. def setRunTimeLimit(self, timeoutSeconds=-1.0):
  507. self.__runtimeLimit = timeoutSeconds if timeoutSeconds >= 0.0 else -1.0
  508. def setMaxCallStackDepth(self, newMaxDepth):
  509. self.maxCallStackDepth = min(max(int(newMaxDepth), 1), 0xFFFFFFFF)
  510. # Returns all user defined code blocks (OBs, FBs, FCs)
  511. def allUserCodeBlocks(self):
  512. for block in itertools.chain(dictValues(self.obs),
  513. dictValues(self.fbs),
  514. dictValues(self.fcs)):
  515. yield block
  516. # Returns all system code blocks (SFBs, SFCs)
  517. def allSystemCodeBlocks(self):
  518. for block in itertools.chain(dictValues(self.sfbs),
  519. dictValues(self.sfcs)):
  520. yield block
  521. # Returns all user defined code blocks (OBs, FBs, FCs, SFBs, SFCs)
  522. def allCodeBlocks(self):
  523. for block in itertools.chain(self.allUserCodeBlocks(),
  524. self.allSystemCodeBlocks()):
  525. yield block
  526. def allCallInsns(self, block):
  527. from awlsim.core.datatypes import AwlDataType
  528. resolver = AwlSymResolver(self)
  529. for insn in block.insns:
  530. if insn.insnType != AwlInsn.TYPE_CALL:
  531. continue
  532. # Get the DB block, if any.
  533. if len(insn.ops) == 1:
  534. dataBlock = None
  535. elif len(insn.ops) == 2:
  536. dataBlockOp = insn.ops[1]
  537. if dataBlockOp.operType == AwlOperatorTypes.SYMBOLIC:
  538. blockIndex, symbol = resolver.resolveBlockName(
  539. {AwlDataType.TYPE_FB_X,
  540. AwlDataType.TYPE_SFB_X},
  541. dataBlockOp.offset.identChain.getString())
  542. dataBlockOp = symbol.operator.dup()
  543. dataBlockIndex = dataBlockOp.offset.byteOffset
  544. try:
  545. if dataBlockOp.operType == AwlOperatorTypes.BLKREF_DB:
  546. dataBlock = self.dbs[dataBlockIndex]
  547. else:
  548. raise AwlSimError("Data block operand "
  549. "in CALL is not a DB.",
  550. insn=insn)
  551. except KeyError as e:
  552. raise AwlSimError("Data block '%s' referenced "
  553. "in CALL does not exist." %\
  554. str(dataBlockOp),
  555. insn=insn)
  556. # Get the code block, if any.
  557. codeBlockOp = insn.ops[0]
  558. if codeBlockOp.operType == AwlOperatorTypes.SYMBOLIC:
  559. blockIndex, symbol = resolver.resolveBlockName(
  560. {AwlDataType.TYPE_FC_X,
  561. AwlDataType.TYPE_FB_X,
  562. AwlDataType.TYPE_SFC_X,
  563. AwlDataType.TYPE_SFB_X},
  564. codeBlockOp.offset.identChain.getString())
  565. codeBlockOp = symbol.operator.dup()
  566. elif codeBlockOp.operType == AwlOperatorTypes.NAMED_LOCAL:
  567. codeBlockOp = resolver.resolveNamedLocal(block, insn, codeBlockOp)
  568. if codeBlockOp.operType in {AwlOperatorTypes.MULTI_FB,
  569. AwlOperatorTypes.MULTI_SFB}:
  570. codeBlockIndex = codeBlockOp.offset.fbNumber
  571. else:
  572. codeBlockIndex = codeBlockOp.offset.byteOffset
  573. try:
  574. if codeBlockOp.operType == AwlOperatorTypes.BLKREF_FC:
  575. codeBlock = self.fcs[codeBlockIndex]
  576. elif codeBlockOp.operType in {AwlOperatorTypes.BLKREF_FB,
  577. AwlOperatorTypes.MULTI_FB}:
  578. codeBlock = self.fbs[codeBlockIndex]
  579. elif codeBlockOp.operType == AwlOperatorTypes.BLKREF_SFC:
  580. codeBlock = self.sfcs[codeBlockIndex]
  581. elif codeBlockOp.operType in {AwlOperatorTypes.BLKREF_SFB,
  582. AwlOperatorTypes.MULTI_SFB}:
  583. codeBlock = self.sfbs[codeBlockIndex]
  584. else:
  585. raise AwlSimError("Code block operand "
  586. "in CALL is not a valid code block "
  587. "(FB, FC, SFB or SFC).",
  588. insn=insn)
  589. except KeyError as e:
  590. raise AwlSimError("Code block '%s' referenced in "
  591. "CALL does not exist." %\
  592. str(codeBlockOp),
  593. insn=insn)
  594. yield insn, codeBlock, dataBlock
  595. def build(self):
  596. """Translate the loaded sources into their executable forms.
  597. """
  598. self.prog.build()
  599. self.reallocate(force=True)
  600. def load(self, parseTree, rebuild = False, sourceManager = None):
  601. for rawDB in dictValues(parseTree.dbs):
  602. rawDB.setSourceRef(sourceManager)
  603. self.prog.addRawDB(rawDB)
  604. for rawFB in dictValues(parseTree.fbs):
  605. rawFB.setSourceRef(sourceManager)
  606. self.prog.addRawFB(rawFB)
  607. for rawFC in dictValues(parseTree.fcs):
  608. rawFC.setSourceRef(sourceManager)
  609. self.prog.addRawFC(rawFC)
  610. for rawOB in dictValues(parseTree.obs):
  611. rawOB.setSourceRef(sourceManager)
  612. self.prog.addRawOB(rawOB)
  613. for rawUDT in dictValues(parseTree.udts):
  614. rawUDT.setSourceRef(sourceManager)
  615. self.prog.addRawUDT(rawUDT)
  616. if rebuild:
  617. self.build()
  618. def loadLibraryBlock(self, libSelection, rebuild = False):
  619. self.prog.addLibrarySelection(libSelection)
  620. if rebuild:
  621. self.build()
  622. @property
  623. def symbolTable(self):
  624. return self.prog.symbolTable
  625. def loadSymbolTable(self, symbolTable, rebuild = False):
  626. self.prog.loadSymbolTable(symbolTable)
  627. if rebuild:
  628. self.build()
  629. def getBlockInfos(self, getOBInfo = False, getFCInfo = False,
  630. getFBInfo = False, getDBInfo = False):
  631. """Returns a list of BlockInfo()."""
  632. return self.prog.getBlockInfos(getOBInfo = getOBInfo,
  633. getFCInfo = getFCInfo,
  634. getFBInfo = getFBInfo,
  635. getDBInfo = getDBInfo)
  636. def staticSanityChecks(self):
  637. """Run static error checks."""
  638. self.prog.staticSanityChecks()
  639. def removeBlock(self, blockInfo, sanityChecks = True):
  640. """Remove a block from the CPU."""
  641. self.prog.removeBlock(blockInfo, sanityChecks)
  642. def reallocate(self, force=False):
  643. #@cy cdef OB ob
  644. if force or (self.specs.nrAccus == 4) != self.is4accu:
  645. self.accu1, self.accu2, self.accu3, self.accu4 =\
  646. Accu(), Accu(), Accu(), Accu()
  647. self.is4accu = (self.specs.nrAccus == 4)
  648. if force or self.specs.nrTimers != len(self.timers):
  649. self.timers = [ Timer(self, i)
  650. for i in range(self.specs.nrTimers) ]
  651. if force or self.specs.nrCounters != len(self.counters):
  652. self.counters = [ Counter(self, i)
  653. for i in range(self.specs.nrCounters) ]
  654. if force or self.specs.nrFlags != len(self.flags):
  655. self.flags = AwlMemory(self.specs.nrFlags)
  656. if force or self.specs.nrInputs != len(self.inputs):
  657. self.inputs = AwlMemory(self.specs.nrInputs)
  658. if force or self.specs.nrOutputs != len(self.outputs):
  659. self.outputs = AwlMemory(self.specs.nrOutputs)
  660. for ob in dictValues(self.obs):
  661. if force or self.specs.nrLocalbytes * 8 != ob.lstack.maxAllocBits:
  662. ob.lstack.resize(self.specs.nrLocalbytes)
  663. def reset(self):
  664. self.prog.reset()
  665. for block in itertools.chain(dictValues(self.udts),
  666. dictValues(self.dbs),
  667. dictValues(self.obs),
  668. dictValues(self.fcs),
  669. dictValues(self.fbs)):
  670. block.destroySourceRef()
  671. self.udts = {} # UDTs
  672. self.dbs = { # DBs
  673. 0 : DB(0, permissions = 0), # read/write-protected system-DB
  674. }
  675. self.obs = { # OBs
  676. 1 : OB([], 1), # Empty OB1
  677. }
  678. self.obTempPresetHandlers = {
  679. # OB TEMP-preset handlers
  680. 1 : OBTempPresets_table[1](self), # Default OB1 handler
  681. # This table is extended as OBs are loaded.
  682. }
  683. self.fcs = {} # User FCs
  684. self.fbs = {} # User FBs
  685. self.sfcs = {} # System SFCs
  686. self.sfbs = {} # System SFBs
  687. self.is4accu = False
  688. self.reallocate(force=True)
  689. self.ar1 = Addressregister()
  690. self.ar2 = Addressregister()
  691. self.db0 = self.dbs[0]
  692. self.dbRegister = self.db0
  693. self.diRegister = self.db0
  694. self.callStackTop = None
  695. self.callStackDepth = 0
  696. self.setMcrActive(False)
  697. self.mcrStack = [ ]
  698. self.statusWord = S7StatusWord()
  699. self.__clockMemByteOffset = None
  700. self.setRunTimeLimit()
  701. self.relativeJump = 1
  702. # Stats
  703. self.__insnCount = 0
  704. self.__cycleCount = 0
  705. self.insnPerSecond = 0.0
  706. self.avgInsnPerCycle = 0.0
  707. self.cycleStartTime = 0.0
  708. self.minCycleTime = 86400.0
  709. self.maxCycleTime = 0.0
  710. self.avgCycleTime = 0.0
  711. self.__avgCycleTimes = deque()
  712. self.__avgCycleTimesCount = 0
  713. self.__avgCycleTimesSum = 0.0
  714. self.__speedMeasureStartTime = 0
  715. self.__speedMeasureStartInsnCount = 0
  716. self.__speedMeasureStartCycleCount = 0
  717. self.initializeTimestamp()
  718. def setCycleExitCallback(self, cb, data=None):
  719. self.cbCycleExit = cb
  720. self.cbCycleExitData = data
  721. def setBlockExitCallback(self, cb, data=None):
  722. self.cbBlockExit = cb
  723. self.cbBlockExitData = data
  724. def setPostInsnCallback(self, cb, data=None):
  725. self.cbPostInsn = cb
  726. self.cbPostInsnData = data
  727. def setPeripheralReadCallback(self, cb, data=None):
  728. if cb:
  729. self.cbPeripheralRead = cb
  730. self.cbPeripheralReadData = data
  731. else:
  732. self.cbPeripheralRead =\
  733. lambda data, bitWidth, byteOffset: bytearray()
  734. self.cbPeripheralReadData = None
  735. def setPeripheralWriteCallback(self, cb, data=None):
  736. if cb:
  737. self.cbPeripheralWrite = cb
  738. self.cbPeripheralWriteData = data
  739. else:
  740. self.cbPeripheralWrite =\
  741. lambda data, bitWidth, byteOffset, value: False
  742. self.cbPeripheralWriteData = None
  743. def setScreenUpdateCallback(self, cb, data=None):
  744. self.cbScreenUpdate = cb
  745. self.cbScreenUpdateData = data
  746. def requestScreenUpdate(self):
  747. if self.cbScreenUpdate is not None:
  748. self.cbScreenUpdate(self.cbScreenUpdateData)
  749. def __runOB(self, block): #@nocy
  750. #@cy cdef __runOB(self, OB block):
  751. #@cy cdef AwlInsn insn
  752. #@cy cdef CallStackElem cse
  753. #@cy cdef CallStackElem exitCse
  754. #@cy cdef LStackAllocator activeLStack
  755. #@cy cdef uint32_t insnCount
  756. # Update timekeeping
  757. self.updateTimestamp()
  758. self.cycleStartTime = self.now
  759. # Initialize the L-stack. A previous block execution might
  760. # have exited with an exception and left allocation behind.
  761. # Clear all allocated bits.
  762. self.activeLStack = activeLStack = block.lstack
  763. activeLStack.reset()
  764. # Initialize CPU state
  765. self.dbRegister = self.diRegister = self.db0
  766. self.accu1.reset()
  767. self.accu2.reset()
  768. self.accu3.reset()
  769. self.accu4.reset()
  770. self.ar1.reset()
  771. self.ar2.reset()
  772. self.statusWord.reset()
  773. self.callStackTop, self.callStackDepth = None, 1
  774. cse = self.callStackTop = make_CallStackElem(self, block, None, None, (), True)
  775. if self.__obTempPresetsEnabled:
  776. # Populate the TEMP region
  777. self.obTempPresetHandlers[block.index].generate(activeLStack.memory.dataBytes)
  778. # Run the user program cycle
  779. while cse is not None:
  780. while cse.ip < cse.nrInsns:
  781. insn, self.relativeJump = cse.insns[cse.ip], 1
  782. insn.run()
  783. if self.cbPostInsn is not None:
  784. self.cbPostInsn(cse, self.cbPostInsnData)
  785. cse.ip += self.relativeJump
  786. cse = self.callStackTop
  787. self.__insnCount = insnCount = (self.__insnCount + 1) & 0x3FFFFFFF
  788. if not (insnCount & 0x3F):
  789. self.updateTimestamp()
  790. if self.now - self.cycleStartTime > self.cycleTimeLimit:
  791. self.__cycleTimeExceed()
  792. if self.cbBlockExit is not None:
  793. self.cbBlockExit(self.cbBlockExitData)
  794. cse, exitCse = cse.prevCse, cse
  795. self.callStackTop = cse
  796. self.callStackDepth -= 1
  797. exitCse.handleBlockExit()
  798. assert(self.callStackDepth == 0) #@nocy
  799. def initClockMemState(self, force=False):
  800. """Reset/initialize the clock memory byte state.
  801. """
  802. if self.conf.clockMemByte >= 0:
  803. clockMemByteOffset = make_AwlOffset(self.conf.clockMemByte, 0)
  804. else:
  805. clockMemByteOffset = None
  806. if force:
  807. resetCount = True
  808. else:
  809. resetCount = clockMemByteOffset != self.__clockMemByteOffset
  810. self.__clockMemByteOffset = None
  811. self.updateTimestamp()
  812. self.__clockMemByteOffset = clockMemByteOffset
  813. if resetCount:
  814. self.__nextClockMemTime = self.now + 0.05
  815. self.__clockMemCount = 0
  816. self.__clockMemCountLCM = math_lcm(2, 4, 5, 8, 10, 16, 20)
  817. if self.__clockMemByteOffset is not None:
  818. self.flags.store(self.__clockMemByteOffset, 8, 0)
  819. # Run startup code
  820. def startup(self):
  821. # Build (translate) the blocks, if not already done so.
  822. self.build()
  823. self.initializeTimestamp()
  824. self.__speedMeasureStartTime = self.now
  825. self.__speedMeasureStartInsnCount = 0
  826. self.__speedMeasureStartCycleCount = 0
  827. self.initClockMemState(force=True)
  828. # Run startup OB
  829. if 102 in self.obs and self.is4accu:
  830. # Cold start.
  831. # This is only done on 4xx-series CPUs.
  832. self.__runOB(self.obs[102])
  833. elif 100 in self.obs:
  834. # Warm start.
  835. # This really is a cold start, because remanent
  836. # resources were reset. However we could not execute
  837. # OB 102, so this is a fallback.
  838. # This is not 100% compliant with real CPUs, but it probably
  839. # is sane behavior.
  840. self.__runOB(self.obs[100])
  841. # Run one cycle of the user program
  842. def runCycle(self): #+cdef
  843. #@cy cdef double elapsedTime
  844. #@cy cdef double cycleTime
  845. #@cy cdef double avgCycleTime
  846. #@cy cdef double avgCycleTimesSum
  847. #@cy cdef double firstSample
  848. #@cy cdef double avgInsnPerCycle
  849. #@cy cdef double avgTimePerInsn
  850. #@cy cdef uint32_t cycleCount
  851. #@cy cdef uint32_t insnCount
  852. # Run the actual OB1 code
  853. self.__runOB(self.obs[1])
  854. # Update timekeeping and statistics
  855. self.updateTimestamp()
  856. self.__cycleCount = (self.__cycleCount + 1) & 0x3FFFFFFF
  857. # Evaluate speed measurement
  858. elapsedTime = self.now - self.__speedMeasureStartTime
  859. if elapsedTime >= 1.0:
  860. # Calculate instruction and cycle counts.
  861. cycleCount = (self.__cycleCount - self.__speedMeasureStartCycleCount) &\
  862. 0x3FFFFFFF
  863. insnCount = (self.__insnCount - self.__speedMeasureStartInsnCount) &\
  864. 0x3FFFFFFF
  865. # Get the average cycle time over the measurement period.
  866. cycleTime = elapsedTime / cycleCount
  867. # Calculate and store maximum and minimum cycle time.
  868. self.maxCycleTime = max(self.maxCycleTime, cycleTime)
  869. self.minCycleTime = min(self.minCycleTime, cycleTime)
  870. # Calculate and store moving average cycle time.
  871. avgCycleTimes = self.__avgCycleTimes
  872. avgCycleTimes.append(cycleTime)
  873. avgCycleTimesSum = self.__avgCycleTimesSum
  874. if self.__avgCycleTimesCount >= 3: # 3 samples
  875. firstSample = avgCycleTimes.popleft()
  876. avgCycleTimesSum -= firstSample
  877. avgCycleTimesSum += cycleTime
  878. self.avgCycleTime = avgCycleTime = avgCycleTimesSum / 3.0 # 3 samples
  879. else:
  880. avgCycleTimesSum += cycleTime
  881. self.__avgCycleTimesCount += 1
  882. self.avgCycleTime = avgCycleTime = 0.0
  883. self.__avgCycleTimesSum = avgCycleTimesSum
  884. # Calculate instruction statistics.
  885. self.avgInsnPerCycle = avgInsnPerCycle = insnCount / cycleCount
  886. if avgInsnPerCycle > 0.0:
  887. avgTimePerInsn = avgCycleTime / avgInsnPerCycle
  888. if avgTimePerInsn > 0.0:
  889. self.insnPerSecond = 1.0 / avgTimePerInsn
  890. else:
  891. self.insnPerSecond = 0.0
  892. else:
  893. self.insnPerSecond = 0.0
  894. # Reset the counters
  895. self.__speedMeasureStartTime = self.now
  896. self.__speedMeasureStartInsnCount = self.__insnCount
  897. self.__speedMeasureStartCycleCount = self.__cycleCount
  898. # Call the cycle exit callback, if any.
  899. if self.cbCycleExit is not None:
  900. self.cbCycleExit(self.cbCycleExitData)
  901. # Returns 'self.now' as 31 bit millisecond representation.
  902. # That is data type 'TIME'.
  903. # The returned value will always be positive and wrap
  904. # from 0x7FFFFFFF to 0.
  905. @property
  906. def now_TIME(self):
  907. return int(self.now * 1000.0) & 0x7FFFFFFF
  908. # Initialize time stamp.
  909. def initializeTimestamp(self):
  910. # Initialize the time stamp so that it will
  911. # overflow 31 bit millisecond count within
  912. # 100 milliseconds after startup.
  913. # An 31 bit overflow happens after 0x7FFFFFFF ms,
  914. # which is 2147483647 ms, which is 2147483.647 s.
  915. # Create an offset to 'self.now' that is added every
  916. # time 'self.now' is updated.
  917. now = perf_monotonic_time()
  918. self.__nowOffset = -(now) + (2147483.647 - 0.1)
  919. self.now = now = now + self.__nowOffset
  920. self.startupTime = now
  921. self.updateTimestamp()
  922. # updateTimestamp() updates self.now, which is a
  923. # floating point count of seconds.
  924. def updateTimestamp(self, _getTime=perf_monotonic_time): #@nocy
  925. #@cy cdef updateTimestamp(self):
  926. #@cy cdef uint32_t value
  927. #@cy cdef uint32_t count
  928. #@cy cdef double now
  929. # Update the system time
  930. now = _getTime() #@nocy
  931. #@cy now = perf_monotonic_time()
  932. self.now = now = now + self.__nowOffset
  933. # Update the clock memory byte
  934. if self.__clockMemByteOffset is not None and\
  935. now >= self.__nextClockMemTime:
  936. try:
  937. self.__nextClockMemTime += 0.05
  938. value = self.flags.fetch(self.__clockMemByteOffset, 8)
  939. value ^= 0x01 # 0.1s period
  940. count = self.__clockMemCount + 1
  941. self.__clockMemCount = count
  942. if not count % 2:
  943. value ^= 0x02 # 0.2s period
  944. if not count % 4:
  945. value ^= 0x04 # 0.4s period
  946. if not count % 5:
  947. value ^= 0x08 # 0.5s period
  948. if not count % 8:
  949. value ^= 0x10 # 0.8s period
  950. if not count % 10:
  951. value ^= 0x20 # 1.0s period
  952. if not count % 16:
  953. value ^= 0x40 # 1.6s period
  954. if not count % 20:
  955. value ^= 0x80 # 2.0s period
  956. if count >= self.__clockMemCountLCM:
  957. self.__clockMemCount = 0
  958. self.flags.store(self.__clockMemByteOffset, 8, value)
  959. except AwlSimError as e:
  960. raise AwlSimError("Failed to generate clock "
  961. "memory signal:\n" + str(e) +\
  962. "\n\nThe configured clock memory byte "
  963. "address might be invalid." )
  964. # Check whether the runtime timeout exceeded
  965. if self.__runtimeLimit >= 0.0:
  966. if now - self.startupTime >= self.__runtimeLimit:
  967. self.__runTimeExceed()
  968. def __cycleTimeExceed(self): #+cdef
  969. raise AwlSimError("Cycle time exceed %.3f seconds" % (
  970. self.cycleTimeLimit))
  971. def __runTimeExceed(self): #+cdef
  972. raise MaintenanceRequest(MaintenanceRequest.TYPE_RTTIMEOUT,
  973. "CPU runtime timeout")
  974. # Make a DATE_AND_TIME for the current wall-time and
  975. # store it in byteArray, which is a bytearray or compatible.
  976. # If byteArray is smaller than 8 bytes, an IndexError is raised.
  977. def makeCurrentDateAndTime(self, byteArray, offset): #@nocy
  978. #@cy cdef makeCurrentDateAndTime(self, bytearray byteArray, uint32_t offset):
  979. #@cy cdef uint32_t year
  980. #@cy cdef uint32_t month
  981. #@cy cdef uint32_t day
  982. #@cy cdef uint32_t hour
  983. #@cy cdef uint32_t minute
  984. #@cy cdef uint32_t second
  985. #@cy cdef uint32_t msec
  986. dt = datetime.datetime.now()
  987. year, month, day, hour, minute, second, msec =\
  988. dt.year, dt.month, dt.day, dt.hour, \
  989. dt.minute, dt.second, dt.microsecond // 1000
  990. byteArray[offset] = (year % 10) | (((year // 10) % 10) << 4)
  991. byteArray[offset + 1] = (month % 10) | (((month // 10) % 10) << 4)
  992. byteArray[offset + 2] = (day % 10) | (((day // 10) % 10) << 4)
  993. byteArray[offset + 3] = (hour % 10) | (((hour // 10) % 10) << 4)
  994. byteArray[offset + 4] = (minute % 10) | (((minute // 10) % 10) << 4)
  995. byteArray[offset + 5] = (second % 10) | (((second // 10) % 10) << 4)
  996. byteArray[offset + 6] = ((msec // 10) % 10) | (((msec // 100) % 10) << 4)
  997. byteArray[offset + 7] = ((msec % 10) << 4) |\
  998. self.__dateAndTimeWeekdayMap[dt.weekday()]
  999. def getCurrentIP(self):
  1000. try:
  1001. return self.callStackTop.ip
  1002. except IndexError as e:
  1003. return None
  1004. def getCurrentInsn(self):
  1005. try:
  1006. cse = self.callStackTop
  1007. if not cse:
  1008. return None
  1009. return cse.insns[cse.ip]
  1010. except IndexError as e:
  1011. return None
  1012. def labelIdxToRelJump(self, labelIndex): #@nocy
  1013. #@cy cdef int32_t labelIdxToRelJump(self, uint32_t labelIndex) except? 0x7FFFFFFF:
  1014. #@cy cdef CallStackElem cse
  1015. # Translate a label index into a relative IP offset.
  1016. cse = self.callStackTop
  1017. label = cse.block.labels[labelIndex]
  1018. return label.insn.ip - cse.ip
  1019. def jumpToLabel(self, labelIndex): #@nocy
  1020. #@cy cdef jumpToLabel(self, uint32_t labelIndex):
  1021. self.relativeJump = self.labelIdxToRelJump(labelIndex)
  1022. def jumpRelative(self, insnOffset): #@nocy
  1023. #@cy cdef jumpRelative(self, int32_t insnOffset):
  1024. self.relativeJump = insnOffset
  1025. def __call_FC(self, blockOper, dbOper, parameters): #@nocy
  1026. #@cy cdef CallStackElem __call_FC(self, AwlOperator blockOper, AwlOperator dbOper, tuple parameters):
  1027. fc = self.fcs[blockOper.offset.byteOffset]
  1028. return make_CallStackElem(self, fc, None, None, parameters, False)
  1029. def __call_RAW_FC(self, blockOper, dbOper, parameters): #@nocy
  1030. #@cy cdef CallStackElem __call_RAW_FC(self, AwlOperator blockOper, AwlOperator dbOper, tuple parameters):
  1031. fc = self.fcs[blockOper.offset.byteOffset]
  1032. return make_CallStackElem(self, fc, None, None, (), True)
  1033. def __call_FB(self, blockOper, dbOper, parameters): #@nocy
  1034. #@cy cdef CallStackElem __call_FB(self, AwlOperator blockOper, AwlOperator dbOper, tuple parameters):
  1035. #@cy cdef CallStackElem cse
  1036. #@cy cdef DB db
  1037. fb = self.fbs[blockOper.offset.byteOffset]
  1038. db = self.dbs[dbOper.offset.byteOffset]
  1039. cse = make_CallStackElem(self, fb, db, make_AwlOffset(0, 0), parameters, False)
  1040. self.dbRegister, self.diRegister = self.diRegister, db
  1041. return cse
  1042. def __call_RAW_FB(self, blockOper, dbOper, parameters): #@nocy
  1043. #@cy cdef CallStackElem __call_RAW_FB(self, AwlOperator blockOper, AwlOperator dbOper, tuple parameters):
  1044. fb = self.fbs[blockOper.offset.byteOffset]
  1045. return make_CallStackElem(self, fb, self.diRegister, None, (), True)
  1046. def __call_SFC(self, blockOper, dbOper, parameters): #@nocy
  1047. #@cy cdef CallStackElem __call_SFC(self, AwlOperator blockOper, AwlOperator dbOper, tuple parameters):
  1048. sfc = self.sfcs[blockOper.offset.byteOffset]
  1049. return make_CallStackElem(self, sfc, None, None, parameters, False)
  1050. def __call_RAW_SFC(self, blockOper, dbOper, parameters): #@nocy
  1051. #@cy cdef CallStackElem __call_RAW_SFC(self, AwlOperator blockOper, AwlOperator dbOper, tuple parameters):
  1052. sfc = self.sfcs[blockOper.offset.byteOffset]
  1053. return make_CallStackElem(self, sfc, None, None, (), True)
  1054. def __call_SFB(self, blockOper, dbOper, parameters): #@nocy
  1055. #@cy cdef CallStackElem __call_SFB(self, AwlOperator blockOper, AwlOperator dbOper, tuple parameters):
  1056. #@cy cdef CallStackElem cse
  1057. #@cy cdef DB db
  1058. sfb = self.sfbs[blockOper.offset.byteOffset]
  1059. db = self.dbs[dbOper.offset.byteOffset]
  1060. cse = make_CallStackElem(self, sfb, db, make_AwlOffset(0, 0), parameters, False)
  1061. self.dbRegister, self.diRegister = self.diRegister, db
  1062. return cse
  1063. def __call_RAW_SFB(self, blockOper, dbOper, parameters): #@nocy
  1064. #@cy cdef CallStackElem __call_RAW_SFB(self, AwlOperator blockOper, AwlOperator dbOper, tuple parameters):
  1065. sfb = self.sfbs[blockOper.offset.byteOffset]
  1066. return make_CallStackElem(self, sfb, self.diRegister, None, (), True)
  1067. def __call_INDIRECT(self, blockOper, dbOper, parameters): #@nocy
  1068. #@cy cdef CallStackElem __call_INDIRECT(self, AwlOperator blockOper, AwlOperator dbOper, tuple parameters):
  1069. blockOper = blockOper.resolve()
  1070. #@cy if blockOper.operType == AwlOperatorTypes.BLKREF_FC:
  1071. #@cy return self.__call_RAW_FC(blockOper, dbOper, parameters)
  1072. #@cy elif blockOper.operType == AwlOperatorTypes.BLKREF_FB:
  1073. #@cy return self.__call_RAW_FB(blockOper, dbOper, parameters)
  1074. #@cy elif blockOper.operType == AwlOperatorTypes.BLKREF_SFC:
  1075. #@cy return self.__call_RAW_SFC(blockOper, dbOper, parameters)
  1076. #@cy elif blockOper.operType == AwlOperatorTypes.BLKREF_SFB:
  1077. #@cy return self.__call_RAW_SFB(blockOper, dbOper, parameters)
  1078. #@cy else:
  1079. #@cy raise AwlSimError("Invalid CALL operand")
  1080. callHelper = self.__rawCallHelpers[blockOper.operType] #@nocy
  1081. try: #@nocy
  1082. return callHelper(self, blockOper, dbOper, parameters) #@nocy
  1083. except KeyError as e: #@nocy
  1084. raise AwlSimError("Code block %d not found in indirect call" %( #@nocy
  1085. blockOper.offset.byteOffset)) #@nocy
  1086. def __call_MULTI_FB(self, blockOper, dbOper, parameters): #@nocy
  1087. #@cy cdef CallStackElem __call_MULTI_FB(self, AwlOperator blockOper, AwlOperator dbOper, tuple parameters):
  1088. fb = self.fbs[blockOper.offset.fbNumber]
  1089. base = make_AwlOffset_fromPointerValue(self.ar2.get()) + blockOper.offset
  1090. cse = make_CallStackElem(self, fb, self.diRegister, base, parameters, False)
  1091. self.dbRegister = self.diRegister
  1092. return cse
  1093. def __call_MULTI_SFB(self, blockOper, dbOper, parameters): #@nocy
  1094. #@cy cdef CallStackElem __call_MULTI_SFB(self, AwlOperator blockOper, AwlOperator dbOper, tuple parameters):
  1095. #@cy cdef AwlOffset base
  1096. #@cy cdef CallStackElem cse
  1097. sfb = self.sfbs[blockOper.offset.fbNumber]
  1098. base = make_AwlOffset_fromPointerValue(self.ar2.get()) + blockOper.offset
  1099. cse = make_CallStackElem(self, sfb, self.diRegister, base, parameters, False)
  1100. self.dbRegister = self.diRegister
  1101. return cse
  1102. __callHelpersDict = { #@nocy
  1103. AwlOperatorTypes.BLKREF_FC : __call_FC, #@nocy
  1104. AwlOperatorTypes.BLKREF_FB : __call_FB, #@nocy
  1105. AwlOperatorTypes.BLKREF_SFC : __call_SFC, #@nocy
  1106. AwlOperatorTypes.BLKREF_SFB : __call_SFB, #@nocy
  1107. AwlOperatorTypes.MULTI_FB : __call_MULTI_FB, #@nocy
  1108. AwlOperatorTypes.MULTI_SFB : __call_MULTI_SFB, #@nocy
  1109. } #@nocy
  1110. __rawCallHelpersDict = { #@nocy
  1111. AwlOperatorTypes.BLKREF_FC : __call_RAW_FC, #@nocy
  1112. AwlOperatorTypes.BLKREF_FB : __call_RAW_FB, #@nocy
  1113. AwlOperatorTypes.BLKREF_SFC : __call_RAW_SFC, #@nocy
  1114. AwlOperatorTypes.BLKREF_SFB : __call_RAW_SFB, #@nocy
  1115. AwlOperatorTypes.INDIRECT : __call_INDIRECT, #@nocy
  1116. } #@nocy
  1117. def run_CALL(self, blockOper, dbOper=None, parameters=(), raw=False): #@nocy
  1118. #@cy cdef run_CALL(self, AwlOperator blockOper, AwlOperator dbOper=None,
  1119. #@cy tuple parameters=(), _Bool raw=False):
  1120. #@cy cdef CallStackElem newCse
  1121. #@cy cdef uint32_t callStackDepth
  1122. callStackDepth = self.callStackDepth
  1123. if callStackDepth >= self.maxCallStackDepth:
  1124. raise AwlSimError("Maximum CALL stack depth of %d CALLs exceed." % (
  1125. self.maxCallStackDepth))
  1126. #@cy if raw:
  1127. #@cy if blockOper.operType == AwlOperatorTypes.BLKREF_FC:
  1128. #@cy newCse = self.__call_RAW_FC(blockOper, dbOper, parameters)
  1129. #@cy elif blockOper.operType == AwlOperatorTypes.BLKREF_FB:
  1130. #@cy newCse = self.__call_RAW_FB(blockOper, dbOper, parameters)
  1131. #@cy elif blockOper.operType == AwlOperatorTypes.BLKREF_SFC:
  1132. #@cy newCse = self.__call_RAW_SFC(blockOper, dbOper, parameters)
  1133. #@cy elif blockOper.operType == AwlOperatorTypes.BLKREF_SFB:
  1134. #@cy newCse = self.__call_RAW_SFB(blockOper, dbOper, parameters)
  1135. #@cy elif blockOper.operType == AwlOperatorTypes.INDIRECT:
  1136. #@cy newCse = self.__call_INDIRECT(blockOper, dbOper, parameters)
  1137. #@cy else:
  1138. #@cy raise AwlSimError("Invalid CALL operand")
  1139. #@cy else:
  1140. #@cy if blockOper.operType == AwlOperatorTypes.BLKREF_FC:
  1141. #@cy newCse = self.__call_FC(blockOper, dbOper, parameters)
  1142. #@cy elif blockOper.operType == AwlOperatorTypes.BLKREF_FB:
  1143. #@cy newCse = self.__call_FB(blockOper, dbOper, parameters)
  1144. #@cy elif blockOper.operType == AwlOperatorTypes.BLKREF_SFC:
  1145. #@cy newCse = self.__call_SFC(blockOper, dbOper, parameters)
  1146. #@cy elif blockOper.operType == AwlOperatorTypes.BLKREF_SFB:
  1147. #@cy newCse = self.__call_SFB(blockOper, dbOper, parameters)
  1148. #@cy elif blockOper.operType == AwlOperatorTypes.MULTI_FB:
  1149. #@cy newCse = self.__call_MULTI_FB(blockOper, dbOper, parameters)
  1150. #@cy elif blockOper.operType == AwlOperatorTypes.MULTI_SFB:
  1151. #@cy newCse = self.__call_MULTI_SFB(blockOper, dbOper, parameters)
  1152. #@cy else:
  1153. #@cy raise AwlSimError("Invalid CALL operand")
  1154. try: #@nocy
  1155. if raw: #@nocy
  1156. callHelper = self.__rawCallHelpers[blockOper.operType] #@nocy
  1157. else: #@nocy
  1158. callHelper = self.__callHelpers[blockOper.operType] #@nocy
  1159. except KeyError: #@nocy
  1160. raise AwlSimError("Invalid CALL operand") #@nocy
  1161. newCse = callHelper(self, blockOper, dbOper, parameters) #@nocy
  1162. newCse.prevCse = self.callStackTop
  1163. self.callStackTop, self.callStackDepth = newCse, callStackDepth + 1
  1164. def run_BE(self): #+cdef
  1165. #@cy cdef S7StatusWord s
  1166. #@cy cdef CallStackElem cse
  1167. s = self.statusWord
  1168. s.OS, s.OR, s.STA, s.NER = 0, 0, 1, 0
  1169. # Jump beyond end of block
  1170. cse = self.callStackTop
  1171. self.relativeJump = len(cse.insns) - cse.ip
  1172. def openDB(self, dbNumber, openDI): #@nocy
  1173. #@cy cdef openDB(self, int32_t dbNumber, _Bool openDI):
  1174. #@cy cdef DB db
  1175. if dbNumber <= 0:
  1176. if openDI:
  1177. self.diRegister = self.db0
  1178. else:
  1179. self.dbRegister = self.db0
  1180. else:
  1181. try:
  1182. if openDI:
  1183. self.diRegister = self.dbs[dbNumber]
  1184. else:
  1185. self.dbRegister = self.dbs[dbNumber]
  1186. except KeyError:
  1187. raise AwlSimError("Datablock %i does not exist" % dbNumber)
  1188. def run_AUF(self, dbOper): #@nocy
  1189. #@cy cdef run_AUF(self, AwlOperator dbOper):
  1190. #@cy cdef _Bool openDI
  1191. #@cy cdef uint32_t operType
  1192. dbOper = dbOper.resolve()
  1193. operType = dbOper.operType
  1194. if operType == AwlOperatorTypes.BLKREF_DB:
  1195. openDI = False
  1196. elif operType == AwlOperatorTypes.BLKREF_DI:
  1197. openDI = True
  1198. else:
  1199. raise AwlSimError("Invalid DB reference in AUF")
  1200. self.openDB(dbOper.offset.byteOffset, openDI)
  1201. def run_TDB(self): #+cdef
  1202. # Swap global and instance DB
  1203. self.diRegister, self.dbRegister = self.dbRegister, self.diRegister
  1204. def getAccu(self, index): #@nocy
  1205. #@cy cdef Accu getAccu(self, uint32_t index):
  1206. if index < 1 or index > self.specs.nrAccus:
  1207. raise AwlSimError("Invalid ACCU offset")
  1208. return (self.accu1, self.accu2,
  1209. self.accu3, self.accu4)[index - 1]
  1210. def getAR(self, index): #@nocy
  1211. #@cy cdef Addressregister getAR(self, uint32_t index):
  1212. if index < 1 or index > 2:
  1213. raise AwlSimError("Invalid AR offset")
  1214. return (self.ar1, self.ar2)[index - 1]
  1215. def getTimer(self, index):
  1216. try:
  1217. return self.timers[index]
  1218. except IndexError as e:
  1219. raise AwlSimError("Fetched invalid timer %d" % index)
  1220. def getCounter(self, index):
  1221. try:
  1222. return self.counters[index]
  1223. except IndexError as e:
  1224. raise AwlSimError("Fetched invalid counter %d" % index)
  1225. def getSpecs(self):
  1226. return self.specs
  1227. def getConf(self):
  1228. return self.conf
  1229. def setMcrActive(self, active): #@nocy
  1230. #@cy cdef void setMcrActive(self, _Bool active):
  1231. self.mcrActive = active
  1232. def mcrIsOn(self): #@nocy
  1233. #@cy cdef _Bool mcrIsOn(self):
  1234. return (not self.mcrActive or all(self.mcrStack))
  1235. def mcrStackAppend(self, statusWord): #@nocy
  1236. #@cy cdef mcrStackAppend(self, S7StatusWord statusWord):
  1237. self.mcrStack.append(statusWord.VKE)
  1238. if len(self.mcrStack) > 8:
  1239. raise AwlSimError("MCR stack overflow")
  1240. def mcrStackPop(self): #+cdef
  1241. try:
  1242. self.mcrStack.pop()
  1243. except IndexError:
  1244. raise AwlSimError("MCR stack underflow")
  1245. def parenStackAppend(self, insnType, statusWord): #@nocy
  1246. #@cy cdef parenStackAppend(self, uint32_t insnType, S7StatusWord statusWord):
  1247. #@cy cdef CallStackElem cse
  1248. cse = self.callStackTop
  1249. cse.parenStack.append(ParenStackElem(self, insnType, statusWord))
  1250. if len(cse.parenStack) > 7:
  1251. raise AwlSimError("Parenthesis stack overflow")
  1252. def __translateFCNamedLocalOper(self, operator, store): #@nocy
  1253. #@cy cdef AwlOperator __translateFCNamedLocalOper(self, AwlOperator operator, _Bool store):
  1254. #@cy cdef uint32_t pointer
  1255. #@cy cdef uint32_t opType
  1256. #@cy cdef uint32_t dbNr
  1257. #@cy cdef AwlOperator interfOp
  1258. #@cy cdef AwlOperator dbPtrOp
  1259. #@cy cdef AwlOperator finalOp
  1260. #@cy cdef AwlOffset subOffset
  1261. # Translate an 'operator' to a named local FC parameter.
  1262. # The returned operator is an operator to the actual data.
  1263. interfOp = self.callStackTop.getInterfIdxOper(operator.interfaceIndex).resolve(store)
  1264. if operator.compound:
  1265. # This is a named local variable with compound data type.
  1266. # The operator (interfOp) points to a DB-pointer in VL.
  1267. # First fetch the DB pointer values from VL.
  1268. dbPtrOp = interfOp.dup()
  1269. dbPtrOp.width = 16
  1270. dbNr = self.fetch(dbPtrOp, AwlOperatorWidths.WIDTH_MASK_16)
  1271. dbPtrOp.offset.byteOffset += 2
  1272. dbPtrOp.width = 32
  1273. pointer = self.fetch(dbPtrOp, AwlOperatorWidths.WIDTH_MASK_32)
  1274. # Open the DB pointed to by the DB-ptr.
  1275. # (This is ok, if dbNr is 0, too)
  1276. self.openDB(dbNr, False)
  1277. # Make an operator from the DB-ptr.
  1278. try:
  1279. opType = AwlIndirectOpConst.area2optype_fetch[
  1280. pointer & PointerConst.AREA_MASK_S]
  1281. except KeyError:
  1282. raise AwlSimError("Corrupt DB pointer in compound "
  1283. "data type FC variable detected "
  1284. "(invalid area).", insn = operator.insn)
  1285. finalOp = make_AwlOperator(opType, operator.width,
  1286. make_AwlOffset_fromPointerValue(pointer),
  1287. operator.insn)
  1288. else:
  1289. # Not a compound data type.
  1290. # The translated operand already points to the variable.
  1291. finalOp = interfOp.dup()
  1292. finalOp.width = operator.width
  1293. # Add possible sub-offsets (ARRAY, STRUCT) to the offset.
  1294. subOffset = operator.offset.subOffset
  1295. if subOffset is not None:
  1296. finalOp.offset += subOffset
  1297. # Reparent the operator to the originating instruction.
  1298. # This is especially important for T and Z fetches due
  1299. # to their semantic dependency on the instruction being used.
  1300. finalOp.insn = operator.insn
  1301. return finalOp
  1302. # Fetch a range in the 'output' memory area.
  1303. # 'byteOffset' is the byte offset into the output area.
  1304. # 'byteCount' is the number if bytes to fetch.
  1305. # Returns a bytearray.
  1306. # This raises an AwlSimError, if the access if out of range.
  1307. def fetchOutputRange(self, byteOffset, byteCount): #@nocy
  1308. #@cy cpdef bytearray fetchOutputRange(self, uint32_t byteOffset, uint32_t byteCount):
  1309. if byteOffset + byteCount > len(self.outputs): #@nocy
  1310. #@cy if <uint64_t>byteOffset + <uint64_t>byteCount > <uint64_t>len(self.outputs):
  1311. raise AwlSimError("Fetch from output process image region "
  1312. "is out of range "
  1313. "(imageSize=%d, fetchOffset=%d, fetchSize=%d)." % (
  1314. len(self.outputs), byteOffset, byteCount))
  1315. return self.outputs.dataBytes[byteOffset : byteOffset + byteCount]
  1316. # Fetch a range in the 'input' memory area.
  1317. # 'byteOffset' is the byte offset into the input area.
  1318. # 'byteCount' is the number if bytes to fetch.
  1319. # Returns a bytearray.
  1320. # This raises an AwlSimError, if the access if out of range.
  1321. def fetchInputRange(self, byteOffset, byteCount): #@nocy
  1322. #@cy cpdef bytearray fetchInputRange(self, uint32_t byteOffset, uint32_t byteCount):
  1323. if byteOffset + byteCount > len(self.inputs): #@nocy
  1324. #@cy if <uint64_t>byteOffset + <uint64_t>byteCount > <uint64_t>len(self.inputs):
  1325. raise AwlSimError("Fetch from input process image region "
  1326. "is out of range "
  1327. "(imageSize=%d, fetchOffset=%d, fetchSize=%d)." % (
  1328. len(self.inputs), byteOffset, byteCount))
  1329. return self.inputs.dataBytes[byteOffset : byteOffset + byteCount]
  1330. # Store a range in the 'input' memory area.
  1331. # 'byteOffset' is the byte offset into the input area.
  1332. # 'data' is a bytearray.
  1333. # This raises an AwlSimError, if the access if out of range.
  1334. def storeInputRange(self, byteOffset, data): #@nocy
  1335. #@cy cpdef storeInputRange(self, uint32_t byteOffset, bytearray data):
  1336. #@cy cdef uint32_t dataLen
  1337. dataLen = len(data)
  1338. if byteOffset + dataLen > len(self.inputs): #@nocy
  1339. #@cy if <uint64_t>byteOffset + <uint64_t>dataLen > <uint64_t>len(self.inputs):
  1340. raise AwlSimError("Store to input process image region "
  1341. "is out of range "
  1342. "(imageSize=%d, storeOffset=%d, storeSize=%d)." % (
  1343. len(self.inputs), byteOffset, dataLen))
  1344. self.inputs.dataBytes[byteOffset : byteOffset + dataLen] = data
  1345. def fetch(self, operator, allowedWidths): #@nocy
  1346. try: #@nocy
  1347. fetchMethod = self.__fetchTypeMethods[operator.operType] #@nocy
  1348. except KeyError: #@nocy
  1349. self.__invalidFetch(operator) #@nocy
  1350. return fetchMethod(self, operator, allowedWidths) #@nocy
  1351. #@cy cpdef object fetch(self, AwlOperator operator, uint32_t allowedWidths):
  1352. #@cy cdef uint32_t operType
  1353. #@cy
  1354. #@cy operType = operator.operType
  1355. #@cy if operType == AwlOperatorTypes.IMM:
  1356. #@cy return self.__fetchIMM(operator, allowedWidths)
  1357. #@cy elif operType == AwlOperatorTypes.IMM_REAL:
  1358. #@cy return self.__fetchIMM(operator, allowedWidths)
  1359. #@cy elif operType == AwlOperatorTypes.IMM_S5T:
  1360. #@cy return self.__fetchIMM(operator, allowedWidths)
  1361. #@cy elif operType == AwlOperatorTypes.IMM_TIME:
  1362. #@cy return self.__fetchIMM(operator, allowedWidths)
  1363. #@cy elif operType == AwlOperatorTypes.IMM_DATE:
  1364. #@cy return self.__fetchIMM(operator, allowedWidths)
  1365. #@cy elif operType == AwlOperatorTypes.IMM_DT:
  1366. #@cy return self.__fetchIMM_DT(operator, allowedWidths)
  1367. #@cy elif operType == AwlOperatorTypes.IMM_TOD:
  1368. #@cy return self.__fetchIMM(operator, allowedWidths)
  1369. #@cy elif operType == AwlOperatorTypes.IMM_PTR:
  1370. #@cy return self.__fetchIMM_PTR(operator, allowedWidths)
  1371. #@cy elif operType == AwlOperatorTypes.IMM_STR:
  1372. #@cy return self.__fetchIMM_STR(operator, allowedWidths)
  1373. #@cy elif operType == AwlOperatorTypes.MEM_E:
  1374. #@cy return self.__fetchE(operator, allowedWidths)
  1375. #@cy elif operType == AwlOperatorTypes.MEM_A:
  1376. #@cy return self.__fetchA(operator, allowedWidths)
  1377. #@cy elif operType == AwlOperatorTypes.MEM_M:
  1378. #@cy return self.__fetchM(operator, allowedWidths)
  1379. #@cy elif operType == AwlOperatorTypes.MEM_L:
  1380. #@cy return self.__fetchL(operator, allowedWidths)
  1381. #@cy elif operType == AwlOperatorTypes.MEM_VL:
  1382. #@cy return self.__fetchVL(operator, allowedWidths)
  1383. #@cy elif operType == AwlOperatorTypes.MEM_DB:
  1384. #@cy return self.__fetchDB(operator, allowedWidths)
  1385. #@cy elif operType == AwlOperatorTypes.MEM_DI:
  1386. #@cy return self.__fetchDI(operator, allowedWidths)
  1387. #@cy elif operType == AwlOperatorTypes.MEM_T:
  1388. #@cy return self.__fetchT(operator, allowedWidths)
  1389. #@cy elif operType == AwlOperatorTypes.MEM_Z:
  1390. #@cy return self.__fetchZ(operator, allowedWidths)
  1391. #@cy elif operType == AwlOperatorTypes.MEM_PE:
  1392. #@cy return self.__fetchPE(operator, allowedWidths)
  1393. #@cy elif operType == AwlOperatorTypes.MEM_DBLG:
  1394. #@cy return self.__fetchDBLG(operator, allowedWidths)
  1395. #@cy elif operType == AwlOperatorTypes.MEM_DBNO:
  1396. #@cy return self.__fetchDBNO(operator, allowedWidths)
  1397. #@cy elif operType == AwlOperatorTypes.MEM_DILG:
  1398. #@cy return self.__fetchDILG(operator, allowedWidths)
  1399. #@cy elif operType == AwlOperatorTypes.MEM_DINO:
  1400. #@cy return self.__fetchDINO(operator, allowedWidths)
  1401. #@cy elif operType == AwlOperatorTypes.MEM_AR2:
  1402. #@cy return self.__fetchAR2(operator, allowedWidths)
  1403. #@cy elif operType == AwlOperatorTypes.MEM_STW:
  1404. #@cy return self.__fetchSTW(operator, allowedWidths)
  1405. #@cy elif operType == AwlOperatorTypes.MEM_STW_Z:
  1406. #@cy return self.__fetchSTW_Z(operator, allowedWidths)
  1407. #@cy elif operType == AwlOperatorTypes.MEM_STW_NZ:
  1408. #@cy return self.__fetchSTW_NZ(operator, allowedWidths)
  1409. #@cy elif operType == AwlOperatorTypes.MEM_STW_POS:
  1410. #@cy return self.__fetchSTW_POS(operator, allowedWidths)
  1411. #@cy elif operType == AwlOperatorTypes.MEM_STW_NEG:
  1412. #@cy return self.__fetchSTW_NEG(operator, allowedWidths)
  1413. #@cy elif operType == AwlOperatorTypes.MEM_STW_POSZ:
  1414. #@cy return self.__fetchSTW_POSZ(operator, allowedWidths)
  1415. #@cy elif operType == AwlOperatorTypes.MEM_STW_NEGZ:
  1416. #@cy return self.__fetchSTW_NEGZ(operator, allowedWidths)
  1417. #@cy elif operType == AwlOperatorTypes.MEM_STW_UO:
  1418. #@cy return self.__fetchSTW_UO(operator, allowedWidths)
  1419. #@cy elif operType == AwlOperatorTypes.NAMED_LOCAL:
  1420. #@cy return self.__fetchNAMED_LOCAL(operator, allowedWidths)
  1421. #@cy elif operType == AwlOperatorTypes.NAMED_LOCAL_PTR:
  1422. #@cy return self.__fetchNAMED_LOCAL_PTR(operator, allowedWidths)
  1423. #@cy elif operType == AwlOperatorTypes.NAMED_DBVAR:
  1424. #@cy return self.__fetchNAMED_DBVAR(operator, allowedWidths)
  1425. #@cy elif operType == AwlOperatorTypes.INDIRECT:
  1426. #@cy return self.__fetchINDIRECT(operator, allowedWidths)
  1427. #@cy elif operType == AwlOperatorTypes.VIRT_ACCU:
  1428. #@cy return self.__fetchVirtACCU(operator, allowedWidths)
  1429. #@cy elif operType == AwlOperatorTypes.VIRT_AR:
  1430. #@cy return self.__fetchVirtAR(operator, allowedWidths)
  1431. #@cy elif operType == AwlOperatorTypes.VIRT_DBR:
  1432. #@cy return self.__fetchVirtDBR(operator, allowedWidths)
  1433. #@cy self.__invalidFetch(operator)
  1434. def __invalidFetch(self, operator):
  1435. raise AwlSimError("Invalid fetch request: %s" % str(operator))
  1436. def __fetchWidthError(self, operator, allowedWidths):
  1437. raise AwlSimError("Data fetch of %d bits, "
  1438. "but only %s bits are allowed." %\
  1439. (operator.width,
  1440. listToHumanStr(AwlOperatorWidths.maskToList(allowedWidths))))
  1441. def __fetchIMM(self, operator, allowedWidths): #@nocy
  1442. #@cy cdef object __fetchIMM(self, AwlOperator operator, uint32_t allowedWidths):
  1443. if not (AwlOperatorWidths.makeMask(operator.width) & allowedWidths):
  1444. self.__fetchWidthError(operator, allowedWidths)
  1445. return operator.immediate
  1446. def __fetchIMM_DT(self, operator, allowedWidths): #@nocy
  1447. #@cy cdef object __fetchIMM_DT(self, AwlOperator operator, uint32_t allowedWidths):
  1448. if not (AwlOperatorWidths.makeMask(operator.width) & allowedWidths):
  1449. self.__fetchWidthError(operator, allowedWidths)
  1450. return operator.immediateBytes
  1451. def __fetchIMM_PTR(self, operator, allowedWidths): #@nocy
  1452. #@cy cdef object __fetchIMM_PTR(self, AwlOperator operator, uint32_t allowedWidths):
  1453. if not (AwlOperatorWidths.makeMask(operator.width) & allowedWidths):
  1454. self.__fetchWidthError(operator, allowedWidths)
  1455. return operator.pointer.toNativePointerValue()
  1456. def __fetchIMM_STR(self, operator, allowedWidths): #@nocy
  1457. #@cy cdef object __fetchIMM_STR(self, AwlOperator operator, uint32_t allowedWidths):
  1458. #@cy cdef uint32_t insnType
  1459. #@cy cdef uint32_t value
  1460. #@cy cdef int32_t i
  1461. if operator.width <= 48 and operator.insn is not None:
  1462. insnType = operator.insn.insnType
  1463. if insnType == AwlInsn.TYPE_L or\
  1464. insnType >= AwlInsn.TYPE_EXTENDED:
  1465. # This is a special 0-4 character fetch (L) that
  1466. # is transparently translated into an integer.
  1467. value, data = 0, operator.immediateBytes
  1468. for i in range(2, operator.width // 8):
  1469. value = (value << 8) | data[i]
  1470. return value
  1471. if not (AwlOperatorWidths.makeMask(operator.width) & allowedWidths):
  1472. self.__fetchWidthError(operator, allowedWidths)
  1473. return operator.immediateBytes
  1474. def __fetchDBLG(self, operator, allowedWidths): #@nocy
  1475. #@cy cdef object __fetchDBLG(self, AwlOperator operator, uint32_t allowedWidths):
  1476. if not (AwlOperatorWidths.makeMask(operator.width) & allowedWidths):
  1477. self.__fetchWidthError(operator, allowedWidths)
  1478. return self.dbRegister.struct.getSize()
  1479. def __fetchDBNO(self, operator, allowedWidths): #@nocy
  1480. #@cy cdef object __fetchDBNO(self, AwlOperator operator, uint32_t allowedWidths):
  1481. if not (AwlOperatorWidths.makeMask(operator.width) & allowedWidths):
  1482. self.__fetchWidthError(operator, allowedWidths)
  1483. return self.dbRegister.index
  1484. def __fetchDILG(self, operator, allowedWidths): #@nocy
  1485. #@cy cdef object __fetchDILG(self, AwlOperator operator, uint32_t allowedWidths):
  1486. if not (AwlOperatorWidths.makeMask(operator.width) & allowedWidths):
  1487. self.__fetchWidthError(operator, allowedWidths)
  1488. return self.diRegister.struct.getSize()
  1489. def __fetchDINO(self, operator, allowedWidths): #@nocy
  1490. #@cy cdef object __fetchDINO(self, AwlOperator operator, uint32_t allowedWidths):
  1491. if not (AwlOperatorWidths.makeMask(operator.width) & allowedWidths):
  1492. self.__fetchWidthError(operator, allowedWidths)
  1493. return self.diRegister.index
  1494. def __fetchAR2(self, operator, allowedWidths): #@nocy
  1495. #@cy cdef object __fetchAR2(self, AwlOperator operator, uint32_t allowedWidths):
  1496. if not (AwlOperatorWidths.makeMask(operator.width) & allowedWidths):
  1497. self.__fetchWidthError(operator, allowedWidths)
  1498. return self.getAR(2).get()
  1499. def __fetchSTW(self, operator, allowedWidths): #@nocy
  1500. #@cy cdef object __fetchSTW(self, AwlOperator operator, uint32_t allowedWidths):
  1501. if not (AwlOperatorWidths.makeMask(operator.width) & allowedWidths):
  1502. self.__fetchWidthError(operator, allowedWidths)
  1503. if operator.width == 1:
  1504. return self.statusWord.getByBitNumber(operator.offset.bitOffset)
  1505. elif operator.width == 16:
  1506. return self.statusWord.getWord()
  1507. else:
  1508. assert(0)
  1509. def __fetchSTW_Z(self, operator, allowedWidths): #@nocy
  1510. #@cy cdef object __fetchSTW_Z(self, AwlOperator operator, uint32_t allowedWidths):
  1511. if not (AwlOperatorWidths.makeMask(operator.width) & allowedWidths):
  1512. self.__fetchWidthError(operator, allowedWidths)
  1513. return (self.statusWord.A0 ^ 1) & (self.statusWord.A1 ^ 1)
  1514. def __fetchSTW_NZ(self, operator, allowedWidths): #@nocy
  1515. #@cy cdef object __fetchSTW_NZ(self, AwlOperator operator, uint32_t allowedWidths):
  1516. if not (AwlOperatorWidths.makeMask(operator.width) & allowedWidths):
  1517. self.__fetchWidthError(operator, allowedWidths)
  1518. return self.statusWord.A0 | self.statusWord.A1
  1519. def __fetchSTW_POS(self, operator, allowedWidths): #@nocy
  1520. #@cy cdef object __fetchSTW_POS(self, AwlOperator operator, uint32_t allowedWidths):
  1521. if not (AwlOperatorWidths.makeMask(operator.width) & allowedWidths):
  1522. self.__fetchWidthError(operator, allowedWidths)
  1523. return (self.statusWord.A0 ^ 1) & self.statusWord.A1
  1524. def __fetchSTW_NEG(self, operator, allowedWidths): #@nocy
  1525. #@cy cdef object __fetchSTW_NEG(self, AwlOperator operator, uint32_t allowedWidths):
  1526. if not (AwlOperatorWidths.makeMask(operator.width) & allowedWidths):
  1527. self.__fetchWidthError(operator, allowedWidths)
  1528. return self.statusWord.A0 & (self.statusWord.A1 ^ 1)
  1529. def __fetchSTW_POSZ(self, operator, allowedWidths): #@nocy
  1530. #@cy cdef object __fetchSTW_POSZ(self, AwlOperator operator, uint32_t allowedWidths):
  1531. if not (AwlOperatorWidths.makeMask(operator.width) & allowedWidths):
  1532. self.__fetchWidthError(operator, allowedWidths)
  1533. return self.statusWord.A0 ^ 1
  1534. def __fetchSTW_NEGZ(self, operator, allowedWidths): #@nocy
  1535. #@cy cdef object __fetchSTW_NEGZ(self, AwlOperator operator, uint32_t allowedWidths):
  1536. if not (AwlOperatorWidths.makeMask(operator.width) & allowedWidths):
  1537. self.__fetchWidthError(operator, allowedWidths)
  1538. return self.statusWord.A1 ^ 1
  1539. def __fetchSTW_UO(self, operator, allowedWidths): #@nocy
  1540. #@cy cdef object __fetchSTW_UO(self, AwlOperator operator, uint32_t allowedWidths):
  1541. if not (AwlOperatorWidths.makeMask(operator.width) & allowedWidths):
  1542. self.__fetchWidthError(operator, allowedWidths)
  1543. return self.statusWord.A0 & self.statusWord.A1
  1544. def __fetchE(self, operator, allowedWidths): #@nocy
  1545. #@cy cdef object __fetchE(self, AwlOperator operator, uint32_t allowedWidths):
  1546. if not (AwlOperatorWidths.makeMask(operator.width) & allowedWidths):
  1547. self.__fetchWidthError(operator, allowedWidths)
  1548. return self.inputs.fetch(operator.offset, operator.width)
  1549. def __fetchA(self, operator, allowedWidths): #@nocy
  1550. #@cy cdef object __fetchA(self, AwlOperator operator, uint32_t allowedWidths):
  1551. if not (AwlOperatorWidths.makeMask(operator.width) & allowedWidths):
  1552. self.__fetchWidthError(operator, allowedWidths)
  1553. return self.outputs.fetch(operator.offset, operator.width)
  1554. def __fetchM(self, operator, allowedWidths): #@nocy
  1555. #@cy cdef object __fetchM(self, AwlOperator operator, uint32_t allowedWidths):
  1556. if not (AwlOperatorWidths.makeMask(operator.width) & allowedWidths):
  1557. self.__fetchWidthError(operator, allowedWidths)
  1558. return self.flags.fetch(operator.offset, operator.width)
  1559. def __fetchL(self, operator, allowedWidths): #@nocy
  1560. #@cy cdef object __fetchL(self, AwlOperator operator, uint32_t allowedWidths):
  1561. #@cy cdef LStackAllocator lstack
  1562. if not (AwlOperatorWidths.makeMask(operator.width) & allowedWidths):
  1563. self.__fetchWidthError(operator, allowedWidths)
  1564. lstack = self.activeLStack
  1565. return lstack.memory.fetch(lstack.topFrameOffset + operator.offset,
  1566. operator.width)
  1567. def __fetchVL(self, operator, allowedWidths): #@nocy
  1568. #@cy cdef object __fetchVL(self, AwlOperator operator, uint32_t allowedWidths):
  1569. #@cy cdef CallStackElem cse
  1570. #@cy cdef LStackAllocator lstack
  1571. #@cy cdef LStackFrame *prevFrame
  1572. if not (AwlOperatorWidths.makeMask(operator.width) & allowedWidths):
  1573. self.__fetchWidthError(operator, allowedWidths)
  1574. lstack = self.activeLStack
  1575. prevFrame = lstack.topFrame.prevFrame
  1576. if not prevFrame:
  1577. raise AwlSimError("Fetch of parent localstack, "
  1578. "but no parent present.")
  1579. return lstack.memory.fetch(make_AwlOffset(prevFrame.byteOffset, 0) + operator.offset,
  1580. operator.width)
  1581. def __fetchDB(self, operator, allowedWidths): #@nocy
  1582. #@cy cdef object __fetchDB(self, AwlOperator operator, uint32_t allowedWidths):
  1583. #@cy cdef int32_t dbNumber
  1584. if not (AwlOperatorWidths.makeMask(operator.width) & allowedWidths):
  1585. self.__fetchWidthError(operator, allowedWidths)
  1586. dbNumber = operator.offset.dbNumber
  1587. if dbNumber >= 0:
  1588. # This is a fully qualified access (DBx.DBx X)
  1589. # Open the data block first.
  1590. self.openDB(dbNumber, False)
  1591. return self.dbRegister.fetch(operator, None)
  1592. def __fetchDI(self, operator, allowedWidths): #@nocy
  1593. #@cy cdef object __fetchDI(self, AwlOperator operator, uint32_t allowedWidths):
  1594. if not (AwlOperatorWidths.makeMask(operator.width) & allowedWidths):
  1595. self.__fetchWidthError(operator, allowedWidths)
  1596. if self.callStackTop.block.isFB:
  1597. # Fetch the data using the multi-instance base offset from AR2.
  1598. return self.diRegister.fetch(operator,
  1599. make_AwlOffset_fromPointerValue(self.ar2.get()))
  1600. # Fetch without base offset.
  1601. return self.diRegister.fetch(operator, None)
  1602. def __fetchPE(self, operator, allowedWidths): #@nocy
  1603. #@cy cdef object __fetchPE(self, AwlOperator operator, uint32_t allowedWidths):
  1604. #@cy cdef bytearray readBytes
  1605. #@cy cdef uint32_t readValue
  1606. #@cy cdef uint32_t bitWidth
  1607. #@cy cdef AwlOffset operatorOffset
  1608. bitWidth = operator.width
  1609. if not (AwlOperatorWidths.makeMask(bitWidth) & allowedWidths):
  1610. self.__fetchWidthError(operator, allowedWidths)
  1611. operatorOffset = operator.offset
  1612. # Fetch the data from the peripheral device.
  1613. readBytes = self.cbPeripheralRead(self.cbPeripheralReadData,
  1614. bitWidth,
  1615. operatorOffset.byteOffset)
  1616. if not readBytes:
  1617. raise AwlSimError("There is no hardware to handle "
  1618. "the direct peripheral fetch. "
  1619. "(width=%d, offset=%d)" %\
  1620. (bitWidth, operatorOffset.byteOffset))
  1621. readValue = WordPacker.fromBytes(readBytes, bitWidth)
  1622. # Store the data to the process image, if it is within the inputs range.
  1623. if operatorOffset.toLongBitOffset() + bitWidth < self.specs.nrInputs * 8:
  1624. self.inputs.store(operatorOffset, bitWidth, readValue)
  1625. return readValue
  1626. def __fetchT(self, operator, allowedWidths): #@nocy
  1627. #@cy cdef object __fetchT(self, AwlOperator operator, uint32_t allowedWidths):
  1628. #@cy cdef uint32_t insnType
  1629. #@cy cdef uint32_t width
  1630. insnType = operator.insn.insnType
  1631. if insnType == AwlInsn.TYPE_L or insnType == AwlInsn.TYPE_LC:
  1632. width = 32
  1633. else:
  1634. width = 1
  1635. if not (AwlOperatorWidths.makeMask(width) & allowedWidths):
  1636. self.__fetchWidthError(operator, allowedWidths)
  1637. timer = self.getTimer(operator.offset.byteOffset)
  1638. if insnType == AwlInsn.TYPE_L:
  1639. return timer.getTimevalBin()
  1640. elif insnType == AwlInsn.TYPE_LC:
  1641. return timer.getTimevalS5T()
  1642. return timer.get()
  1643. def __fetchZ(self, operator, allowedWidths): #@nocy
  1644. #@cy cdef object __fetchZ(self, AwlOperator operator, uint32_t allowedWidths):
  1645. #@cy cdef uint32_t insnType
  1646. #@cy cdef uint32_t width
  1647. insnType = operator.insn.insnType
  1648. if insnType == AwlInsn.TYPE_L or insnType == AwlInsn.TYPE_LC:
  1649. width = 32
  1650. else:
  1651. width = 1
  1652. if not (AwlOperatorWidths.makeMask(width) & allowedWidths):
  1653. self.__fetchWidthError(operator, allowedWidths)
  1654. counter = self.getCounter(operator.offset.byteOffset)
  1655. if insnType == AwlInsn.TYPE_L:
  1656. return counter.getValueBin()
  1657. elif insnType == AwlInsn.TYPE_LC:
  1658. return counter.getValueBCD()
  1659. return counter.get()
  1660. def __fetchNAMED_LOCAL(self, operator, allowedWidths): #@nocy
  1661. #@cy cdef object __fetchNAMED_LOCAL(self, AwlOperator operator, uint32_t allowedWidths):
  1662. # load from an FC interface field.
  1663. return self.fetch(self.__translateFCNamedLocalOper(operator, False),
  1664. allowedWidths)
  1665. def __fetchNAMED_LOCAL_PTR(self, operator, allowedWidths): #@nocy
  1666. #@cy cdef object __fetchNAMED_LOCAL_PTR(self, AwlOperator operator, uint32_t allowedWidths):
  1667. assert(operator.offset.subOffset is None) #@nocy
  1668. return self.callStackTop.getInterfIdxOper(operator.interfaceIndex).resolve(False).makePointerValue()
  1669. def __fetchNAMED_DBVAR(self, operator, allowedWidths): #@nocy
  1670. #@cy cdef object __fetchNAMED_DBVAR(self, AwlOperator operator, uint32_t allowedWidths):
  1671. # All legit accesses will have been translated to absolute addressing already
  1672. raise AwlSimError("Fully qualified load from DB variable "
  1673. "is not supported in this place.")
  1674. def __fetchINDIRECT(self, operator, allowedWidths): #@nocy
  1675. #@cy cdef object __fetchINDIRECT(self, AwlOperator operator, uint32_t allowedWidths):
  1676. return self.fetch(operator.resolve(False), allowedWidths)
  1677. def __fetchVirtACCU(self, operator, allowedWidths): #@nocy
  1678. #@cy cdef object __fetchVirtACCU(self, AwlOperator operator, uint32_t allowedWidths):
  1679. if not (AwlOperatorWidths.makeMask(operator.width) & allowedWidths):
  1680. self.__fetchWidthError(operator, allowedWidths)
  1681. return self.getAccu(operator.offset.byteOffset).get()
  1682. def __fetchVirtAR(self, operator, allowedWidths): #@nocy
  1683. #@cy cdef object __fetchVirtAR(self, AwlOperator operator, uint32_t allowedWidths):
  1684. if not (AwlOperatorWidths.makeMask(operator.width) & allowedWidths):
  1685. self.__fetchWidthError(operator, allowedWidths)
  1686. return self.getAR(operator.offset.byteOffset).get()
  1687. def __fetchVirtDBR(self, operator, allowedWidths): #@nocy
  1688. #@cy cdef object __fetchVirtDBR(self, AwlOperator operator, uint32_t allowedWidths):
  1689. if not (AwlOperatorWidths.makeMask(operator.width) & allowedWidths):
  1690. self.__fetchWidthError(operator, allowedWidths)
  1691. if operator.offset.byteOffset == 1:
  1692. if self.dbRegister:
  1693. return self.dbRegister.index
  1694. elif operator.offset.byteOffset == 2:
  1695. if self.diRegister:
  1696. return self.diRegister.index
  1697. else:
  1698. raise AwlSimError("Invalid __DBR %d. "
  1699. "Must be 1 for DB-register or "
  1700. "2 for DI-register." %\
  1701. operator.offset.byteOffset)
  1702. return 0
  1703. __fetchTypeMethodsDict = { #@nocy
  1704. AwlOperatorTypes.IMM : __fetchIMM, #@nocy
  1705. AwlOperatorTypes.IMM_REAL : __fetchIMM, #@nocy
  1706. AwlOperatorTypes.IMM_S5T : __fetchIMM, #@nocy
  1707. AwlOperatorTypes.IMM_TIME : __fetchIMM, #@nocy
  1708. AwlOperatorTypes.IMM_DATE : __fetchIMM, #@nocy
  1709. AwlOperatorTypes.IMM_DT : __fetchIMM_DT, #@nocy
  1710. AwlOperatorTypes.IMM_TOD : __fetchIMM, #@nocy
  1711. AwlOperatorTypes.IMM_PTR : __fetchIMM_PTR, #@nocy
  1712. AwlOperatorTypes.IMM_STR : __fetchIMM_STR, #@nocy
  1713. AwlOperatorTypes.MEM_E : __fetchE, #@nocy
  1714. AwlOperatorTypes.MEM_A : __fetchA, #@nocy
  1715. AwlOperatorTypes.MEM_M : __fetchM, #@nocy
  1716. AwlOperatorTypes.MEM_L : __fetchL, #@nocy
  1717. AwlOperatorTypes.MEM_VL : __fetchVL, #@nocy
  1718. AwlOperatorTypes.MEM_DB : __fetchDB, #@nocy
  1719. AwlOperatorTypes.MEM_DI : __fetchDI, #@nocy
  1720. AwlOperatorTypes.MEM_T : __fetchT, #@nocy
  1721. AwlOperatorTypes.MEM_Z : __fetchZ, #@nocy
  1722. AwlOperatorTypes.MEM_PE : __fetchPE, #@nocy
  1723. AwlOperatorTypes.MEM_DBLG : __fetchDBLG, #@nocy
  1724. AwlOperatorTypes.MEM_DBNO : __fetchDBNO, #@nocy
  1725. AwlOperatorTypes.MEM_DILG : __fetchDILG, #@nocy
  1726. AwlOperatorTypes.MEM_DINO : __fetchDINO, #@nocy
  1727. AwlOperatorTypes.MEM_AR2 : __fetchAR2, #@nocy
  1728. AwlOperatorTypes.MEM_STW : __fetchSTW, #@nocy
  1729. AwlOperatorTypes.MEM_STW_Z : __fetchSTW_Z, #@nocy
  1730. AwlOperatorTypes.MEM_STW_NZ : __fetchSTW_NZ, #@nocy
  1731. AwlOperatorTypes.MEM_STW_POS : __fetchSTW_POS, #@nocy
  1732. AwlOperatorTypes.MEM_STW_NEG : __fetchSTW_NEG, #@nocy
  1733. AwlOperatorTypes.MEM_STW_POSZ : __fetchSTW_POSZ, #@nocy
  1734. AwlOperatorTypes.MEM_STW_NEGZ : __fetchSTW_NEGZ, #@nocy
  1735. AwlOperatorTypes.MEM_STW_UO : __fetchSTW_UO, #@nocy
  1736. AwlOperatorTypes.NAMED_LOCAL : __fetchNAMED_LOCAL, #@nocy
  1737. AwlOperatorTypes.NAMED_LOCAL_PTR : __fetchNAMED_LOCAL_PTR, #@nocy
  1738. AwlOperatorTypes.NAMED_DBVAR : __fetchNAMED_DBVAR, #@nocy
  1739. AwlOperatorTypes.INDIRECT : __fetchINDIRECT, #@nocy
  1740. AwlOperatorTypes.VIRT_ACCU : __fetchVirtACCU, #@nocy
  1741. AwlOperatorTypes.VIRT_AR : __fetchVirtAR, #@nocy
  1742. AwlOperatorTypes.VIRT_DBR : __fetchVirtDBR, #@nocy
  1743. } #@nocy
  1744. def store(self, operator, value, allowedWidths): #@nocy
  1745. try: #@nocy
  1746. storeMethod = self.__storeTypeMethods[operator.operType] #@nocy
  1747. except KeyError: #@nocy
  1748. self.__invalidStore(operator) #@nocy
  1749. storeMethod(self, operator, value, allowedWidths) #@nocy
  1750. #@cy cpdef store(self, AwlOperator operator, object value, uint32_t allowedWidths):
  1751. #@cy cdef uint32_t operType
  1752. #@cy
  1753. #@cy operType = operator.operType
  1754. #@cy if operType == AwlOperatorTypes.MEM_E:
  1755. #@cy self.__storeE(operator, value, allowedWidths)
  1756. #@cy elif operType == AwlOperatorTypes.MEM_A:
  1757. #@cy self.__storeA(operator, value, allowedWidths)
  1758. #@cy elif operType == AwlOperatorTypes.MEM_M:
  1759. #@cy self.__storeM(operator, value, allowedWidths)
  1760. #@cy elif operType == AwlOperatorTypes.MEM_L:
  1761. #@cy self.__storeL(operator, value, allowedWidths)
  1762. #@cy elif operType == AwlOperatorTypes.MEM_VL:
  1763. #@cy self.__storeVL(operator, value, allowedWidths)
  1764. #@cy elif operType == AwlOperatorTypes.MEM_DB:
  1765. #@cy self.__storeDB(operator, value, allowedWidths)
  1766. #@cy elif operType == AwlOperatorTypes.MEM_DI:
  1767. #@cy self.__storeDI(operator, value, allowedWidths)
  1768. #@cy elif operType == AwlOperatorTypes.MEM_PA:
  1769. #@cy self.__storePA(operator, value, allowedWidths)
  1770. #@cy elif operType == AwlOperatorTypes.MEM_AR2:
  1771. #@cy self.__storeAR2(operator, value, allowedWidths)
  1772. #@cy elif operType == AwlOperatorTypes.MEM_STW:
  1773. #@cy self.__storeSTW(operator, value, allowedWidths)
  1774. #@cy elif operType == AwlOperatorTypes.NAMED_LOCAL:
  1775. #@cy self.__storeNAMED_LOCAL(operator, value, allowedWidths)
  1776. #@cy elif operType == AwlOperatorTypes.NAMED_DBVAR:
  1777. #@cy self.__storeNAMED_DBVAR(operator, value, allowedWidths)
  1778. #@cy elif operType == AwlOperatorTypes.INDIRECT:
  1779. #@cy self.__storeINDIRECT(operator, value, allowedWidths)
  1780. #@cy else:
  1781. #@cy self.__invalidStore(operator)
  1782. def __invalidStore(self, operator):
  1783. raise AwlSimError("Invalid store request: %s" % str(operator))
  1784. def __storeWidthError(self, operator, allowedWidths):
  1785. raise AwlSimError("Data store of %d bits, "
  1786. "but only %s bits are allowed." %\
  1787. (operator.width,
  1788. listToHumanStr(AwlOperatorWidths.maskToList(allowedWidths))))
  1789. def __storeE(self, operator, value, allowedWidths): #@nocy
  1790. #@cy cdef __storeE(self, AwlOperator operator, object value, uint32_t allowedWidths):
  1791. if not (AwlOperatorWidths.makeMask(operator.width) & allowedWidths):
  1792. self.__storeWidthError(operator, allowedWidths)
  1793. self.inputs.store(operator.offset, operator.width, value)
  1794. def __storeA(self, operator, value, allowedWidths): #@nocy
  1795. #@cy cdef __storeA(self, AwlOperator operator, object value, uint32_t allowedWidths):
  1796. if not (AwlOperatorWidths.makeMask(operator.width) & allowedWidths):
  1797. self.__storeWidthError(operator, allowedWidths)
  1798. self.outputs.store(operator.offset, operator.width, value)
  1799. def __storeM(self, operator, value, allowedWidths): #@nocy
  1800. #@cy cdef __storeM(self, AwlOperator operator, object value, uint32_t allowedWidths):
  1801. if not (AwlOperatorWidths.makeMask(operator.width) & allowedWidths):
  1802. self.__storeWidthError(operator, allowedWidths)
  1803. self.flags.store(operator.offset, operator.width, value)
  1804. def __storeL(self, operator, value, allowedWidths): #@nocy
  1805. #@cy cdef __storeL(self, AwlOperator operator, object value, uint32_t allowedWidths):
  1806. #@cy cdef LStackAllocator lstack
  1807. if not (AwlOperatorWidths.makeMask(operator.width) & allowedWidths):
  1808. self.__storeWidthError(operator, allowedWidths)
  1809. lstack = self.activeLStack
  1810. lstack.memory.store(lstack.topFrameOffset + operator.offset,
  1811. operator.width,
  1812. value)
  1813. def __storeVL(self, operator, value, allowedWidths): #@nocy
  1814. #@cy cdef __storeVL(self, AwlOperator operator, object value, uint32_t allowedWidths):
  1815. #@cy cdef CallStackElem cse
  1816. #@cy cdef LStackFrame *prevFrame
  1817. if not (AwlOperatorWidths.makeMask(operator.width) & allowedWidths):
  1818. self.__storeWidthError(operator, allowedWidths)
  1819. lstack = self.activeLStack
  1820. prevFrame = lstack.topFrame.prevFrame
  1821. if not prevFrame:
  1822. raise AwlSimError("Store to parent localstack, "
  1823. "but no parent present.")
  1824. lstack.memory.store(make_AwlOffset(prevFrame.byteOffset, 0) + operator.offset,
  1825. operator.width,
  1826. value)
  1827. def __storeDB(self, operator, value, allowedWidths): #@nocy
  1828. #@cy cdef __storeDB(self, AwlOperator operator, object value, uint32_t allowedWidths):
  1829. #@cy cdef DB db
  1830. #@cy cdef int32_t dbNumber
  1831. if not (AwlOperatorWidths.makeMask(operator.width) & allowedWidths):
  1832. self.__storeWidthError(operator, allowedWidths)
  1833. dbNumber = operator.offset.dbNumber
  1834. if dbNumber < 0:
  1835. db = self.dbRegister
  1836. else:
  1837. try:
  1838. db = self.dbs[dbNumber]
  1839. except KeyError:
  1840. raise AwlSimError("Store to DB %d, but DB "
  1841. "does not exist" % dbNumber)
  1842. db.store(operator, value, None)
  1843. def __storeDI(self, operator, value, allowedWidths): #@nocy
  1844. #@cy cdef __storeDI(self, AwlOperator operator, object value, uint32_t allowedWidths):
  1845. if not (AwlOperatorWidths.makeMask(operator.width) & allowedWidths):
  1846. self.__storeWidthError(operator, allowedWidths)
  1847. if self.callStackTop.block.isFB:
  1848. # Store the data using the multi-instance base offset from AR2.
  1849. self.diRegister.store(operator, value,
  1850. make_AwlOffset_fromPointerValue(self.ar2.get()))
  1851. else:
  1852. # Store without base offset.
  1853. self.diRegister.store(operator, value, None)
  1854. def __storePA(self, operator, value, allowedWidths): #@nocy
  1855. #@cy cdef __storePA(self, AwlOperator operator, object value, uint32_t allowedWidths):
  1856. #@cy cdef _Bool ok
  1857. #@cy cdef uint32_t bitWidth
  1858. #@cy cdef bytearray valueBytes
  1859. #@cy cdef AwlOffset operatorOffset
  1860. bitWidth = operator.width
  1861. if not (AwlOperatorWidths.makeMask(bitWidth) & allowedWidths):
  1862. self.__storeWidthError(operator, allowedWidths)
  1863. operatorOffset = operator.offset
  1864. # Store the data to the process image, if it is within the outputs range.
  1865. if operatorOffset.toLongBitOffset() + bitWidth < self.specs.nrOutputs * 8:
  1866. self.outputs.store(operatorOffset, bitWidth, value)
  1867. # Store the data to the peripheral device.
  1868. valueBytes = bytearray(bitWidth // 8)
  1869. WordPacker.toBytes(valueBytes, bitWidth, 0, value)
  1870. ok = self.cbPeripheralWrite(self.cbPeripheralWriteData,
  1871. bitWidth,
  1872. operatorOffset.byteOffset,
  1873. valueBytes)
  1874. if not ok:
  1875. raise AwlSimError("There is no hardware to handle "
  1876. "the direct peripheral store. "
  1877. "(width=%d, offset=%d, value=0x%X)" %\
  1878. (bitWidth, operatorOffset.byteOffset,
  1879. value))
  1880. def __storeAR2(self, operator, value, allowedWidths): #@nocy
  1881. #@cy cdef __storeAR2(self, AwlOperator operator, object value, uint32_t allowedWidths):
  1882. if not (AwlOperatorWidths.makeMask(operator.width) & allowedWidths):
  1883. self.__storeWidthError(operator, allowedWidths)
  1884. self.getAR(2).set(value)
  1885. def __storeSTW(self, operator, value, allowedWidths): #@nocy
  1886. #@cy cdef __storeSTW(self, AwlOperator operator, object value, uint32_t allowedWidths):
  1887. if not (AwlOperatorWidths.makeMask(operator.width) & allowedWidths):
  1888. self.__storeWidthError(operator, allowedWidths)
  1889. if operator.width == 1:
  1890. raise AwlSimError("Cannot store to individual STW bits")
  1891. elif operator.width == 16:
  1892. self.statusWord.setWord(value)
  1893. else:
  1894. assert(0)
  1895. def __storeNAMED_LOCAL(self, operator, value, allowedWidths): #@nocy
  1896. #@cy cdef __storeNAMED_LOCAL(self, AwlOperator operator, object value, uint32_t allowedWidths):
  1897. # store to an FC interface field.
  1898. self.store(self.__translateFCNamedLocalOper(operator, True),
  1899. value, allowedWidths)
  1900. def __storeNAMED_DBVAR(self, operator, value, allowedWidths): #@nocy
  1901. #@cy cdef __storeNAMED_DBVAR(self, AwlOperator operator, object value, uint32_t allowedWidths):
  1902. # All legit accesses will have been translated to absolute addressing already
  1903. raise AwlSimError("Fully qualified store to DB variable "
  1904. "is not supported in this place.")
  1905. def __storeINDIRECT(self, operator, value, allowedWidths): #@nocy
  1906. #@cy cdef __storeINDIRECT(self, AwlOperator operator, object value, uint32_t allowedWidths):
  1907. self.store(operator.resolve(True), value, allowedWidths)
  1908. __storeTypeMethodsDict = { #@nocy
  1909. AwlOperatorTypes.MEM_E : __storeE, #@nocy
  1910. AwlOperatorTypes.MEM_A : __storeA, #@nocy
  1911. AwlOperatorTypes.MEM_M : __storeM, #@nocy
  1912. AwlOperatorTypes.MEM_L : __storeL, #@nocy
  1913. AwlOperatorTypes.MEM_VL : __storeVL, #@nocy
  1914. AwlOperatorTypes.MEM_DB : __storeDB, #@nocy
  1915. AwlOperatorTypes.MEM_DI : __storeDI, #@nocy
  1916. AwlOperatorTypes.MEM_PA : __storePA, #@nocy
  1917. AwlOperatorTypes.MEM_AR2 : __storeAR2, #@nocy
  1918. AwlOperatorTypes.MEM_STW : __storeSTW, #@nocy
  1919. AwlOperatorTypes.NAMED_LOCAL : __storeNAMED_LOCAL, #@nocy
  1920. AwlOperatorTypes.NAMED_DBVAR : __storeNAMED_DBVAR, #@nocy
  1921. AwlOperatorTypes.INDIRECT : __storeINDIRECT, #@nocy
  1922. } #@nocy
  1923. def __dumpMem(self, prefix, memory, byteOffset, maxLen):
  1924. if not memory or not memory.dataBytes or maxLen <= 0:
  1925. return prefix + "--"
  1926. memArray = memory.dataBytes
  1927. ret, line, first, count, i = [], [], True, 0, byteOffset
  1928. def append(line):
  1929. ret.append((prefix if first else (' ' * len(prefix))) +\
  1930. ' '.join(line))
  1931. end = maxLen + byteOffset
  1932. while i < end:
  1933. line.append("%02X" % memArray[i])
  1934. count += 1
  1935. if count >= 16:
  1936. append(line)
  1937. line, count, first = [], 0, False
  1938. i += 1
  1939. if count:
  1940. append(line)
  1941. return '\n'.join(ret)
  1942. def __dumpLStackFrame(self, prefix, frame): #@nocy
  1943. #@cy cdef __dumpLStackFrame(self, prefix, LStackFrame *frame):
  1944. if frame:
  1945. memory = self.activeLStack.memory
  1946. byteOffset = frame.byteOffset
  1947. allocBits = frame.allocBits
  1948. else:
  1949. memory, byteOffset, allocBits = None, 0, 0
  1950. return self.__dumpMem(prefix,
  1951. memory,
  1952. byteOffset,
  1953. min(64, intDivRoundUp(allocBits, 8)))
  1954. def dump(self, withTime=True):
  1955. #@cy cdef LStackFrame *frame
  1956. callStackTop = self.callStackTop
  1957. if not callStackTop:
  1958. return ""
  1959. mnemonics = self.getMnemonics()
  1960. isEnglish = (mnemonics == S7CPUConfig.MNEMONICS_EN)
  1961. specs = self.specs
  1962. self.updateTimestamp()
  1963. ret = []
  1964. ret.append("[S7-CPU] t: %.01fs %s / py %d compat / %s / v%s" %\
  1965. ((self.now - self.startupTime) if withTime else 0.0,
  1966. pythonInterpreter,
  1967. 3 if isPy3Compat else 2,
  1968. "Win" if osIsWindows else ("Posix" if osIsPosix else "unknown"),
  1969. VERSION_STRING))
  1970. ret.append(" STW: " + self.statusWord.getString(mnemonics))
  1971. if self.is4accu:
  1972. accus = ( accu.toHex()
  1973. for accu in (self.accu1, self.accu2,
  1974. self.accu3, self.accu4) )
  1975. else:
  1976. accus = ( accu.toHex()
  1977. for accu in (self.accu1, self.accu2) )
  1978. ret.append(" Accu: " + " ".join(accus))
  1979. ars = ( "%s (%s)" % (ar.toHex(), ar.toPointerString())
  1980. for ar in (self.ar1, self.ar2) )
  1981. ret.append(" AR: " + " ".join(ars))
  1982. ret.append(self.__dumpMem(" M: ",
  1983. self.flags, 0,
  1984. min(64, specs.nrFlags)))
  1985. prefix = " I: " if isEnglish else " E: "
  1986. ret.append(self.__dumpMem(prefix,
  1987. self.inputs, 0,
  1988. min(64, specs.nrInputs)))
  1989. prefix = " Q: " if isEnglish else " A: "
  1990. ret.append(self.__dumpMem(prefix,
  1991. self.outputs, 0,
  1992. min(64, specs.nrOutputs)))
  1993. pstack = str(callStackTop.parenStack) if callStackTop.parenStack else "--"
  1994. ret.append(" PStack: " + pstack)
  1995. ret.append(" DBreg: %s %s" % (str(self.dbRegister),
  1996. str(self.diRegister).replace("DB", "DI")))
  1997. if callStackTop:
  1998. elemsMax, elemsCount, elems, cse =\
  1999. 8, 0, [], callStackTop
  2000. while cse is not None:
  2001. elemsCount += 1
  2002. elems.insert(0, cse.block)
  2003. cse = cse.prevCse
  2004. assert(elemsCount == self.callStackDepth)
  2005. ret.append(" Calls: (%d) %s%s" %\
  2006. (elemsCount, " -> ".join(str(e) for e in elems[:elemsMax]),
  2007. " -> ..." if len(elems) > elemsMax else ""))
  2008. frame = self.activeLStack.topFrame
  2009. ret.append(self.__dumpLStackFrame(" L: ", frame))
  2010. frame = frame.prevFrame if frame else None #@cy-NoneToNULL
  2011. ret.append(self.__dumpLStackFrame(" VL: ", frame))
  2012. else:
  2013. ret.append(" Calls: None")
  2014. curInsn = self.getCurrentInsn()
  2015. ret.append(" Stmt: IP:%s %s" %\
  2016. (str(self.getCurrentIP()),
  2017. str(curInsn) if curInsn else "none"))
  2018. ret.append(" Speed: %s stmt/s (= %s us/stmt) %.01f stmt/cycle" % (
  2019. self.insnPerSecondHR,
  2020. self.usPerInsnHR,
  2021. self.avgInsnPerCycle))
  2022. avgCycleTime = self.avgCycleTime
  2023. minCycleTime = self.minCycleTime
  2024. maxCycleTime = self.maxCycleTime
  2025. if maxCycleTime == 0.0:
  2026. avgCycleTimeStr = minCycleTimeStr = maxCycleTimeStr = "-/-"
  2027. else:
  2028. if avgCycleTime == 0.0:
  2029. avgCycleTimeStr = "-/-"
  2030. else:
  2031. avgCycleTimeStr = "%.03f" % (self.avgCycleTime * 1000.0)
  2032. minCycleTimeStr = "%.03f" % (self.minCycleTime * 1000.0)
  2033. maxCycleTimeStr = "%.03f" % (self.maxCycleTime * 1000.0)
  2034. ret.append("OB1time: avg: %s ms min: %s ms max: %s ms" % (
  2035. avgCycleTimeStr, minCycleTimeStr, maxCycleTimeStr))
  2036. return '\n'.join(ret)
  2037. @property
  2038. def insnPerSecondHR(self):
  2039. """Get a human readable instructions per seconds string.
  2040. """
  2041. insnPerSecond = self.insnPerSecond
  2042. if insnPerSecond >= 1000000.0:
  2043. insnPerSecondStr = "%.02f M" % (insnPerSecond / 1000000.0)
  2044. elif insnPerSecond >= 1000.0:
  2045. insnPerSecondStr = "%.02f k" % (insnPerSecond / 1000.0)
  2046. elif insnPerSecond > 0.0:
  2047. insnPerSecondStr = "%.02f" % insnPerSecond
  2048. else:
  2049. insnPerSecondStr = "-/-"
  2050. return insnPerSecondStr
  2051. @property
  2052. def usPerInsnHR(self):
  2053. """Get a human readable microseconds per instructions string.
  2054. """
  2055. insnPerSecond = self.insnPerSecond
  2056. if insnPerSecond > 0.0:
  2057. usPerInsnStr = "%.03f" % ((1.0 / insnPerSecond) * 1000000)
  2058. else:
  2059. usPerInsnStr = "-/-"
  2060. return usPerInsnStr
  2061. def __repr__(self):
  2062. return self.dump()