regop.isa revision 9212:dc386ccc1db9
15369Ssaidi@eecs.umich.edu// Copyright (c) 2007-2008 The Hewlett-Packard Development Company
23005Sstever@eecs.umich.edu// All rights reserved.
33005Sstever@eecs.umich.edu//
43005Sstever@eecs.umich.edu// The license below extends only to copyright in the software and shall
53005Sstever@eecs.umich.edu// not be construed as granting a license to any other intellectual
63005Sstever@eecs.umich.edu// property including but not limited to intellectual property relating
73005Sstever@eecs.umich.edu// to a hardware implementation of the functionality of the software
83005Sstever@eecs.umich.edu// licensed hereunder.  You may use the software subject to the license
93005Sstever@eecs.umich.edu// terms below provided that you ensure that this notice is replicated
103005Sstever@eecs.umich.edu// unmodified and in its entirety in all distributions of the software,
113005Sstever@eecs.umich.edu// modified or unmodified, in source code or in binary form.
123005Sstever@eecs.umich.edu//
133005Sstever@eecs.umich.edu// Redistribution and use in source and binary forms, with or without
143005Sstever@eecs.umich.edu// modification, are permitted provided that the following conditions are
153005Sstever@eecs.umich.edu// met: redistributions of source code must retain the above copyright
163005Sstever@eecs.umich.edu// notice, this list of conditions and the following disclaimer;
173005Sstever@eecs.umich.edu// redistributions in binary form must reproduce the above copyright
183005Sstever@eecs.umich.edu// notice, this list of conditions and the following disclaimer in the
193005Sstever@eecs.umich.edu// documentation and/or other materials provided with the distribution;
203005Sstever@eecs.umich.edu// neither the name of the copyright holders nor the names of its
213005Sstever@eecs.umich.edu// contributors may be used to endorse or promote products derived from
223005Sstever@eecs.umich.edu// this software without specific prior written permission.
233005Sstever@eecs.umich.edu//
243005Sstever@eecs.umich.edu// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
253005Sstever@eecs.umich.edu// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
263005Sstever@eecs.umich.edu// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
273005Sstever@eecs.umich.edu// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
283005Sstever@eecs.umich.edu// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
292710SN/A// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
302710SN/A// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
313005Sstever@eecs.umich.edu// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
322889SN/A// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
336654Snate@binkert.org// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
346654Snate@binkert.org// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
356654Snate@binkert.org//
366654Snate@binkert.org// Authors: Gabe Black
376654Snate@binkert.org
382667SN/A//////////////////////////////////////////////////////////////////////////
396654Snate@binkert.org//
406654Snate@binkert.org// RegOp Microop templates
416654Snate@binkert.org//
425457Ssaidi@eecs.umich.edu//////////////////////////////////////////////////////////////////////////
436654Snate@binkert.org
446654Snate@binkert.orgdef template MicroRegOpExecute {{
455457Ssaidi@eecs.umich.edu        Fault %(class_name)s::execute(%(CPU_exec_context)s *xc,
466654Snate@binkert.org                Trace::InstRecord *traceData) const
476654Snate@binkert.org        {
483395Shsul@eecs.umich.edu            Fault fault = NoFault;
496981SLisa.Hsu@amd.com
503448Shsul@eecs.umich.edu            DPRINTF(X86, "The data size is %d\n", dataSize);
515369Ssaidi@eecs.umich.edu            %(op_decl)s;
523394Shsul@eecs.umich.edu            %(op_rd)s;
533444Sktlim@umich.edu
543444Sktlim@umich.edu            IntReg result M5_VAR_USED;
553444Sktlim@umich.edu
563444Sktlim@umich.edu            if(%(cond_check)s)
572424SN/A            {
582957SN/A                %(code)s;
592957SN/A                %(flag_code)s;
603323Shsul@eecs.umich.edu            }
613005Sstever@eecs.umich.edu            else
625514SMichael.Adler@intel.com            {
635514SMichael.Adler@intel.com                %(else_code)s;
642957SN/A            }
655514SMichael.Adler@intel.com
665514SMichael.Adler@intel.com            //Write the resulting state to the execution context
675514SMichael.Adler@intel.com            if(fault == NoFault)
685514SMichael.Adler@intel.com            {
693323Shsul@eecs.umich.edu                %(op_wb)s;
703444Sktlim@umich.edu            }
712957SN/A            return fault;
722957SN/A        }
732957SN/A}};
742957SN/A
752957SN/Adef template MicroRegOpImmExecute {{
762957SN/A        Fault %(class_name)s::execute(%(CPU_exec_context)s *xc,
772957SN/A                Trace::InstRecord *traceData) const
785369Ssaidi@eecs.umich.edu        {
795369Ssaidi@eecs.umich.edu            Fault fault = NoFault;
806654Snate@binkert.org
815369Ssaidi@eecs.umich.edu            %(op_decl)s;
825369Ssaidi@eecs.umich.edu            %(op_rd)s;
835369Ssaidi@eecs.umich.edu
845369Ssaidi@eecs.umich.edu            IntReg result M5_VAR_USED;
855369Ssaidi@eecs.umich.edu
865369Ssaidi@eecs.umich.edu            if(%(cond_check)s)
875369Ssaidi@eecs.umich.edu            {
885369Ssaidi@eecs.umich.edu                %(code)s;
895369Ssaidi@eecs.umich.edu                %(flag_code)s;
905369Ssaidi@eecs.umich.edu            }
915369Ssaidi@eecs.umich.edu            else
925369Ssaidi@eecs.umich.edu            {
935369Ssaidi@eecs.umich.edu                %(else_code)s;
942801SN/A            }
952801SN/A
965514SMichael.Adler@intel.com            //Write the resulting state to the execution context
975514SMichael.Adler@intel.com            if(fault == NoFault)
985514SMichael.Adler@intel.com            {
995514SMichael.Adler@intel.com                %(op_wb)s;
1002418SN/A            }
1016391Sksewell@umich.edu            return fault;
1026391Sksewell@umich.edu        }
1036391Sksewell@umich.edu}};
1046642Sksewell@umich.edu
1056391Sksewell@umich.edudef template MicroRegOpDeclare {{
1066642Sksewell@umich.edu    class %(class_name)s : public %(base_class)s
1072833SN/A    {
1082833SN/A      public:
1092833SN/A        %(class_name)s(ExtMachInst _machInst,
1102833SN/A                const char * instMnem, uint64_t setFlags,
1112833SN/A                InstRegIndex _src1, InstRegIndex _src2, InstRegIndex _dest,
1122833SN/A                uint8_t _dataSize, uint16_t _ext);
1135514SMichael.Adler@intel.com
1145514SMichael.Adler@intel.com        %(BasicExecDeclare)s
1152833SN/A    };
1162833SN/A}};
1172833SN/A
1185514SMichael.Adler@intel.comdef template MicroRegOpImmDeclare {{
1195514SMichael.Adler@intel.com
1205514SMichael.Adler@intel.com    class %(class_name)s : public %(base_class)s
1215514SMichael.Adler@intel.com    {
1222833SN/A      public:
1232833SN/A        %(class_name)s(ExtMachInst _machInst,
1242833SN/A                const char * instMnem, uint64_t setFlags,
1253005Sstever@eecs.umich.edu                InstRegIndex _src1, uint8_t _imm8, InstRegIndex _dest,
1262833SN/A                uint8_t _dataSize, uint16_t _ext);
1272833SN/A
1282833SN/A        %(BasicExecDeclare)s
1295514SMichael.Adler@intel.com    };
1305514SMichael.Adler@intel.com}};
1315514SMichael.Adler@intel.com
1325514SMichael.Adler@intel.comdef template MicroRegOpConstructor {{
1332833SN/A    inline %(class_name)s::%(class_name)s(
1342833SN/A            ExtMachInst machInst, const char * instMnem, uint64_t setFlags,
1356642Sksewell@umich.edu            InstRegIndex _src1, InstRegIndex _src2, InstRegIndex _dest,
1366642Sksewell@umich.edu            uint8_t _dataSize, uint16_t _ext) :
1373481Shsul@eecs.umich.edu        %(base_class)s(machInst, "%(mnemonic)s", instMnem, setFlags,
1382957SN/A                _src1, _src2, _dest, _dataSize, _ext,
1393395Shsul@eecs.umich.edu                %(op_class)s)
1406642Sksewell@umich.edu    {
1413005Sstever@eecs.umich.edu        %(constructor)s;
1423395Shsul@eecs.umich.edu        %(cond_control_flag_init)s;
1433395Shsul@eecs.umich.edu    }
1443395Shsul@eecs.umich.edu}};
1453323Shsul@eecs.umich.edu
1463395Shsul@eecs.umich.edudef template MicroRegOpImmConstructor {{
1473395Shsul@eecs.umich.edu    inline %(class_name)s::%(class_name)s(
1483005Sstever@eecs.umich.edu            ExtMachInst machInst, const char * instMnem, uint64_t setFlags,
1493395Shsul@eecs.umich.edu            InstRegIndex _src1, uint8_t _imm8, InstRegIndex _dest,
1506981SLisa.Hsu@amd.com            uint8_t _dataSize, uint16_t _ext) :
1515056Ssaidi@eecs.umich.edu        %(base_class)s(machInst, "%(mnemonic)s", instMnem, setFlags,
1523395Shsul@eecs.umich.edu                _src1, _imm8, _dest, _dataSize, _ext,
1533395Shsul@eecs.umich.edu                %(op_class)s)
1543005Sstever@eecs.umich.edu    {
1554968Sacolyte@umich.edu        %(constructor)s;
1564968Sacolyte@umich.edu        %(cond_control_flag_init)s;
1574968Sacolyte@umich.edu    }
1583005Sstever@eecs.umich.edu}};
1592902SN/A
1603481Shsul@eecs.umich.eduoutput header {{
161    void
162    divide(uint64_t dividend, uint64_t divisor,
163            uint64_t &quotient, uint64_t &remainder);
164
165    enum SegmentSelectorCheck {
166      SegNoCheck, SegCSCheck, SegCallGateCheck, SegIntGateCheck,
167      SegSoftIntGateCheck, SegSSCheck, SegIretCheck, SegIntCSCheck,
168      SegTRCheck, SegTSSCheck, SegInGDTCheck, SegLDTCheck
169    };
170
171    enum LongModeDescriptorType {
172        LDT64 = 2,
173        AvailableTSS64 = 9,
174        BusyTSS64 = 0xb,
175        CallGate64 = 0xc,
176        IntGate64 = 0xe,
177        TrapGate64 = 0xf
178    };
179}};
180
181output decoder {{
182    void
183    divide(uint64_t dividend, uint64_t divisor,
184            uint64_t &quotient, uint64_t &remainder)
185    {
186        //Check for divide by zero.
187        assert(divisor != 0);
188        //If the divisor is bigger than the dividend, don't do anything.
189        if (divisor <= dividend) {
190            //Shift the divisor so it's msb lines up with the dividend.
191            int dividendMsb = findMsbSet(dividend);
192            int divisorMsb = findMsbSet(divisor);
193            int shift = dividendMsb - divisorMsb;
194            divisor <<= shift;
195            //Compute what we'll add to the quotient if the divisor isn't
196            //now larger than the dividend.
197            uint64_t quotientBit = 1;
198            quotientBit <<= shift;
199            //If we need to step back a bit (no pun intended) because the
200            //divisor got too to large, do that here. This is the "or two"
201            //part of one or two bit division.
202            if (divisor > dividend) {
203                quotientBit >>= 1;
204                divisor >>= 1;
205            }
206            //Decrement the remainder and increment the quotient.
207            quotient += quotientBit;
208            remainder -= divisor;
209        }
210    }
211}};
212
213let {{
214    # Make these empty strings so that concatenating onto
215    # them will always work.
216    header_output = ""
217    decoder_output = ""
218    exec_output = ""
219
220    immTemplates = (
221            MicroRegOpImmDeclare,
222            MicroRegOpImmConstructor,
223            MicroRegOpImmExecute)
224
225    regTemplates = (
226            MicroRegOpDeclare,
227            MicroRegOpConstructor,
228            MicroRegOpExecute)
229
230    class RegOpMeta(type):
231        def buildCppClasses(self, name, Name, suffix, code, big_code, \
232                flag_code, cond_check, else_code, cond_control_flag_init):
233
234            # Globals to stick the output in
235            global header_output
236            global decoder_output
237            global exec_output
238
239            # Stick all the code together so it can be searched at once
240            allCode = "|".join((code, flag_code, cond_check, else_code, 
241                                cond_control_flag_init))
242            allBigCode = "|".join((big_code, flag_code, cond_check, else_code,
243                                   cond_control_flag_init))
244
245            # If op2 is used anywhere, make register and immediate versions
246            # of this code.
247            matcher = re.compile(r"(?<!\w)(?P<prefix>s?)op2(?P<typeQual>_[^\W_]+)?")
248            match = matcher.search(allCode + allBigCode)
249            if match:
250                typeQual = ""
251                if match.group("typeQual"):
252                    typeQual = match.group("typeQual")
253                src2_name = "%spsrc2%s" % (match.group("prefix"), typeQual)
254                self.buildCppClasses(name, Name, suffix,
255                        matcher.sub(src2_name, code),
256                        matcher.sub(src2_name, big_code),
257                        matcher.sub(src2_name, flag_code),
258                        matcher.sub(src2_name, cond_check),
259                        matcher.sub(src2_name, else_code),
260                        matcher.sub(src2_name, cond_control_flag_init))
261                imm_name = "%simm8" % match.group("prefix")
262                self.buildCppClasses(name + "i", Name, suffix + "Imm",
263                        matcher.sub(imm_name, code),
264                        matcher.sub(imm_name, big_code),
265                        matcher.sub(imm_name, flag_code),
266                        matcher.sub(imm_name, cond_check),
267                        matcher.sub(imm_name, else_code),
268                        matcher.sub(imm_name, cond_control_flag_init))
269                return
270
271            # If there's something optional to do with flags, generate
272            # a version without it and fix up this version to use it.
273            if flag_code != "" or cond_check != "true":
274                self.buildCppClasses(name, Name, suffix,
275                        code, big_code, "", "true", else_code, "")
276                suffix = "Flags" + suffix
277
278            # If psrc1 or psrc2 is used, we need to actually insert code to
279            # compute it.
280            for (big, all) in ((False, allCode), (True, allBigCode)):
281                prefix = ""
282                for (rex, decl) in (
283                        ("(?<!\w)psrc1(?!\w)",
284                         "uint64_t psrc1 = pick(SrcReg1, 0, dataSize);"),
285                        ("(?<!\w)psrc2(?!\w)",
286                         "uint64_t psrc2 = pick(SrcReg2, 1, dataSize);"),
287                        ("(?<!\w)spsrc1(?!\w)",
288                         "int64_t spsrc1 = signedPick(SrcReg1, 0, dataSize);"),
289                        ("(?<!\w)spsrc2(?!\w)",
290                         "int64_t spsrc2 = signedPick(SrcReg2, 1, dataSize);"),
291                        ("(?<!\w)simm8(?!\w)",
292                         "int8_t simm8 = imm8;")):
293                    matcher = re.compile(rex)
294                    if matcher.search(all):
295                        prefix += decl + "\n"
296                if big:
297                    if big_code != "":
298                        big_code = prefix + big_code
299                else:
300                    code = prefix + code
301
302            base = "X86ISA::RegOp"
303
304            # If imm8 shows up in the code, use the immediate templates, if
305            # not, hopefully the register ones will be correct.
306            templates = regTemplates
307            matcher = re.compile("(?<!\w)s?imm8(?!\w)")
308            if matcher.search(allCode):
309                base += "Imm"
310                templates = immTemplates
311
312            # Get everything ready for the substitution
313            iops = [InstObjParams(name, Name + suffix, base,
314                    {"code" : code,
315                     "flag_code" : flag_code,
316                     "cond_check" : cond_check,
317                     "else_code" : else_code,
318                     "cond_control_flag_init" : cond_control_flag_init})]
319            if big_code != "":
320                iops += [InstObjParams(name, Name + suffix + "Big", base,
321                         {"code" : big_code,
322                          "flag_code" : flag_code,
323                          "cond_check" : cond_check,
324                          "else_code" : else_code,
325                          "cond_control_flag_init" :
326                              cond_control_flag_init})]
327
328            # Generate the actual code (finally!)
329            for iop in iops:
330                header_output += templates[0].subst(iop)
331                decoder_output += templates[1].subst(iop)
332                exec_output += templates[2].subst(iop)
333
334
335        def __new__(mcls, Name, bases, dict):
336            abstract = False
337            name = Name.lower()
338            if "abstract" in dict:
339                abstract = dict['abstract']
340                del dict['abstract']
341
342            cls = super(RegOpMeta, mcls).__new__(mcls, Name, bases, dict)
343            if not abstract:
344                cls.className = Name
345                cls.base_mnemonic = name
346                code = cls.code
347                big_code = cls.big_code
348                flag_code = cls.flag_code
349                cond_check = cls.cond_check
350                else_code = cls.else_code
351                cond_control_flag_init = cls.cond_control_flag_init
352
353                # Set up the C++ classes
354                mcls.buildCppClasses(cls, name, Name, "", code, big_code,
355                        flag_code, cond_check, else_code,
356                        cond_control_flag_init)
357
358                # Hook into the microassembler dict
359                global microopClasses
360                microopClasses[name] = cls
361
362                allCode = "|".join((code, flag_code, cond_check, else_code,
363                                    cond_control_flag_init))
364
365                # If op2 is used anywhere, make register and immediate versions
366                # of this code.
367                matcher = re.compile(r"op2(?P<typeQual>_[^\W_]+)?")
368                if matcher.search(allCode):
369                    microopClasses[name + 'i'] = cls
370            return cls
371
372
373    class RegOp(X86Microop):
374        __metaclass__ = RegOpMeta
375        # This class itself doesn't act as a microop
376        abstract = True
377
378        # Default template parameter values
379        big_code = ""
380        flag_code = ""
381        cond_check = "true"
382        else_code = ";"
383        cond_control_flag_init = ""
384
385        def __init__(self, dest, src1, op2, flags = None, dataSize = "env.dataSize"):
386            self.dest = dest
387            self.src1 = src1
388            self.op2 = op2
389            self.flags = flags
390            self.dataSize = dataSize
391            if flags is None:
392                self.ext = 0
393            else:
394                if not isinstance(flags, (list, tuple)):
395                    raise Exception, "flags must be a list or tuple of flags"
396                self.ext = " | ".join(flags)
397                self.className += "Flags"
398
399        def getAllocator(self, microFlags):
400            if self.big_code != "":
401                className = self.className
402                if self.mnemonic == self.base_mnemonic + 'i':
403                    className += "Imm"
404                allocString = '''
405                    (%(dataSize)s >= 4) ?
406                        (StaticInstPtr)(new %(class_name)sBig(machInst,
407                            macrocodeBlock, %(flags)s, %(src1)s, %(op2)s,
408                            %(dest)s, %(dataSize)s, %(ext)s)) :
409                        (StaticInstPtr)(new %(class_name)s(machInst,
410                            macrocodeBlock, %(flags)s, %(src1)s, %(op2)s,
411                            %(dest)s, %(dataSize)s, %(ext)s))
412                    '''
413                allocator = allocString % {
414                    "class_name" : className,
415                    "flags" : self.microFlagsText(microFlags),
416                    "src1" : self.src1, "op2" : self.op2,
417                    "dest" : self.dest,
418                    "dataSize" : self.dataSize,
419                    "ext" : self.ext}
420                return allocator
421            else:
422                className = self.className
423                if self.mnemonic == self.base_mnemonic + 'i':
424                    className += "Imm"
425                allocator = '''new %(class_name)s(machInst, macrocodeBlock,
426                        %(flags)s, %(src1)s, %(op2)s, %(dest)s,
427                        %(dataSize)s, %(ext)s)''' % {
428                    "class_name" : className,
429                    "flags" : self.microFlagsText(microFlags),
430                    "src1" : self.src1, "op2" : self.op2,
431                    "dest" : self.dest,
432                    "dataSize" : self.dataSize,
433                    "ext" : self.ext}
434                return allocator
435
436    class LogicRegOp(RegOp):
437        abstract = True
438        flag_code = '''
439            //Don't have genFlags handle the OF or CF bits
440            uint64_t mask = CFBit | ECFBit | OFBit;
441            uint64_t newFlags = genFlags(PredccFlagBits | PreddfBit |
442                                 PredezfBit, ext & ~mask, result, psrc1, op2);
443            PredezfBit = newFlags & EZFBit;
444            PreddfBit = newFlags & DFBit;
445            PredccFlagBits = newFlags & ccFlagMask;
446
447            //If a logic microop wants to set these, it wants to set them to 0.
448            PredcfofBits = PredcfofBits & ~((CFBit | OFBit) & ext);
449            PredecfBit = PredecfBit & ~(ECFBit & ext);
450        '''
451
452    class FlagRegOp(RegOp):
453        abstract = True
454        flag_code = '''
455            uint64_t newFlags = genFlags(PredccFlagBits | PredcfofBits |
456                                    PreddfBit | PredecfBit | PredezfBit,
457                                    ext, result, psrc1, op2);
458
459            PredcfofBits = newFlags & cfofMask;
460            PredecfBit = newFlags & ECFBit;
461            PredezfBit = newFlags & EZFBit;
462            PreddfBit = newFlags & DFBit;
463            PredccFlagBits = newFlags & ccFlagMask;
464        '''
465
466    class SubRegOp(RegOp):
467        abstract = True
468        flag_code = '''
469            uint64_t newFlags = genFlags(PredccFlagBits | PredcfofBits |
470                                         PreddfBit | PredecfBit | PredezfBit,
471                                         ext, result, psrc1, ~op2, true);
472
473            PredcfofBits = newFlags & cfofMask;
474            PredecfBit = newFlags & ECFBit;
475            PredezfBit = newFlags & EZFBit;
476            PreddfBit = newFlags & DFBit;
477            PredccFlagBits = newFlags & ccFlagMask;
478        '''
479
480    class CondRegOp(RegOp):
481        abstract = True
482        cond_check = "checkCondition(ccFlagBits | cfofBits | dfBit | ecfBit | \
483                                     ezfBit, ext)"
484        cond_control_flag_init = "flags[IsCondControl] = flags[IsControl];"
485
486    class RdRegOp(RegOp):
487        abstract = True
488        def __init__(self, dest, src1=None, dataSize="env.dataSize"):
489            if not src1:
490                src1 = dest
491            super(RdRegOp, self).__init__(dest, src1, \
492                    "InstRegIndex(NUM_INTREGS)", None, dataSize)
493
494    class WrRegOp(RegOp):
495        abstract = True
496        def __init__(self, src1, src2, flags=None, dataSize="env.dataSize"):
497            super(WrRegOp, self).__init__("InstRegIndex(NUM_INTREGS)", \
498                    src1, src2, flags, dataSize)
499
500    class Add(FlagRegOp):
501        code = 'DestReg = merge(DestReg, result = (psrc1 + op2), dataSize);'
502        big_code = 'DestReg = result = (psrc1 + op2) & mask(dataSize * 8);'
503
504    class Or(LogicRegOp):
505        code = 'DestReg = merge(DestReg, result = (psrc1 | op2), dataSize);'
506        big_code = 'DestReg = result = (psrc1 | op2) & mask(dataSize * 8);'
507
508    class Adc(FlagRegOp):
509        code = '''
510            CCFlagBits flags = cfofBits;
511            DestReg = merge(DestReg, result = (psrc1 + op2 + flags.cf), dataSize);
512            '''
513        big_code = '''
514            CCFlagBits flags = cfofBits;
515            DestReg = result = (psrc1 + op2 + flags.cf) & mask(dataSize * 8);
516            '''
517
518    class Sbb(SubRegOp):
519        code = '''
520            CCFlagBits flags = cfofBits;
521            DestReg = merge(DestReg, result = (psrc1 - op2 - flags.cf), dataSize);
522            '''
523        big_code = '''
524            CCFlagBits flags = cfofBits;
525            DestReg = result = (psrc1 - op2 - flags.cf) & mask(dataSize * 8);
526            '''
527
528    class And(LogicRegOp):
529        code = 'DestReg = merge(DestReg, result = (psrc1 & op2), dataSize)'
530        big_code = 'DestReg = result = (psrc1 & op2) & mask(dataSize * 8)'
531
532    class Sub(SubRegOp):
533        code = 'DestReg = merge(DestReg, result = (psrc1 - op2), dataSize)'
534        big_code = 'DestReg = result = (psrc1 - op2) & mask(dataSize * 8)'
535
536    class Xor(LogicRegOp):
537        code = 'DestReg = merge(DestReg, result = (psrc1 ^ op2), dataSize)'
538        big_code = 'DestReg = result = (psrc1 ^ op2) & mask(dataSize * 8)'
539
540    class Mul1s(WrRegOp):
541        code = '''
542            ProdLow = psrc1 * op2;
543            int halfSize = (dataSize * 8) / 2;
544            uint64_t shifter = (ULL(1) << halfSize);
545            uint64_t hiResult;
546            uint64_t psrc1_h = psrc1 / shifter;
547            uint64_t psrc1_l = psrc1 & mask(halfSize);
548            uint64_t psrc2_h = (op2 / shifter) & mask(halfSize);
549            uint64_t psrc2_l = op2 & mask(halfSize);
550            hiResult = ((psrc1_l * psrc2_h + psrc1_h * psrc2_l +
551                        ((psrc1_l * psrc2_l) / shifter)) /shifter) +
552                       psrc1_h * psrc2_h;
553            if (bits(psrc1, dataSize * 8 - 1))
554                hiResult -= op2;
555            if (bits(op2, dataSize * 8 - 1))
556                hiResult -= psrc1;
557            ProdHi = hiResult;
558            '''
559        flag_code = '''
560            if ((-ProdHi & mask(dataSize * 8)) !=
561                    bits(ProdLow, dataSize * 8 - 1)) {
562                PredcfofBits = PredcfofBits | (ext & (CFBit | OFBit));
563                PredecfBit = PredecfBit | (ext & ECFBit);
564            } else {
565                PredcfofBits = PredcfofBits & ~(ext & (CFBit | OFBit));
566                PredecfBit = PredecfBit & ~(ext & ECFBit);
567            }
568        '''
569
570    class Mul1u(WrRegOp):
571        code = '''
572            ProdLow = psrc1 * op2;
573            int halfSize = (dataSize * 8) / 2;
574            uint64_t shifter = (ULL(1) << halfSize);
575            uint64_t psrc1_h = psrc1 / shifter;
576            uint64_t psrc1_l = psrc1 & mask(halfSize);
577            uint64_t psrc2_h = (op2 / shifter) & mask(halfSize);
578            uint64_t psrc2_l = op2 & mask(halfSize);
579            ProdHi = ((psrc1_l * psrc2_h + psrc1_h * psrc2_l +
580                      ((psrc1_l * psrc2_l) / shifter)) / shifter) +
581                     psrc1_h * psrc2_h;
582            '''
583        flag_code = '''
584            if (ProdHi) {
585                PredcfofBits = PredcfofBits | (ext & (CFBit | OFBit));
586                PredecfBit = PredecfBit | (ext & ECFBit);
587            } else {
588                PredcfofBits = PredcfofBits & ~(ext & (CFBit | OFBit));
589                PredecfBit = PredecfBit & ~(ext & ECFBit);
590            }
591        '''
592
593    class Mulel(RdRegOp):
594        code = 'DestReg = merge(SrcReg1, ProdLow, dataSize);'
595        big_code = 'DestReg = ProdLow & mask(dataSize * 8);'
596
597    class Muleh(RdRegOp):
598        def __init__(self, dest, src1=None, flags=None, dataSize="env.dataSize"):
599            if not src1:
600                src1 = dest
601            super(RdRegOp, self).__init__(dest, src1, \
602                    "InstRegIndex(NUM_INTREGS)", flags, dataSize)
603        code = 'DestReg = merge(SrcReg1, ProdHi, dataSize);'
604        big_code = 'DestReg = ProdHi & mask(dataSize * 8);'
605
606    # One or two bit divide
607    class Div1(WrRegOp):
608        code = '''
609            //These are temporaries so that modifying them later won't make
610            //the ISA parser think they're also sources.
611            uint64_t quotient = 0;
612            uint64_t remainder = psrc1;
613            //Similarly, this is a temporary so changing it doesn't make it
614            //a source.
615            uint64_t divisor = op2;
616            //This is a temporary just for consistency and clarity.
617            uint64_t dividend = remainder;
618            //Do the division.
619            if (divisor == 0) {
620                fault = new DivideByZero;
621            } else {
622                divide(dividend, divisor, quotient, remainder);
623                //Record the final results.
624                Remainder = remainder;
625                Quotient = quotient;
626                Divisor = divisor;
627            }
628            '''
629
630    # Step divide
631    class Div2(RegOp):
632        divCode = '''
633            uint64_t dividend = Remainder;
634            uint64_t divisor = Divisor;
635            uint64_t quotient = Quotient;
636            uint64_t remainder = dividend;
637            int remaining = op2;
638            //If we overshot, do nothing. This lets us unrool division loops a
639            //little.
640            if (divisor == 0) {
641                fault = new DivideByZero;
642            } else if (remaining) {
643                if (divisor & (ULL(1) << 63)) {
644                    while (remaining && !(dividend & (ULL(1) << 63))) {
645                        dividend = (dividend << 1) |
646                            bits(SrcReg1, remaining - 1);
647                        quotient <<= 1;
648                        remaining--;
649                    }
650                    if (dividend & (ULL(1) << 63)) {
651                        bool highBit = false;
652                        if (dividend < divisor && remaining) {
653                            highBit = true;
654                            dividend = (dividend << 1) |
655                                bits(SrcReg1, remaining - 1);
656                            quotient <<= 1;
657                            remaining--;
658                        }
659                        if (highBit || divisor <= dividend) {
660                            quotient++;
661                            dividend -= divisor;
662                        }
663                    }
664                    remainder = dividend;
665                } else {
666                    //Shift in bits from the low order portion of the dividend
667                    while (dividend < divisor && remaining) {
668                        dividend = (dividend << 1) |
669                            bits(SrcReg1, remaining - 1);
670                        quotient <<= 1;
671                        remaining--;
672                    }
673                    remainder = dividend;
674                    //Do the division.
675                    divide(dividend, divisor, quotient, remainder);
676                }
677            }
678            //Keep track of how many bits there are still to pull in.
679            %s
680            //Record the final results
681            Remainder = remainder;
682            Quotient = quotient;
683        '''
684        code = divCode % "DestReg = merge(DestReg, remaining, dataSize);"
685        big_code = divCode % "DestReg = remaining & mask(dataSize * 8);"
686        flag_code = '''
687            if (remaining == 0)
688                PredezfBit = PredezfBit | (ext & EZFBit);
689            else
690                PredezfBit = PredezfBit & ~(ext & EZFBit);
691        '''
692
693    class Divq(RdRegOp):
694        code = 'DestReg = merge(SrcReg1, Quotient, dataSize);'
695        big_code = 'DestReg = Quotient & mask(dataSize * 8);'
696
697    class Divr(RdRegOp):
698        code = 'DestReg = merge(SrcReg1, Remainder, dataSize);'
699        big_code = 'DestReg = Remainder & mask(dataSize * 8);'
700
701    class Mov(CondRegOp):
702        code = 'DestReg = merge(SrcReg1, op2, dataSize)'
703        else_code = 'DestReg = DestReg;'
704
705    # Shift instructions
706
707    class Sll(RegOp):
708        code = '''
709            uint8_t shiftAmt = (op2 & ((dataSize == 8) ? mask(6) : mask(5)));
710            DestReg = merge(DestReg, psrc1 << shiftAmt, dataSize);
711            '''
712        big_code = '''
713            uint8_t shiftAmt = (op2 & ((dataSize == 8) ? mask(6) : mask(5)));
714            DestReg = (psrc1 << shiftAmt) & mask(dataSize * 8);
715            '''
716        flag_code = '''
717            // If the shift amount is zero, no flags should be modified.
718            if (shiftAmt) {
719                //Zero out any flags we might modify. This way we only have to
720                //worry about setting them.
721                PredcfofBits = PredcfofBits & ~(ext & (CFBit | OFBit));
722                PredecfBit = PredecfBit & ~(ext & ECFBit);
723
724                int CFBits = 0;
725                //Figure out if we -would- set the CF bits if requested.
726                if (shiftAmt <= dataSize * 8 &&
727                        bits(SrcReg1, dataSize * 8 - shiftAmt)) {
728                    CFBits = 1;
729                }
730
731                //If some combination of the CF bits need to be set, set them.
732                if ((ext & (CFBit | ECFBit)) && CFBits) {
733                    PredcfofBits = PredcfofBits | (ext & CFBit);
734                    PredecfBit = PredecfBit | (ext & ECFBit);
735                }
736
737                //Figure out what the OF bit should be.
738                if ((ext & OFBit) && (CFBits ^ bits(DestReg, dataSize * 8 - 1)))
739                    PredcfofBits = PredcfofBits | OFBit;
740
741                //Use the regular mechanisms to calculate the other flags.
742                uint64_t newFlags = genFlags(PredccFlagBits | PreddfBit |
743                                PredezfBit, ext & ~(CFBit | ECFBit | OFBit),
744                                DestReg, psrc1, op2);
745
746                PredezfBit = newFlags & EZFBit;
747                PreddfBit = newFlags & DFBit;
748                PredccFlagBits = newFlags & ccFlagMask;
749            }
750        '''
751
752    class Srl(RegOp):
753        # Because what happens to the bits shift -in- on a right shift
754        # is not defined in the C/C++ standard, we have to mask them out
755        # to be sure they're zero.
756        code = '''
757            uint8_t shiftAmt = (op2 & ((dataSize == 8) ? mask(6) : mask(5)));
758            uint64_t logicalMask = mask(dataSize * 8 - shiftAmt);
759            DestReg = merge(DestReg, (psrc1 >> shiftAmt) & logicalMask, dataSize);
760            '''
761        big_code = '''
762            uint8_t shiftAmt = (op2 & ((dataSize == 8) ? mask(6) : mask(5)));
763            uint64_t logicalMask = mask(dataSize * 8 - shiftAmt);
764            DestReg = (psrc1 >> shiftAmt) & logicalMask;
765            '''
766        flag_code = '''
767            // If the shift amount is zero, no flags should be modified.
768            if (shiftAmt) {
769                //Zero out any flags we might modify. This way we only have to
770                //worry about setting them.
771                PredcfofBits = PredcfofBits & ~(ext & (CFBit | OFBit));
772                PredecfBit = PredecfBit & ~(ext & ECFBit);
773
774                //If some combination of the CF bits need to be set, set them.
775                if ((ext & (CFBit | ECFBit)) && 
776                        shiftAmt <= dataSize * 8 &&
777                        bits(SrcReg1, shiftAmt - 1)) {
778                    PredcfofBits = PredcfofBits | (ext & CFBit);
779                    PredecfBit = PredecfBit | (ext & ECFBit);
780                }
781
782                //Figure out what the OF bit should be.
783                if ((ext & OFBit) && bits(SrcReg1, dataSize * 8 - 1))
784                    PredcfofBits = PredcfofBits | OFBit;
785
786                //Use the regular mechanisms to calculate the other flags.
787                uint64_t newFlags = genFlags(PredccFlagBits | PreddfBit |
788                                PredezfBit, ext & ~(CFBit | ECFBit | OFBit),
789                                DestReg, psrc1, op2);
790
791                PredezfBit = newFlags & EZFBit;
792                PreddfBit = newFlags & DFBit;
793                PredccFlagBits = newFlags & ccFlagMask;
794            }
795        '''
796
797    class Sra(RegOp):
798        # Because what happens to the bits shift -in- on a right shift
799        # is not defined in the C/C++ standard, we have to sign extend
800        # them manually to be sure.
801        code = '''
802            uint8_t shiftAmt = (op2 & ((dataSize == 8) ? mask(6) : mask(5)));
803            uint64_t arithMask = (shiftAmt == 0) ? 0 :
804                -bits(psrc1, dataSize * 8 - 1) << (dataSize * 8 - shiftAmt);
805            DestReg = merge(DestReg, (psrc1 >> shiftAmt) | arithMask, dataSize);
806            '''
807        big_code = '''
808            uint8_t shiftAmt = (op2 & ((dataSize == 8) ? mask(6) : mask(5)));
809            uint64_t arithMask = (shiftAmt == 0) ? 0 :
810                -bits(psrc1, dataSize * 8 - 1) << (dataSize * 8 - shiftAmt);
811            DestReg = ((psrc1 >> shiftAmt) | arithMask) & mask(dataSize * 8);
812            '''
813        flag_code = '''
814            // If the shift amount is zero, no flags should be modified.
815            if (shiftAmt) {
816                //Zero out any flags we might modify. This way we only have to
817                //worry about setting them.
818                PredcfofBits = PredcfofBits & ~(ext & (CFBit | OFBit));
819                PredecfBit = PredecfBit & ~(ext & ECFBit);
820
821                //If some combination of the CF bits need to be set, set them.
822                uint8_t effectiveShift =
823                    (shiftAmt <= dataSize * 8) ? shiftAmt : (dataSize * 8);
824                if ((ext & (CFBit | ECFBit)) &&
825                        bits(SrcReg1, effectiveShift - 1)) {
826                    PredcfofBits = PredcfofBits | (ext & CFBit);
827                    PredecfBit = PredecfBit | (ext & ECFBit);
828                }
829
830                //Use the regular mechanisms to calculate the other flags.
831                uint64_t newFlags = genFlags(PredccFlagBits | PreddfBit |
832                                PredezfBit, ext & ~(CFBit | ECFBit | OFBit),
833                                DestReg, psrc1, op2);
834
835                PredezfBit = newFlags & EZFBit;
836                PreddfBit = newFlags & DFBit;
837                PredccFlagBits = newFlags & ccFlagMask;
838            }
839        '''
840
841    class Ror(RegOp):
842        code = '''
843            uint8_t shiftAmt =
844                (op2 & ((dataSize == 8) ? mask(6) : mask(5)));
845            uint8_t realShiftAmt = shiftAmt % (dataSize * 8);
846            if (realShiftAmt) {
847                uint64_t top = psrc1 << (dataSize * 8 - realShiftAmt);
848                uint64_t bottom = bits(psrc1, dataSize * 8, realShiftAmt);
849                DestReg = merge(DestReg, top | bottom, dataSize);
850            } else
851                DestReg = merge(DestReg, DestReg, dataSize);
852            '''
853        flag_code = '''
854            // If the shift amount is zero, no flags should be modified.
855            if (shiftAmt) {
856                //Zero out any flags we might modify. This way we only have to
857                //worry about setting them.
858                PredcfofBits = PredcfofBits & ~(ext & (CFBit | OFBit));
859                PredecfBit = PredecfBit & ~(ext & ECFBit);
860
861                //Find the most and second most significant bits of the result.
862                int msb = bits(DestReg, dataSize * 8 - 1);
863                int smsb = bits(DestReg, dataSize * 8 - 2);
864                //If some combination of the CF bits need to be set, set them.
865                if ((ext & (CFBit | ECFBit)) && msb) {
866                    PredcfofBits = PredcfofBits | (ext & CFBit);
867                    PredecfBit = PredecfBit | (ext & ECFBit);
868                }
869
870                //Figure out what the OF bit should be.
871                if ((ext & OFBit) && (msb ^ smsb))
872                    PredcfofBits = PredcfofBits | OFBit;
873
874                //Use the regular mechanisms to calculate the other flags.
875                uint64_t newFlags = genFlags(PredccFlagBits | PreddfBit |
876                                PredezfBit, ext & ~(CFBit | ECFBit | OFBit),
877                                DestReg, psrc1, op2);
878
879                PredezfBit = newFlags & EZFBit;
880                PreddfBit = newFlags & DFBit;
881                PredccFlagBits = newFlags & ccFlagMask;
882            }
883        '''
884
885    class Rcr(RegOp):
886        code = '''
887            uint8_t shiftAmt =
888                (op2 & ((dataSize == 8) ? mask(6) : mask(5)));
889            uint8_t realShiftAmt = shiftAmt % (dataSize * 8 + 1);
890            if (realShiftAmt) {
891                CCFlagBits flags = cfofBits;
892                uint64_t top = flags.cf << (dataSize * 8 - realShiftAmt);
893                if (realShiftAmt > 1)
894                    top |= psrc1 << (dataSize * 8 - realShiftAmt + 1);
895                uint64_t bottom = bits(psrc1, dataSize * 8 - 1, realShiftAmt);
896                DestReg = merge(DestReg, top | bottom, dataSize);
897            } else
898                DestReg = merge(DestReg, DestReg, dataSize);
899            '''
900        flag_code = '''
901            // If the shift amount is zero, no flags should be modified.
902            if (shiftAmt) {
903                int origCFBit = (cfofBits & CFBit) ? 1 : 0;
904                //Zero out any flags we might modify. This way we only have to
905                //worry about setting them.
906                PredcfofBits = PredcfofBits & ~(ext & (CFBit | OFBit));
907                PredecfBit = PredecfBit & ~(ext & ECFBit);
908
909                //Figure out what the OF bit should be.
910                if ((ext & OFBit) && (origCFBit ^
911                                      bits(SrcReg1, dataSize * 8 - 1))) {
912                    PredcfofBits = PredcfofBits | OFBit;
913                }
914                //If some combination of the CF bits need to be set, set them.
915                if ((ext & (CFBit | ECFBit)) &&
916                        (realShiftAmt == 0) ? origCFBit :
917                        bits(SrcReg1, realShiftAmt - 1)) {
918                    PredcfofBits = PredcfofBits | (ext & CFBit);
919                    PredecfBit = PredecfBit | (ext & ECFBit);
920                }
921
922                //Use the regular mechanisms to calculate the other flags.
923                uint64_t newFlags = genFlags(PredccFlagBits | PreddfBit |
924                                PredezfBit, ext & ~(CFBit | ECFBit | OFBit),
925                                DestReg, psrc1, op2);
926
927                PredezfBit = newFlags & EZFBit;
928                PreddfBit = newFlags & DFBit;
929                PredccFlagBits = newFlags & ccFlagMask;
930            }
931        '''
932
933    class Rol(RegOp):
934        code = '''
935            uint8_t shiftAmt =
936                (op2 & ((dataSize == 8) ? mask(6) : mask(5)));
937            uint8_t realShiftAmt = shiftAmt % (dataSize * 8);
938            if (realShiftAmt) {
939                uint64_t top = psrc1 << realShiftAmt;
940                uint64_t bottom =
941                    bits(psrc1, dataSize * 8 - 1, dataSize * 8 - realShiftAmt);
942                DestReg = merge(DestReg, top | bottom, dataSize);
943            } else
944                DestReg = merge(DestReg, DestReg, dataSize);
945            '''
946        flag_code = '''
947            // If the shift amount is zero, no flags should be modified.
948            if (shiftAmt) {
949                //Zero out any flags we might modify. This way we only have to
950                //worry about setting them.
951                PredcfofBits = PredcfofBits & ~(ext & (CFBit | OFBit));
952                PredecfBit = PredecfBit & ~(ext & ECFBit);
953
954                //The CF bits, if set, would be set to the lsb of the result.
955                int lsb = DestReg & 0x1;
956                int msb = bits(DestReg, dataSize * 8 - 1);
957                //If some combination of the CF bits need to be set, set them.
958                if ((ext & (CFBit | ECFBit)) && lsb) {
959                    PredcfofBits = PredcfofBits | (ext & CFBit);
960                    PredecfBit = PredecfBit | (ext & ECFBit);
961                }
962
963                //Figure out what the OF bit should be.
964                if ((ext & OFBit) && (msb ^ lsb))
965                    PredcfofBits = PredcfofBits | OFBit;
966
967                //Use the regular mechanisms to calculate the other flags.
968                uint64_t newFlags = genFlags(PredccFlagBits | PreddfBit |
969                                PredezfBit, ext & ~(CFBit | ECFBit | OFBit),
970                                DestReg, psrc1, op2);
971
972                PredezfBit = newFlags & EZFBit;
973                PreddfBit = newFlags & DFBit;
974                PredccFlagBits = newFlags & ccFlagMask;
975            }
976        '''
977
978    class Rcl(RegOp):
979        code = '''
980            uint8_t shiftAmt =
981                (op2 & ((dataSize == 8) ? mask(6) : mask(5)));
982            uint8_t realShiftAmt = shiftAmt % (dataSize * 8 + 1);
983            if (realShiftAmt) {
984                CCFlagBits flags = cfofBits;
985                uint64_t top = psrc1 << realShiftAmt;
986                uint64_t bottom = flags.cf << (realShiftAmt - 1);
987                if(shiftAmt > 1)
988                    bottom |=
989                        bits(psrc1, dataSize * 8 - 1,
990                                   dataSize * 8 - realShiftAmt + 1);
991                DestReg = merge(DestReg, top | bottom, dataSize);
992            } else
993                DestReg = merge(DestReg, DestReg, dataSize);
994            '''
995        flag_code = '''
996            // If the shift amount is zero, no flags should be modified.
997            if (shiftAmt) {
998                int origCFBit = (cfofBits & CFBit) ? 1 : 0;
999                //Zero out any flags we might modify. This way we only have to
1000                //worry about setting them.
1001                PredcfofBits = PredcfofBits & ~(ext & (CFBit | OFBit));
1002                PredecfBit = PredecfBit & ~(ext & ECFBit);
1003
1004                int msb = bits(DestReg, dataSize * 8 - 1);
1005                int CFBits = bits(SrcReg1, dataSize * 8 - realShiftAmt);
1006                //If some combination of the CF bits need to be set, set them.
1007                if ((ext & (CFBit | ECFBit)) && 
1008                        (realShiftAmt == 0) ? origCFBit : CFBits) {
1009                    PredcfofBits = PredcfofBits | (ext & CFBit);
1010                    PredecfBit = PredecfBit | (ext & ECFBit);
1011                }
1012
1013                //Figure out what the OF bit should be.
1014                if ((ext & OFBit) && (msb ^ CFBits))
1015                    PredcfofBits = PredcfofBits | OFBit;
1016
1017                //Use the regular mechanisms to calculate the other flags.
1018                uint64_t newFlags = genFlags(PredccFlagBits | PreddfBit |
1019                                PredezfBit, ext & ~(CFBit | ECFBit | OFBit),
1020                                DestReg, psrc1, op2);
1021
1022                PredezfBit = newFlags & EZFBit;
1023                PreddfBit = newFlags & DFBit;
1024                PredccFlagBits = newFlags & ccFlagMask;
1025            }
1026        '''
1027
1028    class Sld(RegOp):
1029        sldCode = '''
1030            uint8_t shiftAmt = (op2 & ((dataSize == 8) ? mask(6) : mask(5)));
1031            uint8_t dataBits = dataSize * 8;
1032            uint8_t realShiftAmt = shiftAmt %% (2 * dataBits);
1033            uint64_t result;
1034            if (realShiftAmt == 0) {
1035                result = psrc1;
1036            } else if (realShiftAmt < dataBits) {
1037                result = (psrc1 << realShiftAmt) |
1038                         (DoubleBits >> (dataBits - realShiftAmt));
1039            } else {
1040                result = (DoubleBits << (realShiftAmt - dataBits)) |
1041                         (psrc1 >> (2 * dataBits - realShiftAmt));
1042            }
1043            %s
1044            '''
1045        code = sldCode % "DestReg = merge(DestReg, result, dataSize);"
1046        big_code = sldCode % "DestReg = result & mask(dataSize * 8);"
1047        flag_code = '''
1048            // If the shift amount is zero, no flags should be modified.
1049            if (shiftAmt) {
1050                //Zero out any flags we might modify. This way we only have to
1051                //worry about setting them.
1052                PredcfofBits = PredcfofBits & ~(ext & (CFBit | OFBit));
1053                PredecfBit = PredecfBit & ~(ext & ECFBit);
1054                int CFBits = 0;
1055
1056                //Figure out if we -would- set the CF bits if requested.
1057                if ((realShiftAmt == 0 &&
1058                        bits(DoubleBits, 0)) ||
1059                    (realShiftAmt <= dataBits &&
1060                     bits(SrcReg1, dataBits - realShiftAmt)) ||
1061                    (realShiftAmt > dataBits &&
1062                     bits(DoubleBits, 2 * dataBits - realShiftAmt))) {
1063                    CFBits = 1;
1064                }
1065
1066                //If some combination of the CF bits need to be set, set them.
1067                if ((ext & (CFBit | ECFBit)) && CFBits) {
1068                    PredcfofBits = PredcfofBits | (ext & CFBit);
1069                    PredecfBit = PredecfBit | (ext & ECFBit);
1070                }
1071
1072                //Figure out what the OF bit should be.
1073                if ((ext & OFBit) && (bits(SrcReg1, dataBits - 1) ^
1074                                      bits(result, dataBits - 1)))
1075                    PredcfofBits = PredcfofBits | OFBit;
1076
1077                //Use the regular mechanisms to calculate the other flags.
1078                uint64_t newFlags = genFlags(PredccFlagBits | PreddfBit |
1079                                PredezfBit, ext & ~(CFBit | ECFBit | OFBit),
1080                                DestReg, psrc1, op2);
1081
1082                PredezfBit = newFlags & EZFBit;
1083                PreddfBit = newFlags & DFBit;
1084                PredccFlagBits = newFlags & ccFlagMask;
1085            }
1086        '''
1087
1088    class Srd(RegOp):
1089        srdCode = '''
1090            uint8_t shiftAmt = (op2 & ((dataSize == 8) ? mask(6) : mask(5)));
1091            uint8_t dataBits = dataSize * 8;
1092            uint8_t realShiftAmt = shiftAmt %% (2 * dataBits);
1093            uint64_t result;
1094            if (realShiftAmt == 0) {
1095                result = psrc1;
1096            } else if (realShiftAmt < dataBits) {
1097                // Because what happens to the bits shift -in- on a right
1098                // shift is not defined in the C/C++ standard, we have to
1099                // mask them out to be sure they're zero.
1100                uint64_t logicalMask = mask(dataBits - realShiftAmt);
1101                result = ((psrc1 >> realShiftAmt) & logicalMask) |
1102                         (DoubleBits << (dataBits - realShiftAmt));
1103            } else {
1104                uint64_t logicalMask = mask(2 * dataBits - realShiftAmt);
1105                result = ((DoubleBits >> (realShiftAmt - dataBits)) &
1106                          logicalMask) |
1107                         (psrc1 << (2 * dataBits - realShiftAmt));
1108            }
1109            %s
1110            '''
1111        code = srdCode % "DestReg = merge(DestReg, result, dataSize);"
1112        big_code = srdCode % "DestReg = result & mask(dataSize * 8);"
1113        flag_code = '''
1114            // If the shift amount is zero, no flags should be modified.
1115            if (shiftAmt) {
1116                //Zero out any flags we might modify. This way we only have to
1117                //worry about setting them.
1118                PredcfofBits = PredcfofBits & ~(ext & (CFBit | OFBit));
1119                PredecfBit = PredecfBit & ~(ext & ECFBit);
1120                int CFBits = 0;
1121
1122                //If some combination of the CF bits need to be set, set them.
1123                if ((realShiftAmt == 0 &&
1124                            bits(DoubleBits, dataBits - 1)) ||
1125                        (realShiftAmt <= dataBits &&
1126                         bits(SrcReg1, realShiftAmt - 1)) ||
1127                        (realShiftAmt > dataBits &&
1128                         bits(DoubleBits, realShiftAmt - dataBits - 1))) {
1129                    CFBits = 1;
1130                }
1131
1132                //If some combination of the CF bits need to be set, set them.
1133                if ((ext & (CFBit | ECFBit)) && CFBits) {
1134                    PredcfofBits = PredcfofBits | (ext & CFBit);
1135                    PredecfBit = PredecfBit | (ext & ECFBit);
1136                }
1137
1138                //Figure out what the OF bit should be.
1139                if ((ext & OFBit) && (bits(SrcReg1, dataBits - 1) ^
1140                                      bits(result, dataBits - 1)))
1141                    PredcfofBits = PredcfofBits | OFBit;
1142
1143                //Use the regular mechanisms to calculate the other flags.
1144                uint64_t newFlags = genFlags(PredccFlagBits | PreddfBit |
1145                                PredezfBit, ext & ~(CFBit | ECFBit | OFBit),
1146                                DestReg, psrc1, op2);
1147
1148                PredezfBit = newFlags & EZFBit;
1149                PreddfBit = newFlags & DFBit;
1150                PredccFlagBits = newFlags & ccFlagMask;
1151            }
1152        '''
1153
1154    class Mdb(WrRegOp):
1155        code = 'DoubleBits = psrc1 ^ op2;'
1156
1157    class Wrip(WrRegOp, CondRegOp):
1158        code = 'NRIP = psrc1 + sop2 + CSBase;'
1159        else_code = "NRIP = NRIP;"
1160
1161    class Wruflags(WrRegOp):
1162        code = '''
1163            uint64_t newFlags = psrc1 ^ op2;
1164            cfofBits = newFlags & cfofMask;
1165            ecfBit = newFlags & ECFBit;
1166            ezfBit = newFlags & EZFBit;
1167            dfBit = newFlags & DFBit;
1168            ccFlagBits = newFlags & ccFlagMask;
1169        '''
1170
1171    class Wrflags(WrRegOp):
1172        code = '''
1173            MiscReg newFlags = psrc1 ^ op2;
1174            MiscReg userFlagMask = 0xDD5;
1175
1176            // Get only the user flags
1177            ccFlagBits = newFlags & ccFlagMask;
1178            dfBit = newFlags & DFBit;
1179            cfofBits = newFlags & cfofMask;
1180            ecfBit = 0;
1181            ezfBit = 0;
1182
1183            // Get everything else
1184            nccFlagBits = newFlags & ~userFlagMask;
1185        '''
1186
1187    class Rdip(RdRegOp):
1188        code = 'DestReg = NRIP - CSBase;'
1189
1190    class Ruflags(RdRegOp):
1191        code = 'DestReg = ccFlagBits | cfofBits | dfBit | ecfBit | ezfBit;'
1192
1193    class Rflags(RdRegOp):
1194        code = '''
1195            DestReg = ccFlagBits | cfofBits | dfBit |
1196                      ecfBit | ezfBit | nccFlagBits;
1197            '''
1198
1199    class Ruflag(RegOp):
1200        code = '''
1201            int flag = bits(ccFlagBits | cfofBits | dfBit |
1202                            ecfBit | ezfBit, imm8);
1203            DestReg = merge(DestReg, flag, dataSize);
1204            ezfBit = (flag == 0) ? EZFBit : 0;
1205            '''
1206
1207        big_code = '''
1208            int flag = bits(ccFlagBits | cfofBits | dfBit |
1209                            ecfBit | ezfBit, imm8);
1210            DestReg = flag & mask(dataSize * 8);
1211            ezfBit = (flag == 0) ? EZFBit : 0;
1212            '''
1213
1214        def __init__(self, dest, imm, flags=None, \
1215                dataSize="env.dataSize"):
1216            super(Ruflag, self).__init__(dest, \
1217                    "InstRegIndex(NUM_INTREGS)", imm, flags, dataSize)
1218
1219    class Rflag(RegOp):
1220        code = '''
1221            MiscReg flagMask = 0x3F7FDD5;
1222            MiscReg flags = (nccFlagBits | ccFlagBits | cfofBits | dfBit |
1223                             ecfBit | ezfBit) & flagMask;
1224
1225            int flag = bits(flags, imm8);
1226            DestReg = merge(DestReg, flag, dataSize);
1227            ezfBit = (flag == 0) ? EZFBit : 0;
1228            '''
1229
1230        big_code = '''
1231            MiscReg flagMask = 0x3F7FDD5;
1232            MiscReg flags = (nccFlagBits | ccFlagBits | cfofBits | dfBit |
1233                             ecfBit | ezfBit) & flagMask;
1234
1235            int flag = bits(flags, imm8);
1236            DestReg = flag & mask(dataSize * 8);
1237            ezfBit = (flag == 0) ? EZFBit : 0;
1238            '''
1239
1240        def __init__(self, dest, imm, flags=None, \
1241                dataSize="env.dataSize"):
1242            super(Rflag, self).__init__(dest, \
1243                    "InstRegIndex(NUM_INTREGS)", imm, flags, dataSize)
1244
1245    class Sext(RegOp):
1246        code = '''
1247            IntReg val = psrc1;
1248            // Mask the bit position so that it wraps.
1249            int bitPos = op2 & (dataSize * 8 - 1);
1250            int sign_bit = bits(val, bitPos, bitPos);
1251            uint64_t maskVal = mask(bitPos+1);
1252            val = sign_bit ? (val | ~maskVal) : (val & maskVal);
1253            DestReg = merge(DestReg, val, dataSize);
1254            '''
1255
1256        big_code = '''
1257            IntReg val = psrc1;
1258            // Mask the bit position so that it wraps.
1259            int bitPos = op2 & (dataSize * 8 - 1);
1260            int sign_bit = bits(val, bitPos, bitPos);
1261            uint64_t maskVal = mask(bitPos+1);
1262            val = sign_bit ? (val | ~maskVal) : (val & maskVal);
1263            DestReg = val & mask(dataSize * 8);
1264            '''
1265
1266        flag_code = '''
1267            if (!sign_bit) {
1268                PredccFlagBits = PredccFlagBits & ~(ext & (ZFBit));
1269                PredcfofBits = PredcfofBits & ~(ext & (CFBit));
1270                PredecfBit = PredecfBit & ~(ext & ECFBit);
1271                PredezfBit = PredezfBit & ~(ext & EZFBit);
1272            } else {
1273                PredccFlagBits = PredccFlagBits | (ext & (ZFBit));
1274                PredcfofBits = PredcfofBits | (ext & (CFBit));
1275                PredecfBit = PredecfBit | (ext & ECFBit);
1276                PredezfBit = PredezfBit | (ext & EZFBit);
1277            }
1278            '''
1279
1280    class Zext(RegOp):
1281        code = 'DestReg = merge(DestReg, bits(psrc1, op2, 0), dataSize);'
1282        big_code = 'DestReg = bits(psrc1, op2, 0) & mask(dataSize * 8);'
1283
1284    class Rddr(RegOp):
1285        def __init__(self, dest, src1, flags=None, dataSize="env.dataSize"):
1286            super(Rddr, self).__init__(dest, \
1287                    src1, "InstRegIndex(NUM_INTREGS)", flags, dataSize)
1288        rdrCode = '''
1289            CR4 cr4 = CR4Op;
1290            DR7 dr7 = DR7Op;
1291            if ((cr4.de == 1 && (src1 == 4 || src1 == 5)) || src1 >= 8) {
1292                fault = new InvalidOpcode();
1293            } else if (dr7.gd) {
1294                fault = new DebugException();
1295            } else {
1296                %s
1297            }
1298        '''
1299        code = rdrCode % "DestReg = merge(DestReg, DebugSrc1, dataSize);"
1300        big_code = rdrCode % "DestReg = DebugSrc1 & mask(dataSize * 8);"
1301
1302    class Wrdr(RegOp):
1303        def __init__(self, dest, src1, flags=None, dataSize="env.dataSize"):
1304            super(Wrdr, self).__init__(dest, \
1305                    src1, "InstRegIndex(NUM_INTREGS)", flags, dataSize)
1306        code = '''
1307            CR4 cr4 = CR4Op;
1308            DR7 dr7 = DR7Op;
1309            if ((cr4.de == 1 && (dest == 4 || dest == 5)) || dest >= 8) {
1310                fault = new InvalidOpcode();
1311            } else if ((dest == 6 || dest == 7) && bits(psrc1, 63, 32) &&
1312                    machInst.mode.mode == LongMode) {
1313                fault = new GeneralProtection(0);
1314            } else if (dr7.gd) {
1315                fault = new DebugException();
1316            } else {
1317                DebugDest = psrc1;
1318            }
1319        '''
1320
1321    class Rdcr(RegOp):
1322        def __init__(self, dest, src1, flags=None, dataSize="env.dataSize"):
1323            super(Rdcr, self).__init__(dest, \
1324                    src1, "InstRegIndex(NUM_INTREGS)", flags, dataSize)
1325        rdcrCode = '''
1326            if (src1 == 1 || (src1 > 4 && src1 < 8) || (src1 > 8)) {
1327                fault = new InvalidOpcode();
1328            } else {
1329                %s
1330            }
1331        '''
1332        code = rdcrCode % "DestReg = merge(DestReg, ControlSrc1, dataSize);"
1333        big_code = rdcrCode % "DestReg = ControlSrc1 & mask(dataSize * 8);"
1334
1335    class Wrcr(RegOp):
1336        def __init__(self, dest, src1, flags=None, dataSize="env.dataSize"):
1337            super(Wrcr, self).__init__(dest, \
1338                    src1, "InstRegIndex(NUM_INTREGS)", flags, dataSize)
1339        code = '''
1340            if (dest == 1 || (dest > 4 && dest < 8) || (dest > 8)) {
1341                fault = new InvalidOpcode();
1342            } else {
1343                // There are *s in the line below so it doesn't confuse the
1344                // parser. They may be unnecessary.
1345                //Mis*cReg old*Val = pick(Cont*rolDest, 0, dat*aSize);
1346                MiscReg newVal = psrc1;
1347
1348                // Check for any modifications that would cause a fault.
1349                switch(dest) {
1350                  case 0:
1351                    {
1352                        Efer efer = EferOp;
1353                        CR0 cr0 = newVal;
1354                        CR4 oldCr4 = CR4Op;
1355                        if (bits(newVal, 63, 32) ||
1356                                (!cr0.pe && cr0.pg) ||
1357                                (!cr0.cd && cr0.nw) ||
1358                                (cr0.pg && efer.lme && !oldCr4.pae))
1359                            fault = new GeneralProtection(0);
1360                    }
1361                    break;
1362                  case 2:
1363                    break;
1364                  case 3:
1365                    break;
1366                  case 4:
1367                    {
1368                        CR4 cr4 = newVal;
1369                        // PAE can't be disabled in long mode.
1370                        if (bits(newVal, 63, 11) ||
1371                                (machInst.mode.mode == LongMode && !cr4.pae))
1372                            fault = new GeneralProtection(0);
1373                    }
1374                    break;
1375                  case 8:
1376                    {
1377                        if (bits(newVal, 63, 4))
1378                            fault = new GeneralProtection(0);
1379                    }
1380                  default:
1381                    fault = new GenericISA::M5PanicFault(
1382                            "Unrecognized control register %d.\\n", dest);
1383                }
1384                ControlDest = newVal;
1385            }
1386            '''
1387
1388    # Microops for manipulating segmentation registers
1389    class SegOp(CondRegOp):
1390        abstract = True
1391        def __init__(self, dest, src1, flags=None, dataSize="env.dataSize"):
1392            super(SegOp, self).__init__(dest, \
1393                    src1, "InstRegIndex(NUM_INTREGS)", flags, dataSize)
1394
1395    class Wrbase(SegOp):
1396        code = '''
1397            SegBaseDest = psrc1;
1398        '''
1399
1400    class Wrlimit(SegOp):
1401        code = '''
1402            SegLimitDest = psrc1;
1403        '''
1404
1405    class Wrsel(SegOp):
1406        code = '''
1407            SegSelDest = psrc1;
1408        '''
1409
1410    class WrAttr(SegOp):
1411        code = '''
1412            SegAttrDest = psrc1;
1413        '''
1414
1415    class Rdbase(SegOp):
1416        code = 'DestReg = merge(DestReg, SegBaseSrc1, dataSize);'
1417        big_code = 'DestReg = SegBaseSrc1 & mask(dataSize * 8);'
1418
1419    class Rdlimit(SegOp):
1420        code = 'DestReg = merge(DestReg, SegLimitSrc1, dataSize);'
1421        big_code = 'DestReg = SegLimitSrc1 & mask(dataSize * 8);'
1422
1423    class RdAttr(SegOp):
1424        code = 'DestReg = merge(DestReg, SegAttrSrc1, dataSize);'
1425        big_code = 'DestReg = SegAttrSrc1 & mask(dataSize * 8);'
1426
1427    class Rdsel(SegOp):
1428        code = 'DestReg = merge(DestReg, SegSelSrc1, dataSize);'
1429        big_code = 'DestReg = SegSelSrc1 & mask(dataSize * 8);'
1430
1431    class Rdval(RegOp):
1432        def __init__(self, dest, src1, flags=None, dataSize="env.dataSize"):
1433            super(Rdval, self).__init__(dest, src1, \
1434                    "InstRegIndex(NUM_INTREGS)", flags, dataSize)
1435        code = '''
1436            DestReg = MiscRegSrc1;
1437        '''
1438
1439    class Wrval(RegOp):
1440        def __init__(self, dest, src1, flags=None, dataSize="env.dataSize"):
1441            super(Wrval, self).__init__(dest, src1, \
1442                    "InstRegIndex(NUM_INTREGS)", flags, dataSize)
1443        code = '''
1444            MiscRegDest = SrcReg1;
1445        '''
1446
1447    class Chks(RegOp):
1448        def __init__(self, dest, src1, src2=0,
1449                flags=None, dataSize="env.dataSize"):
1450            super(Chks, self).__init__(dest,
1451                    src1, src2, flags, dataSize)
1452        code = '''
1453            // The selector is in source 1 and can be at most 16 bits.
1454            SegSelector selector = DestReg;
1455            SegDescriptor desc = SrcReg1;
1456            HandyM5Reg m5reg = M5Reg;
1457
1458            switch (imm8)
1459            {
1460              case SegNoCheck:
1461                break;
1462              case SegCSCheck:
1463                // Make sure it's the right type
1464                if (desc.s == 0 || desc.type.codeOrData != 1) {
1465                    fault = new GeneralProtection(0);
1466                } else if (m5reg.cpl != desc.dpl) {
1467                    fault = new GeneralProtection(0);
1468                }
1469                break;
1470              case SegCallGateCheck:
1471                fault = new GenericISA::M5PanicFault("CS checks for far "
1472                        "calls/jumps through call gates not implemented.\\n");
1473                break;
1474              case SegSoftIntGateCheck:
1475                // Check permissions.
1476                if (desc.dpl < m5reg.cpl) {
1477                    fault = new GeneralProtection(selector);
1478                    break;
1479                }
1480                // Fall through on purpose
1481              case SegIntGateCheck:
1482                // Make sure the gate's the right type.
1483                if ((m5reg.mode == LongMode && (desc.type & 0xe) != 0xe) ||
1484                        ((desc.type & 0x6) != 0x6)) {
1485                    fault = new GeneralProtection(0);
1486                }
1487                break;
1488              case SegSSCheck:
1489                if (selector.si || selector.ti) {
1490                    if (!desc.p) {
1491                        fault = new StackFault(selector);
1492                    } else if (!(desc.s == 1 && desc.type.codeOrData == 0 &&
1493                                desc.type.w) ||
1494                            (desc.dpl != m5reg.cpl) ||
1495                            (selector.rpl != m5reg.cpl)) {
1496                        fault = new GeneralProtection(selector);
1497                    }
1498                } else if (m5reg.submode != SixtyFourBitMode ||
1499                        m5reg.cpl == 3) {
1500                    fault = new GeneralProtection(selector);
1501                }
1502                break;
1503              case SegIretCheck:
1504                {
1505                    if ((!selector.si && !selector.ti) ||
1506                            (selector.rpl < m5reg.cpl) ||
1507                            !(desc.s == 1 && desc.type.codeOrData == 1) ||
1508                            (!desc.type.c && desc.dpl != selector.rpl) ||
1509                            (desc.type.c && desc.dpl > selector.rpl)) {
1510                        fault = new GeneralProtection(selector);
1511                    } else if (!desc.p) {
1512                        fault = new SegmentNotPresent(selector);
1513                    }
1514                    break;
1515                }
1516              case SegIntCSCheck:
1517                if (m5reg.mode == LongMode) {
1518                    if (desc.l != 1 || desc.d != 0) {
1519                        fault = new GeneralProtection(selector);
1520                    }
1521                } else {
1522                    fault = new GenericISA::M5PanicFault("Interrupt CS "
1523                            "checks not implemented in legacy mode.\\n");
1524                }
1525                break;
1526              case SegTRCheck:
1527                if (!selector.si || selector.ti) {
1528                    fault = new GeneralProtection(selector);
1529                }
1530                break;
1531              case SegTSSCheck:
1532                if (!desc.p) {
1533                    fault = new SegmentNotPresent(selector);
1534                } else if (!(desc.type == 0x9 ||
1535                        (desc.type == 1 &&
1536                         m5reg.mode != LongMode))) {
1537                    fault = new GeneralProtection(selector);
1538                }
1539                break;
1540              case SegInGDTCheck:
1541                if (selector.ti) {
1542                    fault = new GeneralProtection(selector);
1543                }
1544                break;
1545              case SegLDTCheck:
1546                if (!desc.p) {
1547                    fault = new SegmentNotPresent(selector);
1548                } else if (desc.type != 0x2) {
1549                    fault = new GeneralProtection(selector);
1550                }
1551                break;
1552              default:
1553                fault = new GenericISA::M5PanicFault(
1554                        "Undefined segment check type.\\n");
1555            }
1556        '''
1557        flag_code = '''
1558            // Check for a NULL selector and set ZF,EZF appropriately.
1559            PredccFlagBits = PredccFlagBits & ~(ext & ZFBit);
1560            PredezfBit = PredezfBit & ~(ext & EZFBit);
1561
1562            if (!selector.si && !selector.ti) {
1563                PredccFlagBits = PredccFlagBits | (ext & ZFBit);
1564                PredezfBit = PredezfBit | (ext & EZFBit);
1565            }
1566        '''
1567
1568    class Wrdh(RegOp):
1569        code = '''
1570            SegDescriptor desc = SrcReg1;
1571
1572            uint64_t target = bits(SrcReg2, 31, 0) << 32;
1573            switch(desc.type) {
1574              case LDT64:
1575              case AvailableTSS64:
1576              case BusyTSS64:
1577                replaceBits(target, 23, 0, desc.baseLow);
1578                replaceBits(target, 31, 24, desc.baseHigh);
1579                break;
1580              case CallGate64:
1581              case IntGate64:
1582              case TrapGate64:
1583                replaceBits(target, 15, 0, bits(desc, 15, 0));
1584                replaceBits(target, 31, 16, bits(desc, 63, 48));
1585                break;
1586              default:
1587                fault = new GenericISA::M5PanicFault(
1588                        "Wrdh used with wrong descriptor type!\\n");
1589            }
1590            DestReg = target;
1591        '''
1592
1593    class Wrtsc(WrRegOp):
1594        code = '''
1595            TscOp = psrc1;
1596        '''
1597
1598    class Rdtsc(RdRegOp):
1599        code = '''
1600            DestReg = TscOp;
1601        '''
1602
1603    class Rdm5reg(RdRegOp):
1604        code = '''
1605            DestReg = M5Reg;
1606        '''
1607
1608    class Wrdl(RegOp):
1609        code = '''
1610            SegDescriptor desc = SrcReg1;
1611            SegSelector selector = SrcReg2;
1612            // This while loop is so we can use break statements in the code
1613            // below to skip the rest of this section without a bunch of
1614            // nesting.
1615            while (true) {
1616                if (selector.si || selector.ti) {
1617                    if (!desc.p) {
1618                        fault = new GenericISA::M5PanicFault(
1619                                "Segment not present.\\n");
1620                        break;
1621                    }
1622                    SegAttr attr = 0;
1623                    attr.dpl = desc.dpl;
1624                    attr.unusable = 0;
1625                    attr.defaultSize = desc.d;
1626                    attr.longMode = desc.l;
1627                    attr.avl = desc.avl;
1628                    attr.granularity = desc.g;
1629                    attr.present = desc.p;
1630                    attr.system = desc.s;
1631                    attr.type = desc.type;
1632                    if (!desc.s) {
1633                        // The expand down bit happens to be set for gates.
1634                        if (desc.type.e) {
1635                            fault = new GenericISA::M5PanicFault(
1636                                    "Gate descriptor encountered.\\n");
1637                            break;
1638                        }
1639                        attr.readable = 1;
1640                        attr.writable = 1;
1641                        attr.expandDown = 0;
1642                    } else {
1643                        if (desc.type.codeOrData) {
1644                            attr.expandDown = 0;
1645                            attr.readable = desc.type.r;
1646                            attr.writable = 0;
1647                        } else {
1648                            attr.expandDown = desc.type.e;
1649                            attr.readable = 1;
1650                            attr.writable = desc.type.w;
1651                        }
1652                    }
1653                    Addr base = desc.baseLow | (desc.baseHigh << 24);
1654                    Addr limit = desc.limitLow | (desc.limitHigh << 16);
1655                    if (desc.g)
1656                        limit = (limit << 12) | mask(12);
1657                    SegBaseDest = base;
1658                    SegLimitDest = limit;
1659                    SegAttrDest = attr;
1660                } else {
1661                    SegBaseDest = SegBaseDest;
1662                    SegLimitDest = SegLimitDest;
1663                    SegAttrDest = SegAttrDest;
1664                }
1665                break;
1666            }
1667        '''
1668}};
1669