aboutsummaryrefslogtreecommitdiffstats
path: root/awlsim/core/instructions/main.py
blob: f1b539229a9679f1e3b49a6f287dae6466d140f6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
# -*- coding: utf-8 -*-
#
# AWL simulator - instructions
#
# Copyright 2012-2017 Michael Buesch <m@bues.ch>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#

from __future__ import division, absolute_import, print_function, unicode_literals
#from awlsim.common.cython_support cimport * #@cy
from awlsim.common.compat import *

from awlsim.common.cpuconfig import *
from awlsim.common.datatypehelpers import * #+cimport
from awlsim.common.exceptions import *
from awlsim.common.util import *

from awlsim.core.instructions.types import * #+cimport
from awlsim.core.instructions.parentinfo import *
from awlsim.core.operatortypes import * #+cimport
from awlsim.core.operators import * #+cimport

from awlsim.awlcompiler.optrans import *


class AwlInsn(object): #+cdef
	"""AWL instruction base class.
	"""

	TYPE_U			= AwlInsnTypes.TYPE_U
	TYPE_UN			= AwlInsnTypes.TYPE_UN
	TYPE_O			= AwlInsnTypes.TYPE_O
	TYPE_ON			= AwlInsnTypes.TYPE_ON
	TYPE_X			= AwlInsnTypes.TYPE_X
	TYPE_XN			= AwlInsnTypes.TYPE_XN
	TYPE_UB			= AwlInsnTypes.TYPE_UB
	TYPE_UNB		= AwlInsnTypes.TYPE_UNB
	TYPE_OB			= AwlInsnTypes.TYPE_OB
	TYPE_ONB		= AwlInsnTypes.TYPE_ONB
	TYPE_XB			= AwlInsnTypes.TYPE_XB
	TYPE_XNB		= AwlInsnTypes.TYPE_XNB
	TYPE_BEND		= AwlInsnTypes.TYPE_BEND
	TYPE_ASSIGN		= AwlInsnTypes.TYPE_ASSIGN
	TYPE_R			= AwlInsnTypes.TYPE_R
	TYPE_S			= AwlInsnTypes.TYPE_S
	TYPE_NOT		= AwlInsnTypes.TYPE_NOT
	TYPE_SET		= AwlInsnTypes.TYPE_SET
	TYPE_CLR		= AwlInsnTypes.TYPE_CLR
	TYPE_SAVE		= AwlInsnTypes.TYPE_SAVE
	TYPE_FN			= AwlInsnTypes.TYPE_FN
	TYPE_FP			= AwlInsnTypes.TYPE_FP
	TYPE_EQ_I		= AwlInsnTypes.TYPE_EQ_I
	TYPE_NE_I		= AwlInsnTypes.TYPE_NE_I
	TYPE_GT_I		= AwlInsnTypes.TYPE_GT_I
	TYPE_LT_I		= AwlInsnTypes.TYPE_LT_I
	TYPE_GE_I		= AwlInsnTypes.TYPE_GE_I
	TYPE_LE_I		= AwlInsnTypes.TYPE_LE_I
	TYPE_EQ_D		= AwlInsnTypes.TYPE_EQ_D
	TYPE_NE_D		= AwlInsnTypes.TYPE_NE_D
	TYPE_GT_D		= AwlInsnTypes.TYPE_GT_D
	TYPE_LT_D		= AwlInsnTypes.TYPE_LT_D
	TYPE_GE_D		= AwlInsnTypes.TYPE_GE_D
	TYPE_LE_D		= AwlInsnTypes.TYPE_LE_D
	TYPE_EQ_R		= AwlInsnTypes.TYPE_EQ_R
	TYPE_NE_R		= AwlInsnTypes.TYPE_NE_R
	TYPE_GT_R		= AwlInsnTypes.TYPE_GT_R
	TYPE_LT_R		= AwlInsnTypes.TYPE_LT_R
	TYPE_GE_R		= AwlInsnTypes.TYPE_GE_R
	TYPE_LE_R		= AwlInsnTypes.TYPE_LE_R
	TYPE_BTI		= AwlInsnTypes.TYPE_BTI
	TYPE_ITB		= AwlInsnTypes.TYPE_ITB
	TYPE_BTD		= AwlInsnTypes.TYPE_BTD
	TYPE_ITD		= AwlInsnTypes.TYPE_ITD
	TYPE_DTB		= AwlInsnTypes.TYPE_DTB
	TYPE_DTR		= AwlInsnTypes.TYPE_DTR
	TYPE_INVI		= AwlInsnTypes.TYPE_INVI
	TYPE_INVD		= AwlInsnTypes.TYPE_INVD
	TYPE_NEGI		= AwlInsnTypes.TYPE_NEGI
	TYPE_NEGD		= AwlInsnTypes.TYPE_NEGD
	TYPE_NEGR		= AwlInsnTypes.TYPE_NEGR
	TYPE_TAW		= AwlInsnTypes.TYPE_TAW
	TYPE_TAD		= AwlInsnTypes.TYPE_TAD
	TYPE_RND		= AwlInsnTypes.TYPE_RND
	TYPE_TRUNC		= AwlInsnTypes.TYPE_TRUNC
	TYPE_RNDP		= AwlInsnTypes.TYPE_RNDP
	TYPE_RNDN		= AwlInsnTypes.TYPE_RNDN
	TYPE_FR			= AwlInsnTypes.TYPE_FR
	TYPE_L			= AwlInsnTypes.TYPE_L
	TYPE_LC			= AwlInsnTypes.TYPE_LC
	TYPE_ZV			= AwlInsnTypes.TYPE_ZV
	TYPE_ZR			= AwlInsnTypes.TYPE_ZR
	TYPE_AUF		= AwlInsnTypes.TYPE_AUF
	TYPE_TDB		= AwlInsnTypes.TYPE_TDB
	TYPE_SPA		= AwlInsnTypes.TYPE_SPA
	TYPE_SPL		= AwlInsnTypes.TYPE_SPL
	TYPE_SPB		= AwlInsnTypes.TYPE_SPB
	TYPE_SPBN		= AwlInsnTypes.TYPE_SPBN
	TYPE_SPBB		= AwlInsnTypes.TYPE_SPBB
	TYPE_SPBNB		= AwlInsnTypes.TYPE_SPBNB
	TYPE_SPBI		= AwlInsnTypes.TYPE_SPBI
	TYPE_SPBIN		= AwlInsnTypes.TYPE_SPBIN
	TYPE_SPO		= AwlInsnTypes.TYPE_SPO
	TYPE_SPS		= AwlInsnTypes.TYPE_SPS
	TYPE_SPZ		= AwlInsnTypes.TYPE_SPZ
	TYPE_SPN		= AwlInsnTypes.TYPE_SPN
	TYPE_SPP		= AwlInsnTypes.TYPE_SPP
	TYPE_SPM		= AwlInsnTypes.TYPE_SPM
	TYPE_SPPZ		= AwlInsnTypes.TYPE_SPPZ
	TYPE_SPMZ		= AwlInsnTypes.TYPE_SPMZ
	TYPE_SPU		= AwlInsnTypes.TYPE_SPU
	TYPE_LOOP		= AwlInsnTypes.TYPE_LOOP
	TYPE_PL_I		= AwlInsnTypes.TYPE_PL_I
	TYPE_MI_I		= AwlInsnTypes.TYPE_MI_I
	TYPE_MU_I		= AwlInsnTypes.TYPE_MU_I
	TYPE_DI_I		= AwlInsnTypes.TYPE_DI_I
	TYPE_PL			= AwlInsnTypes.TYPE_PL
	TYPE_PL_D		= AwlInsnTypes.TYPE_PL_D
	TYPE_MI_D		= AwlInsnTypes.TYPE_MI_D
	TYPE_MU_D		= AwlInsnTypes.TYPE_MU_D
	TYPE_DI_D		= AwlInsnTypes.TYPE_DI_D
	TYPE_MOD		= AwlInsnTypes.TYPE_MOD
	TYPE_PL_R		= AwlInsnTypes.TYPE_PL_R
	TYPE_MI_R		= AwlInsnTypes.TYPE_MI_R
	TYPE_MU_R		= AwlInsnTypes.TYPE_MU_R
	TYPE_DI_R		= AwlInsnTypes.TYPE_DI_R
	TYPE_ABS		= AwlInsnTypes.TYPE_ABS
	TYPE_SQR		= AwlInsnTypes.TYPE_SQR
	TYPE_SQRT		= AwlInsnTypes.TYPE_SQRT
	TYPE_EXP		= AwlInsnTypes.TYPE_EXP
	TYPE_LN			= AwlInsnTypes.TYPE_LN
	TYPE_SIN		= AwlInsnTypes.TYPE_SIN
	TYPE_COS		= AwlInsnTypes.TYPE_COS
	TYPE_TAN		= AwlInsnTypes.TYPE_TAN
	TYPE_ASIN		= AwlInsnTypes.TYPE_ASIN
	TYPE_ACOS		= AwlInsnTypes.TYPE_ACOS
	TYPE_ATAN		= AwlInsnTypes.TYPE_ATAN
	TYPE_LAR1		= AwlInsnTypes.TYPE_LAR1
	TYPE_LAR2		= AwlInsnTypes.TYPE_LAR2
	TYPE_T			= AwlInsnTypes.TYPE_T
	TYPE_TAR		= AwlInsnTypes.TYPE_TAR
	TYPE_TAR1		= AwlInsnTypes.TYPE_TAR1
	TYPE_TAR2		= AwlInsnTypes.TYPE_TAR2
	TYPE_BE			= AwlInsnTypes.TYPE_BE
	TYPE_BEB		= AwlInsnTypes.TYPE_BEB
	TYPE_BEA		= AwlInsnTypes.TYPE_BEA
	TYPE_CALL		= AwlInsnTypes.TYPE_CALL
	TYPE_CC			= AwlInsnTypes.TYPE_CC
	TYPE_UC			= AwlInsnTypes.TYPE_UC
	TYPE_MCRB		= AwlInsnTypes.TYPE_MCRB
	TYPE_BMCR		= AwlInsnTypes.TYPE_BMCR
	TYPE_MCRA		= AwlInsnTypes.TYPE_MCRA
	TYPE_MCRD		= AwlInsnTypes.TYPE_MCRD
	TYPE_SSI		= AwlInsnTypes.TYPE_SSI
	TYPE_SSD		= AwlInsnTypes.TYPE_SSD
	TYPE_SLW		= AwlInsnTypes.TYPE_SLW
	TYPE_SRW		= AwlInsnTypes.TYPE_SRW
	TYPE_SLD		= AwlInsnTypes.TYPE_SLD
	TYPE_SRD		= AwlInsnTypes.TYPE_SRD
	TYPE_RLD		= AwlInsnTypes.TYPE_RLD
	TYPE_RRD		= AwlInsnTypes.TYPE_RRD
	TYPE_RLDA		= AwlInsnTypes.TYPE_RLDA
	TYPE_RRDA		= AwlInsnTypes.TYPE_RRDA
	TYPE_SI			= AwlInsnTypes.TYPE_SI
	TYPE_SV			= AwlInsnTypes.TYPE_SV
	TYPE_SE			= AwlInsnTypes.TYPE_SE
	TYPE_SS			= AwlInsnTypes.TYPE_SS
	TYPE_SA			= AwlInsnTypes.TYPE_SA
	TYPE_UW			= AwlInsnTypes.TYPE_UW
	TYPE_OW			= AwlInsnTypes.TYPE_OW
	TYPE_XOW		= AwlInsnTypes.TYPE_XOW
	TYPE_UD			= AwlInsnTypes.TYPE_UD
	TYPE_OD			= AwlInsnTypes.TYPE_OD
	TYPE_XOD		= AwlInsnTypes.TYPE_XOD
	TYPE_TAK		= AwlInsnTypes.TYPE_TAK
	TYPE_PUSH		= AwlInsnTypes.TYPE_PUSH
	TYPE_POP		= AwlInsnTypes.TYPE_POP
	TYPE_ENT		= AwlInsnTypes.TYPE_ENT
	TYPE_LEAVE		= AwlInsnTypes.TYPE_LEAVE
	TYPE_INC		= AwlInsnTypes.TYPE_INC
	TYPE_DEC		= AwlInsnTypes.TYPE_DEC
	TYPE_INCAR1		= AwlInsnTypes.TYPE_INCAR1
	TYPE_INCAR2		= AwlInsnTypes.TYPE_INCAR2
	TYPE_BLD		= AwlInsnTypes.TYPE_BLD
	TYPE_NOP		= AwlInsnTypes.TYPE_NOP
	TYPE_EXTENDED		= AwlInsnTypes.TYPE_EXTENDED
	TYPE_ASSERT_EQ		= AwlInsnTypes.TYPE_ASSERT_EQ
	TYPE_ASSERT_EQ_R	= AwlInsnTypes.TYPE_ASSERT_EQ_R
	TYPE_ASSERT_NE		= AwlInsnTypes.TYPE_ASSERT_NE
	TYPE_ASSERT_GT		= AwlInsnTypes.TYPE_ASSERT_GT
	TYPE_ASSERT_LT		= AwlInsnTypes.TYPE_ASSERT_LT
	TYPE_ASSERT_GE		= AwlInsnTypes.TYPE_ASSERT_GE
	TYPE_ASSERT_LE		= AwlInsnTypes.TYPE_ASSERT_LE
	TYPE_SLEEP		= AwlInsnTypes.TYPE_SLEEP
	TYPE_STWRST		= AwlInsnTypes.TYPE_STWRST
	TYPE_FEATURE		= AwlInsnTypes.TYPE_FEATURE
	TYPE_GENERIC_CALL	= AwlInsnTypes.TYPE_GENERIC_CALL
	TYPE_INLINE_AWL		= AwlInsnTypes.TYPE_INLINE_AWL

	english2german = AwlInsnTypes.english2german
	german2english = AwlInsnTypes.german2english
	name2type_german = AwlInsnTypes.name2type_german
	type2name_german = AwlInsnTypes.type2name_german
	name2type_english = AwlInsnTypes.name2type_english
	type2name_english = AwlInsnTypes.type2name_english

	__slots__ = (
		"cpu",
		"insnType",
		"ip",
		"ops",
		"opCount",
		"op0",
		"op1",
		"params",
		"labelStr",
		"commentStr",
		"parentInfo",
		"_widths_1",
		"_widths_8_16_32",
		"_widths_16",
		"_widths_32",
		"_widths_scalar",
		"_widths_all",
	)

	def __init__(self, cpu, insnType, rawInsn=None, ops=None):
		"""Initialize base instruction.
		"""
		self.parentInfo = AwlInsnParentInfo()	# Parent information
		self.cpu = cpu				# S7CPU() or None
		self.insnType = insnType		# TYPE_...
		self.parentInfo.rawInsn = rawInsn	# RawAwlInsn() or None
		self.ip = 0				# Instruction pointer (IP)
		self.ops = ops or []			# AwlOperator()s
		self.params = ()			# Parameter assignments (for CALL)
		self.labelStr = None			# Optional label string.
		self.commentStr = ""			# Optional comment string.

		# Local copy of commonly used fetch/store widths.
		self._widths_1		= AwlOperatorWidths.WIDTH_MASK_1
		self._widths_8_16_32	= AwlOperatorWidths.WIDTH_MASK_8_16_32
		self._widths_16		= AwlOperatorWidths.WIDTH_MASK_16
		self._widths_32		= AwlOperatorWidths.WIDTH_MASK_32
		self._widths_scalar	= AwlOperatorWidths.WIDTH_MASK_SCALAR
		self._widths_all	= AwlOperatorWidths.WIDTH_MASK_ALL

		if rawInsn and ops is None:
			opTrans = AwlOpTranslator(self)
			opTrans.translateFromRawInsn(rawInsn)
		self.__setupOpQuickRef()

	def __setupOpQuickRef(self):
		# Add a quick reference to the first and the second operator.
		self.opCount = len(self.ops)
		if self.opCount >= 1:
			self.op0 = self.ops[0]
		if self.opCount >= 2:
			self.op1 = self.ops[1]

	def finalSetup(self):
		"""Run the final setup steps.
		This method has to be called before the
		instruction can be run for the first time.
		"""
		self.__setupOpQuickRef()

	def staticSanityChecks(self):
		"""Run static sanity checks.
		"""
		pass # Default: No sanity checks

	def assertOpCount(self, counts):
		"""Check whether we have the required operator count.
		counts is a list/set/int of possible counts.
		"""
		assert(self.opCount == len_u32(self.ops))
		counts = toList(counts)
		if self.opCount not in counts:
			raise AwlSimError("Invalid number of operators. "
				"Expected %s." % listToHumanStr(counts),
				insn=self)

	def getMnemonics(self):
		"""Return the MNEMONICS_... setting for this instruction.
		Returns None, if the mnemonics setting is unknown.
		"""
		if self.cpu:
			return self.cpu.getMnemonics()
		return None

	def getRawInsn(self):
		return self.parentInfo.rawInsn

	def hasLabel(self):
		"""Returns True, if this insn has a label.
		"""
		if self.labelStr is not None:
			return bool(self.labelStr)
		if self.parentInfo.rawInsn:
			return self.parentInfo.rawInsn.hasLabel()
		return False

	def getLabel(self):
		"""Returns the label string.
		"""
		if self.labelStr is not None:
			return self.labelStr
		if self.parentInfo.rawInsn:
			return self.parentInfo.rawInsn.getLabel()
		return None

	def setLabel(self, labelStr):
		self.labelStr = labelStr or ""

	def getIP(self):
		return self.ip

	def setIP(self, newIp):
		self.ip = newIp

	def getCpu(self):
		return self.cpu

	def getSourceId(self):
		if not self.parentInfo.rawInsn:
			return None
		return self.parentInfo.rawInsn.getSourceId()

	def getLineNr(self):
		if not self.parentInfo.rawInsn:
			return -1
		return self.parentInfo.rawInsn.getLineNr()

	def getParentInfo(self):
		return self.parentInfo

	def run(self): #+cdef
		"""Run the instruction.
		The default implementation does nothing.
		"""
		pass #@nocov

	def _warnDeprecated(self, moreText=""):
		lineNrStr = ""
		lineNr = self.getLineNr()
		if lineNr >= 0:
			lineNrStr = " at line %d" % lineNr
		if moreText:
			moreText = "\n%s" % moreText
		printWarning("Found DEPRECATED instruction%s:\n  %s%s" % (
			     lineNrStr, str(self), moreText))

	def getStr(self,
		   compact=True,
		   withSemicolon=False,
		   withComment=False,
		   withParentInfo=True):
		ret = []
		if self.hasLabel():
			labelStr = self.getLabel() + ":"
			ret.append(labelStr)
			nrPad = 1
			if not compact:
				nrPad = 8 - len(labelStr)
			ret.append(" " * nrPad)
		else:
			if not compact:
				ret.append(" " * 8)
		type2name = AwlInsn.type2name_english
		if self.getMnemonics() == S7CPUConfig.MNEMONICS_DE:
			type2name = AwlInsn.type2name_german
		try:
			name = type2name[self.insnType]
		except KeyError: #@nocov
			name = "<unknown type %d>" % self.insnType
		ret.append(name)
		if self.ops:
			if compact:
				ret.append(" ")
			else:
				ret.append(" " * (8 - len(name)))
			ret.append(", ".join(str(op) for op in self.ops))
		if self.params:
			ret.append(" ( ")
			ret.append(", ".join(str(param) for param in self.params))
			ret.append(" )")
		if withSemicolon:
			ret.append(";")
		text = "".join(ret)
		withParentInfo = withParentInfo and self.parentInfo
		if withComment and (self.commentStr or withParentInfo):
			text += " " * (40 - len(text))
			text += "// "
			if self.commentStr:
				text += self.commentStr
				if withParentInfo:
					text += " "
			if withParentInfo:
				text += str(self.parentInfo)
		return text

	def __repr__(self):
		return self.getStr()

# Sanity check of english2german table
assert(all(germanName in AwlInsn.name2type_german \
	   for englishName, germanName in dictItems(AwlInsn.english2german)))
bues.ch cgit interface