amo64.isa revision 14150:1391e94a7b95
1// -*- mode:c++ -*-
2
3// Copyright (c) 2018 Metempsy Technology Consulting
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: Jordi Vaquero
39
40let {{
41
42    import math
43
44    OP_DICT = { "CAS" : 'if (a == *b){*b = c;}',
45                "SWP" : '*b = c;',
46                "ADD" : '*b += c;',
47                "EOR" : '*b ^= c;',
48                "CLR" : '*b &= ~c;',
49                "SET" : '*b |= c;',
50                "MAX" : '*b = std::max(*b, c);',
51                "MIN" : '*b = std::min(*b, c);', }
52
53    MASKS = { 1: 0xFF,
54              2: 0xFFFF,
55              4: 0xFFFFFFFF,
56              8: 0xFFFFFFFFFFFFFFFF,
57             }
58
59    header_output = ""
60    decoder_output = ""
61    exec_output = ""
62
63    class AtomicInst64(LoadStoreInst):
64        execBase = 'AtomicInst64'
65        micro = False
66
67        def __init__(self, mnem, Name, size=4, user=False, flavor="normal",
68                    unsign=True, top = False, paired=False):
69            super(AtomicInst64, self).__init__()
70
71            self.name= mnem
72            self.Name = Name
73            self.size = size
74            self.user = user
75            self.flavor = flavor
76            self.unsign = unsign
77            self.top = top
78            self.paired = paired
79
80            self.memFlags = ["ArmISA::TLB::MustBeOne"]
81            self.instFlags = ["IsAtomic"]
82            self.codeBlobs = { "postacc_code" : "" }
83            self.codeBlobs['usrDecl'] = ""
84
85            # Add memory request flags where necessary
86            if self.user:
87                self.memFlags.append("ArmISA::TLB::UserMode")
88
89            sz = self.size*2 if paired else self.size
90            self.memFlags.append("%d" % int(math.log(sz, 2)))
91
92            if self.micro:
93                self.instFlags.append("IsMicroop")
94
95            if self.flavor in ("release", "acquire_release", "acquire"):
96                self.instFlags.append("IsMemBarrier")
97            if self.flavor in ("release", "acquire_release"):
98                self.instFlags.append("IsWriteBarrier")
99            if self.flavor in ("acquire_release", "acquire"):
100                self.instFlags.append("IsReadBarrier")
101            self.memFlags.append('Request::ATOMIC_RETURN_OP')
102
103        def emitHelper(self, base = 'Memory64', wbDecl = None, ):
104            global header_output, decoder_output, exec_output
105
106            # If this is a microop itself, don't allow anything that would
107            # require further microcoding.
108            if self.micro:
109                assert not wbDecl
110
111            fa_code = None
112            if not self.micro :
113            #and self.flavor in ("normal", "release"):
114                fa_code = '''
115                    fault->annotate(ArmFault::SAS, %s);
116                    fault->annotate(ArmFault::SSE, false);
117                    fault->annotate(ArmFault::SRT, dest);
118                    fault->annotate(ArmFault::SF, %s);
119                    fault->annotate(ArmFault::AR, %s);
120                ''' % ("0" if self.size == 1 else
121                       "1" if self.size == 2 else
122                       "2" if self.size == 4 else "3",
123                       "true" if self.size == 8 else "false",
124                       "true" if self.flavor != "normal"  else "false")
125            sas_code = "3"
126            if self.size == 1 :
127                sas_code = "0"
128            elif self.size == 2:
129                sas_code = "1"
130            elif self.size == 4:
131                sas_code = "2"
132
133            if self.paired and sas_code == "3":
134                sas_code = "4"
135            if self.paired and sas_code == "2":
136                sas_code = "3"
137
138
139            fa_code = '''
140               fault->annotate(ArmFault::SAS, %s);
141               fault->annotate(ArmFault::SSE, %s);
142               fault->annotate(ArmFault::SRT, dest);
143               fault->annotate(ArmFault::SF, %s);
144               fault->annotate(ArmFault::AR, %s);
145               ''' % (sas_code,
146                     "true" if not self.unsign else "false",
147                     "true" if self.size == 8 else "false",
148                     "true" if self.flavor != "normal"  else "false")
149
150            (newHeader, newDecoder, newExec) = \
151                self.fillTemplates(self.name, self.Name, self.codeBlobs,
152                                   self.memFlags, self.instFlags,
153                                   base, wbDecl, faCode=fa_code)
154
155            header_output += newHeader
156            decoder_output += newDecoder
157            exec_output += newExec
158
159        def buildEACode(self):
160            # Address computation
161            eaCode = SPAlignmentCheckCode + "EA = XBase"
162            if self.size == 16:
163                if self.top:
164                    eaCode += " + (isBigEndian64(xc->tcBase()) ? 0 : 8)"
165                else:
166                    eaCode += " + (isBigEndian64(xc->tcBase()) ? 8 : 0)"
167            if not self.post:
168                eaCode += self.offset
169            eaCode += ";"
170            self.codeBlobs["ea_code"] = eaCode
171
172
173    class AtomicSingleOp(AtomicInst64):
174        decConstBase = 'AmoOp'
175        base = 'ArmISA::MemoryEx64'
176        writeback = True
177        post = False
178        execBase = 'AmoOp'
179
180        def __init__(self, *args, **kargs):
181            super(AtomicSingleOp, self).__init__(*args, **kargs)
182            self.suffix = buildMemSuffix(not self.unsign, self.size)
183            if self.size == 8:
184                self.res = 'XResult_ud' #if self.unsign else 'XResult_sd'
185                self.des = 'XDest_ud' #if self.unsign else 'XDest_sd'
186                self.tp = 'uint64_t' if self.unsign else 'int64_t'
187                self.utp = 'uint64_t'
188                self.suffix = '_sd' if not self.unsign else '_ud'
189            elif self.size == 4:
190                self.res = 'XResult_uw' #if self.unsign else 'XResult_sw'
191                self.des = 'XDest_uw' #if self.unsign else 'XDest_sw'
192                self.tp = 'uint32_t' if self.unsign else 'int32_t'
193                self.utp = 'uint32_t'
194            elif self.size == 2:
195                self.res = 'XResult_uh' #if self.unsign else 'XResult_sh'
196                self.des = 'XDest_uh' #if self.unsign else 'XDest_sh'
197                self.tp = 'uint16_t' if self.unsign else 'int16_t'
198                self.utp = 'uint16_t'
199            elif self.size == 1:
200                self.res = 'XResult_ub' #if self.unsign else 'XResult_sb'
201                self.des = 'XDest_ub' #if self.unsign else 'XDest_sb'
202                self.tp = 'uint8_t' if self.unsign else 'int8_t'
203                self.utp = 'uint8_t'
204            self.offset = ""
205            store_res = '''
206                        %(result)s = cSwap(Mem%(suffix)s,
207                                         isBigEndian64(xc->tcBase()));
208                      '''
209            store_res = store_res % {"result":self.res, "suffix":self.suffix}
210            self.codeBlobs["postacc_code"] = \
211                    store_res + " SevMailbox = 1; LLSCLock = 0;"
212
213        def emit(self, op):
214            self.buildEACode()
215            usrDecl = "%(type)s valRs;\n" % {'type': self.tp}
216            self.codeBlobs['usrDecl'] = usrDecl
217
218            opcode = "valRs = cSwap(%(dest)s,"\
219                      " isBigEndian64(xc->tcBase()));\n"
220            opcode += "TypedAtomicOpFunctor<%(type)s> *amo_op = "\
221                      "new AtomicGeneric3Op<%(type)s>(Mem%(suffix)s,"\
222                      " valRs, [](%(type)s* b, %(type)s a,"\
223                      " %(type)s c){ %(op)s });\n"
224
225            opcode = opcode % {"suffix": self.suffix,
226                               "type": self.tp ,
227                               "dest": self.des,
228                               "op": op}
229            self.codeBlobs['amo_code'] = opcode
230            accCode = "Mem%(suffix)s = cSwap(%(result)s,"\
231                      " isBigEndian64(xc->tcBase()));"
232            accCode = accCode % { "result": self.res, "type":self.tp,
233                                  "suffix": self.suffix}
234            self.codeBlobs["memacc_code"] = accCode
235            self.emitHelper(self.base)
236
237
238    AtomicSingleOp("cas",   "CAS64",   8, unsign=True,
239                   flavor="normal").emit(OP_DICT['CAS'])
240    AtomicSingleOp("casa",  "CASA64",  8, unsign=True,
241                   flavor="acquire").emit(OP_DICT['CAS'])
242    AtomicSingleOp("casal", "CASAL64", 8, unsign=True,
243                   flavor="acquire_release").emit(OP_DICT['CAS'])
244    AtomicSingleOp("casl",  "CASL64",  8, unsign=True,
245                   flavor="release").emit(OP_DICT['CAS'])
246
247    AtomicSingleOp("casb",   "CASB",   1, unsign=True,
248                   flavor="normal").emit(OP_DICT['CAS'])
249    AtomicSingleOp("casab",  "CASAB",  1, unsign=True,
250                   flavor="acquire").emit(OP_DICT['CAS'])
251    AtomicSingleOp("casalb", "CASALB", 1, unsign=True,
252                   flavor="acquire_release").emit(OP_DICT['CAS'])
253    AtomicSingleOp("caslb",  "CASLB",  1, unsign=True,
254                   flavor="release").emit(OP_DICT['CAS'])
255
256    AtomicSingleOp("cash",   "CASH",   2, unsign=True,
257                   flavor="normal").emit(OP_DICT['CAS'])
258    AtomicSingleOp("casah",  "CASAH",  2, unsign=True,
259                   flavor="acquire").emit(OP_DICT['CAS'])
260    AtomicSingleOp("casalh", "CASALH", 2, unsign=True,
261                   flavor="acquire_release").emit(OP_DICT['CAS'])
262    AtomicSingleOp("caslh",  "CASLH",  2, unsign=True,
263                   flavor="release").emit(OP_DICT['CAS'])
264
265    AtomicSingleOp("cas",   "CAS32",   4, unsign=True,
266                   flavor="normal").emit(OP_DICT['CAS'])
267    AtomicSingleOp("casa",  "CASA32",  4, unsign=True,
268                   flavor="acquire").emit(OP_DICT['CAS'])
269    AtomicSingleOp("casal", "CASAL32", 4, unsign=True,
270                   flavor="acquire_release").emit(OP_DICT['CAS'])
271    AtomicSingleOp("casl",  "CASL32",  4, unsign=True,
272                   flavor="release").emit(OP_DICT['CAS'])
273
274    class CasPair64(AtomicInst64):
275        decConstBase = 'AmoPairOp'
276        base = 'ArmISA::MemoryEx64'
277        writeback = True
278        post = False
279        execBase = 'AmoOp'
280
281        def __init__(self, *args, **kargs):
282            super(CasPair64, self).__init__(*args, **kargs)
283            self.paired = True
284            self.offset = ""
285            if self.size == 8:
286                self.res = 'XResult_ud'
287                self.des = 'XDest_ud'
288                self.tp = 'std::array<uint64_t, 2>'
289                self.suffix = "_tud"
290                store_res = '''
291                            %(result)s = cSwap(Mem%(suffix)s[0],
292                                          isBigEndian64(xc->tcBase()));
293                            uint64_t result2 = cSwap(Mem%(suffix)s[1],
294                                           isBigEndian64(xc->tcBase()));
295                            xc->setIntRegOperand(this, r2_dst, (result2)
296                                                    & mask(aarch64 ? 64 : 32));
297                            '''
298            elif self.size == 4:
299                self.res = 'Result_uw'
300                self.des = 'WDest_uw'
301                self.tp = 'uint64_t'
302                self.suffix = "_ud"
303                store_res = '''
304                    uint64_t data = cSwap(Mem%(suffix)s,
305                                          isBigEndian64(xc->tcBase()));
306                    %(result)s = isBigEndian64(xc->tcBase())
307                                   ? (data >> 32)
308                                   : (uint32_t)data;
309                    uint32_t result2 = isBigEndian64(xc->tcBase())
310                                   ? (uint32_t)data
311                                   : (data >> 32);
312                    xc->setIntRegOperand(this, r2_dst, (result2) &
313                                                mask(aarch64 ? 64 : 32));
314                            '''
315
316            store_res = store_res % {"result":self.res, "suffix":self.suffix}
317            usrDecl = "%(type)s valRs;\n" % {'type': self.tp}
318            self.codeBlobs['usrDecl'] = usrDecl
319            self.codeBlobs["postacc_code"] = \
320                    store_res + " SevMailbox = 1; LLSCLock = 0;"
321
322        def emit(self):
323            self.buildEACode()
324
325            # Code that actually handles the access
326
327            if self.size == 4:
328                accCode = \
329                  "uint32_t result2 = ((xc->readIntRegOperand(this, r2_src))"\
330                  " & mask(aarch64 ? 64 : 32)) ;\n"\
331                  " uint32_t dest2 = ((xc->readIntRegOperand(this, d2_src)) "\
332                  " & mask(aarch64 ? 64 : 32)) ;"
333                accCode += '''
334                     uint64_t data = dest2;
335                     data = isBigEndian64(xc->tcBase())
336                          ? ((uint64_t(WDest_uw) << 32) | data)
337                                 : ((data << 32) | WDest_uw);
338                     valRs = cSwap(data, isBigEndian64(xc->tcBase()));
339                     uint64_t data2 = result2 ;
340                     data2 = isBigEndian64(xc->tcBase())
341                          ? ((uint64_t(Result_uw) << 32) | data2)
342                                 : ((data2 << 32) | Result_uw);
343                     Mem_ud = cSwap(data2, isBigEndian64(xc->tcBase()));
344                     '''
345
346                opcode = "TypedAtomicOpFunctor<%(type)s> *amo_op = "\
347                      "new AtomicGeneric3Op<%(type)s>(Mem%(suffix)s,"\
348                      " valRs, [](%(type)s* b, %(type)s a,"\
349                      " %(type)s c){ %(op)s });\n"
350
351            elif self.size == 8:
352                accCode = ""\
353                  "uint64_t result2 = ((xc->readIntRegOperand(this, r2_src))"\
354                  " & mask(aarch64 ? 64 : 32)) ;\n"\
355                  " uint64_t dest2 = ((xc->readIntRegOperand(this, d2_src)) "\
356                  " & mask(aarch64 ? 64 : 32)) ;"
357                accCode += '''
358                   // This temporary needs to be here so that the parser
359                   // will correctly identify this instruction as a store.
360                   std::array<uint64_t, 2> temp;
361                   temp[0] = cSwap(XDest_ud,isBigEndian64(xc->tcBase()));
362                   temp[1] = cSwap(dest2,isBigEndian64(xc->tcBase()));
363                   valRs = temp;
364                   std::array<uint64_t, 2> temp2;
365                   temp2[0] = cSwap(XResult_ud,isBigEndian64(xc->tcBase()));
366                   temp2[1] = cSwap(result2,isBigEndian64(xc->tcBase()));
367                   Mem_tud = temp2;
368                     '''
369
370                opcode = "TypedAtomicOpFunctor<uint64_t> *amo_op = "\
371                          "new AtomicGenericPair3Op<uint64_t>(Mem_tud, "\
372                          "valRs, [](uint64_t* b, std::array<uint64_t,2> a,"\
373                          '''
374                          std::array<uint64_t,2> c){
375                             if(a[0]==b[0] && a[1]==b[1]){
376                                b[0] = c[0]; b[1] = c[1];
377                             }
378                          });'''
379
380            opcode = opcode % { "suffix" : self.suffix,
381                                "type": self.tp,
382                                "op": OP_DICT['CAS']}
383            self.codeBlobs['amo_code'] = opcode
384            self.codeBlobs["memacc_code"] = accCode % {"type": self.tp}
385
386            # Push it out to the output files
387            self.emitHelper(self.base)
388
389    CasPair64("casp",   "CASP64",   8, flavor="normal", paired=True).emit()
390    CasPair64("caspa",  "CASPA64",  8, flavor="acquire", paired=True).emit()
391    CasPair64("caspal", "CASPAL64", 8, flavor="acquire_release",
392            paired=True).emit()
393    CasPair64("caspl",  "CASPL64",  8, flavor="release", paired=True).emit()
394
395    CasPair64("casp",   "CASP32",   4, flavor="normal", paired=True).emit()
396    CasPair64("caspa",  "CASPA32",  4, flavor="acquire", paired=True).emit()
397    CasPair64("caspal", "CASPAL32", 4, flavor="acquire_release",
398            paired=True).emit()
399    CasPair64("caspl",  "CASPL32",  4, flavor="release", paired=True).emit()
400
401}};
402