1// -*- mode:c++ -*-
2
3// Copyright (c) 2010-2011 ARM Limited
3// Copyright (c) 2010-2011,2019 ARM Limited
4// All rights reserved
5//
6// The license below extends only to copyright in the software and shall
7// not be construed as granting a license to any other intellectual
8// property including but not limited to intellectual property relating
9// to a hardware implementation of the functionality of the software
10// licensed hereunder. You may use the software subject to the license
11// terms below provided that you ensure that this notice is replicated
12// unmodified and in its entirety in all distributions of the software,
13// modified or unmodified, in source code or in binary form.
14//
15// Redistribution and use in source and binary forms, with or without
16// modification, are permitted provided that the following conditions are
17// met: redistributions of source code must retain the above copyright
18// notice, this list of conditions and the following disclaimer;
19// redistributions in binary form must reproduce the above copyright
20// notice, this list of conditions and the following disclaimer in the
21// documentation and/or other materials provided with the distribution;
22// neither the name of the copyright holders nor the names of its
23// contributors may be used to endorse or promote products derived from
24// this software without specific prior written permission.
25//
26// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
27// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
28// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
29// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
30// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
31// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
32// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
33// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
34// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
35// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
36// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37//
38// Authors: Gabe Black
39
40let {{
41 import math
42
43 header_output = ""
44 decoder_output = ""
45 exec_output = ""
46
47 class LoadInst(LoadStoreInst):
48 execBase = 'Load'
49
50 def __init__(self, mnem, post, add, writeback,
51 size=4, sign=False, user=False, flavor="normal"):
52 super(LoadInst, self).__init__()
53
54 self.name = mnem
55 self.post = post
56 self.add = add
57 self.writeback = writeback
58 self.size = size
59 self.sign = sign
60 self.user = user
61 self.flavor = flavor
62 self.rasPop = False
63
64 if self.add:
65 self.op = " +"
66 else:
67 self.op = " -"
68
69 self.memFlags = ["ArmISA::TLB::MustBeOne"]
70 self.codeBlobs = {"postacc_code" : ""}
71
72 def emitHelper(self, base = 'Memory', wbDecl = None, instFlags = [], pcDecl = None):
73
74 global header_output, decoder_output, exec_output
75
76 codeBlobs = self.codeBlobs
77 codeBlobs["predicate_test"] = pickPredicate(codeBlobs)
78 (newHeader,
79 newDecoder,
80 newExec) = self.fillTemplates(self.name, self.Name, codeBlobs,
81 self.memFlags, instFlags, base,
82 wbDecl, pcDecl, self.rasPop,
83 self.size, self.sign)
84
85 header_output += newHeader
86 decoder_output += newDecoder
87 exec_output += newExec
88
89 class RfeInst(LoadInst):
90 decConstBase = 'Rfe'
91
92 def __init__(self, mnem, post, add, writeback):
93 super(RfeInst, self).__init__(mnem, post, add, writeback)
94 self.Name = "RFE_" + loadImmClassName(post, add, writeback, 8)
95
96 self.memFlags.append("ArmISA::TLB::AlignWord")
97
98 def emit(self):
99 offset = 0
100 if self.post != self.add:
101 offset += 4
102 if not self.add:
103 offset -= 8
104 self.codeBlobs["ea_code"] = "EA = Base + %d;" % offset
105
106 wbDiff = -8
107 if self.add:
108 wbDiff = 8
109 accCode = '''
110 CPSR cpsr = Cpsr;
111 cpsr.nz = CondCodesNZ;
112 cpsr.c = CondCodesC;
113 cpsr.v = CondCodesV;
114 cpsr.ge = CondCodesGE;
115 URc = cpsr;
116 URa = cSwap<uint32_t>(Mem_ud, cpsr.e);
117 URb = cSwap<uint32_t>(Mem_ud >> 32, cpsr.e);
118 '''
119 self.codeBlobs["memacc_code"] = accCode
120
121 wbDecl = None
122 pcDecl = "MicroUopSetPCCPSR(machInst, INTREG_UREG0, INTREG_UREG1, INTREG_UREG2);"
123
124 if self.writeback:
125 wbDecl = "MicroAddiUop(machInst, base, base, %d);" % wbDiff
126 self.emitHelper('RfeOp', wbDecl, ["IsSerializeAfter", "IsNonSpeculative"], pcDecl)
127
128 class LoadImmInst(LoadInst):
129 def __init__(self, *args, **kargs):
130 super(LoadImmInst, self).__init__(*args, **kargs)
131 self.offset = self.op + " imm"
132
133 if self.add:
134 self.wbDecl = "MicroAddiUop(machInst, base, base, imm);"
135 else:
136 self.wbDecl = "MicroSubiUop(machInst, base, base, imm);"
137
138 if self.add and self.post and self.writeback and not self.sign and \
139 not self.user and self.size == 4:
140 self.rasPop = True
141
142 class LoadRegInst(LoadInst):
143 def __init__(self, *args, **kargs):
144 super(LoadRegInst, self).__init__(*args, **kargs)
145 self.offset = self.op + " shift_rm_imm(Index, shiftAmt," + \
146 " shiftType, OptShiftRmCondCodesC)"
147 if self.add:
148 self.wbDecl = '''
149 MicroAddUop(machInst, base, base, wbIndexReg, shiftAmt, shiftType);
150 '''
151 else:
152 self.wbDecl = '''
153 MicroSubUop(machInst, base, base, wbIndexReg, shiftAmt, shiftType);
154 '''
155
156 class LoadSingle(LoadInst):
157 def __init__(self, *args, **kargs):
158 super(LoadSingle, self).__init__(*args, **kargs)
159
160 # Build the default class name
161 self.Name = self.nameFunc(self.post, self.add, self.writeback,
162 self.size, self.sign, self.user)
163
164 # Add memory request flags where necessary
165 self.memFlags.append("%d" % int(math.log(self.size, 2)))
166 if self.user:
167 self.memFlags.append("ArmISA::TLB::UserMode")
168
169 self.instFlags = []
170 if self.flavor == "dprefetch":
171 self.memFlags.append("Request::PREFETCH")
172 self.instFlags = ['IsDataPrefetch']
173 elif self.flavor == "iprefetch":
174 self.memFlags.append("Request::PREFETCH")
175 self.instFlags = ['IsInstPrefetch']
176 elif self.flavor == "exclusive":
177 self.memFlags.append("Request::LLSC")
176 elif self.flavor == "normal":
177 self.memFlags.append("ArmISA::TLB::AllowUnaligned")
178
179 if self.flavor in ("exclusive", "acex"):
180 self.memFlags.append("Request::LLSC")
181
182 if self.flavor in ("acquire", "acex"):
183 self.instFlags.extend(["IsMemBarrier",
184 "IsWriteBarrier",
185 "IsReadBarrier"])
186
187 # Disambiguate the class name for different flavors of loads
188 if self.flavor != "normal":
189 self.Name = "%s_%s" % (self.name.upper(), self.Name)
190
191 def emit(self):
192 # Address compuation code
193 eaCode = "EA = Base"
194 if not self.post:
195 eaCode += self.offset
196 eaCode += ";"
197
198 if self.flavor == "fp":
199 eaCode += vfpEnabledCheckCode
200
201 self.codeBlobs["ea_code"] = eaCode
202
203 # Code that actually handles the access
204 if self.flavor == "dprefetch" or self.flavor == "iprefetch":
205 accCode = 'uint64_t temp = Mem%s; temp = temp;'
206 elif self.flavor == "fp":
207 accCode = "FpDest_uw = cSwap(Mem%s, ((CPSR)Cpsr).e);\n"
208 else:
209 accCode = "IWDest = cSwap(Mem%s, ((CPSR)Cpsr).e);"
210 accCode = accCode % buildMemSuffix(self.sign, self.size)
211
212 self.codeBlobs["memacc_code"] = accCode
213
214 # Push it out to the output files
215 base = buildMemBase(self.basePrefix, self.post, self.writeback)
216 wbDecl = None
217 if self.writeback:
218 wbDecl = self.wbDecl
219 self.emitHelper(base, wbDecl, self.instFlags)
220
221 def loadImmClassName(post, add, writeback, size=4, sign=False, user=False):
222 return memClassName("LOAD_IMM", post, add, writeback, size, sign, user)
223
224 class LoadImm(LoadImmInst, LoadSingle):
225 decConstBase = 'LoadImm'
226 basePrefix = 'MemoryImm'
227 nameFunc = staticmethod(loadImmClassName)
228
229 def loadRegClassName(post, add, writeback, size=4, sign=False, user=False):
230 return memClassName("LOAD_REG", post, add, writeback, size, sign, user)
231
232 class LoadReg(LoadRegInst, LoadSingle):
233 decConstBase = 'LoadReg'
234 basePrefix = 'MemoryReg'
235 nameFunc = staticmethod(loadRegClassName)
236
237 class LoadDouble(LoadInst):
238 def __init__(self, *args, **kargs):
239 super(LoadDouble, self).__init__(*args, **kargs)
240
241 # Build the default class name
242 self.Name = self.nameFunc(self.post, self.add, self.writeback)
243
244 self.instFlags = []
245 # Add memory request flags where necessary
239 if self.flavor == "exclusive":
246 if self.flavor in ("exclusive", "acex"):
247 self.memFlags.append("Request::LLSC")
248 self.memFlags.append("ArmISA::TLB::AlignDoubleWord")
249 else:
250 self.memFlags.append("ArmISA::TLB::AlignWord")
251
252 # Disambiguate the class name for different flavors of loads
253 if self.flavor != "normal":
254 self.Name = "%s_%s" % (self.name.upper(), self.Name)
255
256 if self.flavor in ("acquire", "acex"):
257 self.instFlags.extend(["IsMemBarrier",
258 "IsWriteBarrier",
259 "IsReadBarrier"])
260
261 def emit(self):
262 # Address computation code
263 eaCode = "EA = Base"
264 if not self.post:
265 eaCode += self.offset
266 eaCode += ";"
267
268 if self.flavor == "fp":
269 eaCode += vfpEnabledCheckCode
270
271 self.codeBlobs["ea_code"] = eaCode
272
273 # Code that actually handles the access
274 if self.flavor != "fp":
275 accCode = '''
276 CPSR cpsr = Cpsr;
277 Dest = cSwap<uint32_t>(Mem_ud, cpsr.e);
278 Dest2 = cSwap<uint32_t>(Mem_ud >> 32, cpsr.e);
279 '''
280 else:
281 accCode = '''
282 uint64_t swappedMem = cSwap(Mem_ud, ((CPSR)Cpsr).e);
283 FpDest_uw = (uint32_t)swappedMem;
284 FpDest2_uw = (uint32_t)(swappedMem >> 32);
285 '''
286
287 self.codeBlobs["memacc_code"] = accCode
288
289 # Push it out to the output files
290 base = buildMemBase(self.basePrefix, self.post, self.writeback)
291 wbDecl = None
292 if self.writeback:
293 wbDecl = self.wbDecl
282 self.emitHelper(base, wbDecl)
294 self.emitHelper(base, wbDecl, self.instFlags)
295
296 def loadDoubleImmClassName(post, add, writeback):
297 return memClassName("LOAD_IMMD", post, add, writeback, 4, False, False)
298
299 class LoadDoubleImm(LoadImmInst, LoadDouble):
300 decConstBase = 'LoadStoreDImm'
301 basePrefix = 'MemoryDImm'
302 nameFunc = staticmethod(loadDoubleImmClassName)
303
304 def loadDoubleRegClassName(post, add, writeback):
305 return memClassName("LOAD_REGD", post, add, writeback, 4, False, False)
306
307 class LoadDoubleReg(LoadRegInst, LoadDouble):
308 decConstBase = 'LoadDReg'
309 basePrefix = 'MemoryDReg'
310 nameFunc = staticmethod(loadDoubleRegClassName)
311
312 def buildLoads(mnem, size=4, sign=False, user=False):
313 LoadImm(mnem, True, True, True, size, sign, user).emit()
314 LoadReg(mnem, True, True, True, size, sign, user).emit()
315 LoadImm(mnem, True, False, True, size, sign, user).emit()
316 LoadReg(mnem, True, False, True, size, sign, user).emit()
317 LoadImm(mnem, False, True, True, size, sign, user).emit()
318 LoadReg(mnem, False, True, True, size, sign, user).emit()
319 LoadImm(mnem, False, False, True, size, sign, user).emit()
320 LoadReg(mnem, False, False, True, size, sign, user).emit()
321 LoadImm(mnem, False, True, False, size, sign, user).emit()
322 LoadReg(mnem, False, True, False, size, sign, user).emit()
323 LoadImm(mnem, False, False, False, size, sign, user).emit()
324 LoadReg(mnem, False, False, False, size, sign, user).emit()
325
326 def buildDoubleLoads(mnem):
327 LoadDoubleImm(mnem, True, True, True).emit()
328 LoadDoubleReg(mnem, True, True, True).emit()
329 LoadDoubleImm(mnem, True, False, True).emit()
330 LoadDoubleReg(mnem, True, False, True).emit()
331 LoadDoubleImm(mnem, False, True, True).emit()
332 LoadDoubleReg(mnem, False, True, True).emit()
333 LoadDoubleImm(mnem, False, False, True).emit()
334 LoadDoubleReg(mnem, False, False, True).emit()
335 LoadDoubleImm(mnem, False, True, False).emit()
336 LoadDoubleReg(mnem, False, True, False).emit()
337 LoadDoubleImm(mnem, False, False, False).emit()
338 LoadDoubleReg(mnem, False, False, False).emit()
339
340 def buildRfeLoads(mnem):
341 RfeInst(mnem, True, True, True).emit()
342 RfeInst(mnem, True, True, False).emit()
343 RfeInst(mnem, True, False, True).emit()
344 RfeInst(mnem, True, False, False).emit()
345 RfeInst(mnem, False, True, True).emit()
346 RfeInst(mnem, False, True, False).emit()
347 RfeInst(mnem, False, False, True).emit()
348 RfeInst(mnem, False, False, False).emit()
349
350 def buildPrefetches(mnem, type):
351 LoadReg(mnem, False, False, False, size=1, flavor=type).emit()
352 LoadImm(mnem, False, False, False, size=1, flavor=type).emit()
353 LoadReg(mnem, False, True, False, size=1, flavor=type).emit()
354 LoadImm(mnem, False, True, False, size=1, flavor=type).emit()
355
356 buildLoads("ldr")
357 buildLoads("ldrt", user=True)
358 buildLoads("ldrb", size=1)
359 buildLoads("ldrbt", size=1, user=True)
360 buildLoads("ldrsb", size=1, sign=True)
361 buildLoads("ldrsbt", size=1, sign=True, user=True)
362 buildLoads("ldrh", size=2)
363 buildLoads("ldrht", size=2, user=True)
364 buildLoads("ldrsh", size=2, sign=True)
365 buildLoads("ldrsht", size=2, sign=True, user=True)
366
367 buildDoubleLoads("ldrd")
368
369 buildRfeLoads("rfe")
370
371 buildPrefetches("pld", "dprefetch")
372 buildPrefetches("pldw", "dprefetch")
373 buildPrefetches("pli", "iprefetch")
374
375 LoadImm("ldrex", False, True, False, size=4, flavor="exclusive").emit()
376 LoadImm("ldrexh", False, True, False, size=2, flavor="exclusive").emit()
377 LoadImm("ldrexb", False, True, False, size=1, flavor="exclusive").emit()
378 LoadDoubleImm("ldrexd", False, True, False, flavor="exclusive").emit()
379
380 LoadImm("lda", False, True, False, size=4, flavor="acquire").emit()
381 LoadImm("ldah", False, True, False, size=2, flavor="acquire").emit()
382 LoadImm("ldab", False, True, False, size=1, flavor="acquire").emit()
383 LoadImm("ldaex", False, True, False, size=4, flavor="acex").emit()
384 LoadImm("ldaexh", False, True, False, size=2, flavor="acex").emit()
385 LoadImm("ldaexb", False, True, False, size=1, flavor="acex").emit()
386 LoadDoubleImm("ldaexd", False, True, False, flavor="acex").emit()
387
388 LoadImm("vldr", False, True, False, size=4, flavor="fp").emit()
389 LoadImm("vldr", False, False, False, size=4, flavor="fp").emit()
390 LoadDoubleImm("vldr", False, True, False, flavor="fp").emit()
391 LoadDoubleImm("vldr", False, False, False, flavor="fp").emit()
392}};