aboutsummaryrefslogtreecommitdiffstats
path: root/awlsim/core/offset.py
blob: b604fc7136c2ea3a4babee82c373629ccf0eb1c1 (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
# -*- coding: utf-8 -*-
#
# AWL data offset
#
# Copyright 2012-2016 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.compat import *

from awlsim.common.datatypehelpers import *

#from awlsim.core.dynattrs cimport * #@cy

from awlsim.core.dynattrs import * #@nocy
from awlsim.core.util import *


class AwlOffset(DynAttrs): #+cdef
	"Memory area offset"

	dynAttrs = {
		# A DB-number for fully qualified access, or None.
		"dbNumber"	: None,

		# A symbolic DB-name for fully qualified access, or None.
		"dbName"	: None,

		# An AwlDataIdentChain, or None.
		# Used for fully qualified (DBx.VAR) or named local (#VAR)
		# global symbolic ("VAR") accesses.
		# For global symbols the chain only has one element.
		"identChain"	: None,

		# A (S)FB-number for multi-instance calls, or None.
		"fbNumber"	: None,

		# Additional sub-offset that is added to this offset.
		# Defaults to 0.0
		# This is used for arrays and structs.
		"subOffset"	: lambda self, name: AwlOffset(),
	}

	def __init__(self, byteOffset=0, bitOffset=0):
		self.byteOffset, self.bitOffset =\
			byteOffset, bitOffset

	def __eq__(self, other): #@nocy
#@cy	cdef __eq(self, object other):
		return (self is other) or (\
			isinstance(other, AwlOffset) and\
			self.byteOffset == other.byteOffset and\
			self.bitOffset == other.bitOffset and\
			super(AwlOffset, self).__eq__(other)\
		)

#@cy	def __richcmp__(self, object other, int op):
#@cy		if op == 2: # __eq__
#@cy			return self.__eq(other)
#@cy		elif op == 3: # __ne__
#@cy			return not self.__eq(other)
#@cy		return False

	def __ne__(self, other):		#@nocy
		return not self.__eq__(other)	#@nocy

	def dup(self):
		offset = AwlOffset(self.byteOffset,
				   self.bitOffset)
		offset.dbNumber = self.dbNumber
		return offset

	@classmethod
	def fromPointerValue(cls, value):
		return cls((value & 0x0007FFF8) >> 3,
			   (value & 0x7))

	def toPointerValue(self):
		return ((self.byteOffset << 3) & 0x0007FFF8) |\
		       (self.bitOffset & 0x7)

	@classmethod
	def fromBitOffset(cls, bitOffset):
		return cls(bitOffset // 8, bitOffset % 8)

	def toBitOffset(self):
		return self.byteOffset * 8 + self.bitOffset

	def __add__(self, other):
		bitOffset = (self.byteOffset + other.byteOffset) * 8 +\
			    self.bitOffset + other.bitOffset
		return AwlOffset(bitOffset // 8, bitOffset % 8)

	def __iadd__(self, other):
		bitOffset = (self.byteOffset + other.byteOffset) * 8 +\
			    self.bitOffset + other.bitOffset
		self.byteOffset = bitOffset // 8
		self.bitOffset = bitOffset % 8
		return self

	# Round the offset to a multiple of 'byteBase' bytes.
	# Returns an AwlOffset.
	def roundUp(self, byteBase):
		byteOffset = self.byteOffset
		if self.bitOffset:
			byteOffset += 1
		byteOffset = roundUp(byteOffset, byteBase)
		return AwlOffset(byteOffset)

	def __repr__(self):
		prefix = ""
		if self.dbNumber is not None:
			prefix = "DB%d" % self.dbNumber
		if self.dbName is not None:
			prefix = '"%s"' % self.dbName
		if self.identChain is not None:
			if prefix:
				return prefix + "." + self.identChain.getString()
			return "#" + self.identChain.getString()
		else:
			if prefix:
				prefix = prefix + ".DBX "
			return "%s%d.%d" % (prefix,
					    self.byteOffset,
					    self.bitOffset)
bues.ch cgit interface