mem.isa revision 2742
1// -*- mode:c++ -*-
2
3// Copyright (c) 2003-2005 The Regents of The University of Michigan
4// All rights reserved.
5//
6// Redistribution and use in source and binary forms, with or without
7// modification, are permitted provided that the following conditions are
8// met: redistributions of source code must retain the above copyright
9// notice, this list of conditions and the following disclaimer;
10// redistributions in binary form must reproduce the above copyright
11// notice, this list of conditions and the following disclaimer in the
12// documentation and/or other materials provided with the distribution;
13// neither the name of the copyright holders nor the names of its
14// contributors may be used to endorse or promote products derived from
15// this software without specific prior written permission.
16//
17// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28//
29// Authors: Steve Reinhardt
30//          Kevin Lim
31
32////////////////////////////////////////////////////////////////////
33//
34// Memory-format instructions: LoadAddress, Load, Store
35//
36
37output header {{
38    /**
39     * Base class for general Alpha memory-format instructions.
40     */
41    class Memory : public AlphaStaticInst
42    {
43      protected:
44
45        /// Memory request flags.  See mem_req_base.hh.
46        unsigned memAccessFlags;
47        /// Pointer to EAComp object.
48        const StaticInstPtr eaCompPtr;
49        /// Pointer to MemAcc object.
50        const StaticInstPtr memAccPtr;
51
52        /// Constructor
53        Memory(const char *mnem, ExtMachInst _machInst, OpClass __opClass,
54               StaticInstPtr _eaCompPtr = nullStaticInstPtr,
55               StaticInstPtr _memAccPtr = nullStaticInstPtr)
56            : AlphaStaticInst(mnem, _machInst, __opClass),
57              memAccessFlags(0), eaCompPtr(_eaCompPtr), memAccPtr(_memAccPtr)
58        {
59        }
60
61        std::string
62        generateDisassembly(Addr pc, const SymbolTable *symtab) const;
63
64      public:
65
66        const StaticInstPtr &eaCompInst() const { return eaCompPtr; }
67        const StaticInstPtr &memAccInst() const { return memAccPtr; }
68    };
69
70    /**
71     * Base class for memory-format instructions using a 32-bit
72     * displacement (i.e. most of them).
73     */
74    class MemoryDisp32 : public Memory
75    {
76      protected:
77        /// Displacement for EA calculation (signed).
78        int32_t disp;
79
80        /// Constructor.
81        MemoryDisp32(const char *mnem, ExtMachInst _machInst, OpClass __opClass,
82                     StaticInstPtr _eaCompPtr = nullStaticInstPtr,
83                     StaticInstPtr _memAccPtr = nullStaticInstPtr)
84            : Memory(mnem, _machInst, __opClass, _eaCompPtr, _memAccPtr),
85              disp(MEMDISP)
86        {
87        }
88    };
89
90
91    /**
92     * Base class for a few miscellaneous memory-format insts
93     * that don't interpret the disp field: wh64, fetch, fetch_m, ecb.
94     * None of these instructions has a destination register either.
95     */
96    class MemoryNoDisp : public Memory
97    {
98      protected:
99        /// Constructor
100        MemoryNoDisp(const char *mnem, ExtMachInst _machInst, OpClass __opClass,
101                     StaticInstPtr _eaCompPtr = nullStaticInstPtr,
102                     StaticInstPtr _memAccPtr = nullStaticInstPtr)
103            : Memory(mnem, _machInst, __opClass, _eaCompPtr, _memAccPtr)
104        {
105        }
106
107        std::string
108        generateDisassembly(Addr pc, const SymbolTable *symtab) const;
109    };
110}};
111
112
113output decoder {{
114    std::string
115    Memory::generateDisassembly(Addr pc, const SymbolTable *symtab) const
116    {
117        return csprintf("%-10s %c%d,%d(r%d)", mnemonic,
118                        flags[IsFloating] ? 'f' : 'r', RA, MEMDISP, RB);
119    }
120
121    std::string
122    MemoryNoDisp::generateDisassembly(Addr pc, const SymbolTable *symtab) const
123    {
124        return csprintf("%-10s (r%d)", mnemonic, RB);
125    }
126}};
127
128def format LoadAddress(code) {{
129    iop = InstObjParams(name, Name, 'MemoryDisp32', CodeBlock(code))
130    header_output = BasicDeclare.subst(iop)
131    decoder_output = BasicConstructor.subst(iop)
132    decode_block = BasicDecode.subst(iop)
133    exec_output = BasicExecute.subst(iop)
134}};
135
136
137def template LoadStoreDeclare {{
138    /**
139     * Static instruction class for "%(mnemonic)s".
140     */
141    class %(class_name)s : public %(base_class)s
142    {
143      protected:
144
145        /**
146         * "Fake" effective address computation class for "%(mnemonic)s".
147         */
148        class EAComp : public %(base_class)s
149        {
150          public:
151            /// Constructor
152            EAComp(ExtMachInst machInst);
153
154            %(BasicExecDeclare)s
155        };
156
157        /**
158         * "Fake" memory access instruction class for "%(mnemonic)s".
159         */
160        class MemAcc : public %(base_class)s
161        {
162          public:
163            /// Constructor
164            MemAcc(ExtMachInst machInst);
165
166            %(BasicExecDeclare)s
167        };
168
169      public:
170
171        /// Constructor.
172        %(class_name)s(ExtMachInst machInst);
173
174        %(BasicExecDeclare)s
175
176        %(InitiateAccDeclare)s
177
178        %(CompleteAccDeclare)s
179    };
180}};
181
182
183def template InitiateAccDeclare {{
184    Fault initiateAcc(%(CPU_exec_context)s *, Trace::InstRecord *) const;
185}};
186
187
188def template CompleteAccDeclare {{
189    Fault completeAcc(Packet *, %(CPU_exec_context)s *,
190                      Trace::InstRecord *) const;
191}};
192
193
194def template LoadStoreConstructor {{
195    /** TODO: change op_class to AddrGenOp or something (requires
196     * creating new member of OpClass enum in op_class.hh, updating
197     * config files, etc.). */
198    inline %(class_name)s::EAComp::EAComp(ExtMachInst machInst)
199        : %(base_class)s("%(mnemonic)s (EAComp)", machInst, IntAluOp)
200    {
201        %(ea_constructor)s;
202    }
203
204    inline %(class_name)s::MemAcc::MemAcc(ExtMachInst machInst)
205        : %(base_class)s("%(mnemonic)s (MemAcc)", machInst, %(op_class)s)
206    {
207        %(memacc_constructor)s;
208    }
209
210    inline %(class_name)s::%(class_name)s(ExtMachInst machInst)
211         : %(base_class)s("%(mnemonic)s", machInst, %(op_class)s,
212                          new EAComp(machInst), new MemAcc(machInst))
213    {
214        %(constructor)s;
215    }
216}};
217
218
219def template EACompExecute {{
220    Fault
221    %(class_name)s::EAComp::execute(%(CPU_exec_context)s *xc,
222                                   Trace::InstRecord *traceData) const
223    {
224        Addr EA;
225        Fault fault = NoFault;
226
227        %(fp_enable_check)s;
228        %(op_decl)s;
229        %(op_rd)s;
230        %(code)s;
231
232        if (fault == NoFault) {
233            %(op_wb)s;
234            xc->setEA(EA);
235        }
236
237        return fault;
238    }
239}};
240
241def template LoadMemAccExecute {{
242    Fault
243    %(class_name)s::MemAcc::execute(%(CPU_exec_context)s *xc,
244                                   Trace::InstRecord *traceData) const
245    {
246        Addr EA;
247        Fault fault = NoFault;
248
249        %(fp_enable_check)s;
250        %(op_decl)s;
251        %(op_rd)s;
252        EA = xc->getEA();
253
254        if (fault == NoFault) {
255            fault = xc->read(EA, (uint%(mem_acc_size)d_t&)Mem, memAccessFlags);
256            %(code)s;
257        }
258
259        if (fault == NoFault) {
260            %(op_wb)s;
261        }
262
263        return fault;
264    }
265}};
266
267
268def template LoadExecute {{
269    Fault %(class_name)s::execute(%(CPU_exec_context)s *xc,
270                                  Trace::InstRecord *traceData) const
271    {
272        Addr EA;
273        Fault fault = NoFault;
274
275        %(fp_enable_check)s;
276        %(op_decl)s;
277        %(op_rd)s;
278        %(ea_code)s;
279
280        if (fault == NoFault) {
281            fault = xc->read(EA, (uint%(mem_acc_size)d_t&)Mem, memAccessFlags);
282            %(memacc_code)s;
283        }
284
285        if (fault == NoFault) {
286            %(op_wb)s;
287        }
288
289        return fault;
290    }
291}};
292
293
294def template LoadInitiateAcc {{
295    Fault %(class_name)s::initiateAcc(%(CPU_exec_context)s *xc,
296                                      Trace::InstRecord *traceData) const
297    {
298        Addr EA;
299        Fault fault = NoFault;
300
301        %(fp_enable_check)s;
302        %(op_src_decl)s;
303        %(op_rd)s;
304        %(ea_code)s;
305
306        if (fault == NoFault) {
307            fault = xc->read(EA, (uint%(mem_acc_size)d_t &)Mem, memAccessFlags);
308        }
309
310        return fault;
311    }
312}};
313
314
315def template LoadCompleteAcc {{
316    Fault %(class_name)s::completeAcc(Packet *pkt,
317                                      %(CPU_exec_context)s *xc,
318                                      Trace::InstRecord *traceData) const
319    {
320        Fault fault = NoFault;
321
322        %(fp_enable_check)s;
323        %(op_decl)s;
324
325        Mem = pkt->get<typeof(Mem)>();
326
327        if (fault == NoFault) {
328            %(memacc_code)s;
329        }
330
331        if (fault == NoFault) {
332            %(op_wb)s;
333        }
334
335        return fault;
336    }
337}};
338
339
340def template StoreMemAccExecute {{
341    Fault
342    %(class_name)s::MemAcc::execute(%(CPU_exec_context)s *xc,
343                                   Trace::InstRecord *traceData) const
344    {
345        Addr EA;
346        Fault fault = NoFault;
347        uint64_t write_result = 0;
348
349        %(fp_enable_check)s;
350        %(op_decl)s;
351        %(op_rd)s;
352        EA = xc->getEA();
353
354        if (fault == NoFault) {
355            %(code)s;
356        }
357
358        if (fault == NoFault) {
359            fault = xc->write((uint%(mem_acc_size)d_t&)Mem, EA,
360                              memAccessFlags, &write_result);
361            if (traceData) { traceData->setData(Mem); }
362        }
363
364        if (fault == NoFault) {
365            %(postacc_code)s;
366        }
367
368        if (fault == NoFault) {
369            %(op_wb)s;
370        }
371
372        return fault;
373    }
374}};
375
376
377def template StoreExecute {{
378    Fault %(class_name)s::execute(%(CPU_exec_context)s *xc,
379                                  Trace::InstRecord *traceData) const
380    {
381        Addr EA;
382        Fault fault = NoFault;
383        uint64_t write_result = 0;
384
385        %(fp_enable_check)s;
386        %(op_decl)s;
387        %(op_rd)s;
388        %(ea_code)s;
389
390        if (fault == NoFault) {
391            %(memacc_code)s;
392        }
393
394        if (fault == NoFault) {
395            fault = xc->write((uint%(mem_acc_size)d_t&)Mem, EA,
396                              memAccessFlags, &write_result);
397            if (traceData) { traceData->setData(Mem); }
398        }
399
400        if (fault == NoFault) {
401            %(postacc_code)s;
402        }
403
404        if (fault == NoFault) {
405            %(op_wb)s;
406        }
407
408        return fault;
409    }
410}};
411
412def template StoreInitiateAcc {{
413    Fault %(class_name)s::initiateAcc(%(CPU_exec_context)s *xc,
414                                      Trace::InstRecord *traceData) const
415    {
416        Addr EA;
417        Fault fault = NoFault;
418
419        %(fp_enable_check)s;
420        %(op_decl)s;
421        %(op_rd)s;
422        %(ea_code)s;
423
424        if (fault == NoFault) {
425            %(memacc_code)s;
426        }
427
428        if (fault == NoFault) {
429            fault = xc->write((uint%(mem_acc_size)d_t&)Mem, EA,
430                              memAccessFlags, NULL);
431            if (traceData) { traceData->setData(Mem); }
432        }
433
434        return fault;
435    }
436}};
437
438
439def template StoreCompleteAcc {{
440    Fault %(class_name)s::completeAcc(Packet *pkt,
441                                      %(CPU_exec_context)s *xc,
442                                      Trace::InstRecord *traceData) const
443    {
444        Fault fault = NoFault;
445
446        %(fp_enable_check)s;
447        %(op_dest_decl)s;
448
449        if (fault == NoFault) {
450            %(postacc_code)s;
451        }
452
453        if (fault == NoFault) {
454            %(op_wb)s;
455        }
456
457        return fault;
458    }
459}};
460
461
462def template StoreCondCompleteAcc {{
463    Fault %(class_name)s::completeAcc(Packet *pkt,
464                                      %(CPU_exec_context)s *xc,
465                                      Trace::InstRecord *traceData) const
466    {
467        Fault fault = NoFault;
468
469        %(fp_enable_check)s;
470        %(op_dest_decl)s;
471
472        uint64_t write_result = pkt->req->getScResult();
473
474        if (fault == NoFault) {
475            %(postacc_code)s;
476        }
477
478        if (fault == NoFault) {
479            %(op_wb)s;
480        }
481
482        return fault;
483    }
484}};
485
486
487def template MiscMemAccExecute {{
488    Fault %(class_name)s::MemAcc::execute(%(CPU_exec_context)s *xc,
489                                          Trace::InstRecord *traceData) const
490    {
491        Addr EA;
492        Fault fault = NoFault;
493
494        %(fp_enable_check)s;
495        %(op_decl)s;
496        %(op_rd)s;
497        EA = xc->getEA();
498
499        if (fault == NoFault) {
500            %(code)s;
501        }
502
503        return NoFault;
504    }
505}};
506
507def template MiscExecute {{
508    Fault %(class_name)s::execute(%(CPU_exec_context)s *xc,
509                                  Trace::InstRecord *traceData) const
510    {
511        Addr EA;
512        Fault fault = NoFault;
513
514        %(fp_enable_check)s;
515        %(op_decl)s;
516        %(op_rd)s;
517        %(ea_code)s;
518
519        if (fault == NoFault) {
520            %(memacc_code)s;
521        }
522
523        return NoFault;
524    }
525}};
526
527def template MiscInitiateAcc {{
528    Fault %(class_name)s::initiateAcc(%(CPU_exec_context)s *xc,
529                                      Trace::InstRecord *traceData) const
530    {
531        panic("Misc instruction does not support split access method!");
532        return NoFault;
533    }
534}};
535
536
537def template MiscCompleteAcc {{
538    Fault %(class_name)s::completeAcc(Packet *pkt,
539                                      %(CPU_exec_context)s *xc,
540                                      Trace::InstRecord *traceData) const
541    {
542        panic("Misc instruction does not support split access method!");
543
544        return NoFault;
545    }
546}};
547
548// load instructions use Ra as dest, so check for
549// Ra == 31 to detect nops
550def template LoadNopCheckDecode {{
551 {
552     AlphaStaticInst *i = new %(class_name)s(machInst);
553     if (RA == 31) {
554         i = makeNop(i);
555     }
556     return i;
557 }
558}};
559
560
561// for some load instructions, Ra == 31 indicates a prefetch (not a nop)
562def template LoadPrefetchCheckDecode {{
563 {
564     if (RA != 31) {
565         return new %(class_name)s(machInst);
566     }
567     else {
568         return new %(class_name)sPrefetch(machInst);
569     }
570 }
571}};
572
573
574let {{
575def LoadStoreBase(name, Name, ea_code, memacc_code, mem_flags, inst_flags,
576                  postacc_code = '', base_class = 'MemoryDisp32',
577                  decode_template = BasicDecode, exec_template_base = ''):
578    # Make sure flags are in lists (convert to lists if not).
579    mem_flags = makeList(mem_flags)
580    inst_flags = makeList(inst_flags)
581
582    # add hook to get effective addresses into execution trace output.
583    ea_code += '\nif (traceData) { traceData->setAddr(EA); }\n'
584
585    # generate code block objects
586    ea_cblk = CodeBlock(ea_code)
587    memacc_cblk = CodeBlock(memacc_code)
588    postacc_cblk = CodeBlock(postacc_code)
589
590    # Some CPU models execute the memory operation as an atomic unit,
591    # while others want to separate them into an effective address
592    # computation and a memory access operation.  As a result, we need
593    # to generate three StaticInst objects.  Note that the latter two
594    # are nested inside the larger "atomic" one.
595
596    # generate InstObjParams for EAComp object
597    ea_iop = InstObjParams(name, Name, base_class, ea_cblk, inst_flags)
598
599    # generate InstObjParams for MemAcc object
600    memacc_iop = InstObjParams(name, Name, base_class, memacc_cblk, inst_flags)
601    # in the split execution model, the MemAcc portion is responsible
602    # for the post-access code.
603    memacc_iop.postacc_code = postacc_cblk.code
604
605    # generate InstObjParams for InitiateAcc, CompleteAcc object
606    # The code used depends on the template being used
607    if (exec_template_base == 'Load'):
608        initiateacc_cblk = CodeBlock(ea_code + memacc_code)
609        completeacc_cblk = CodeBlock(memacc_code + postacc_code)
610    elif (exec_template_base.startswith('Store')):
611        initiateacc_cblk = CodeBlock(ea_code + memacc_code)
612        completeacc_cblk = CodeBlock(postacc_code)
613    else:
614        initiateacc_cblk = ''
615        completeacc_cblk = ''
616
617    initiateacc_iop = InstObjParams(name, Name, base_class, initiateacc_cblk,
618                                    inst_flags)
619
620    completeacc_iop = InstObjParams(name, Name, base_class, completeacc_cblk,
621                                    inst_flags)
622
623    if (exec_template_base == 'Load'):
624        initiateacc_iop.ea_code = ea_cblk.code
625        initiateacc_iop.memacc_code = memacc_cblk.code
626        completeacc_iop.memacc_code = memacc_cblk.code
627        completeacc_iop.postacc_code = postacc_cblk.code
628    elif (exec_template_base.startswith('Store')):
629        initiateacc_iop.ea_code = ea_cblk.code
630        initiateacc_iop.memacc_code = memacc_cblk.code
631        completeacc_iop.postacc_code = postacc_cblk.code
632
633    # generate InstObjParams for unified execution
634    cblk = CodeBlock(ea_code + memacc_code + postacc_code)
635    iop = InstObjParams(name, Name, base_class, cblk, inst_flags)
636
637    iop.ea_constructor = ea_cblk.constructor
638    iop.ea_code = ea_cblk.code
639    iop.memacc_constructor = memacc_cblk.constructor
640    iop.memacc_code = memacc_cblk.code
641    iop.postacc_code = postacc_cblk.code
642
643    if mem_flags:
644        s = '\n\tmemAccessFlags = ' + string.join(mem_flags, '|') + ';'
645        iop.constructor += s
646        memacc_iop.constructor += s
647
648    # select templates
649
650    # define aliases... most StoreCond templates are the same as the
651    # corresponding Store templates (only CompleteAcc is different).
652    StoreCondMemAccExecute = StoreMemAccExecute
653    StoreCondExecute = StoreExecute
654    StoreCondInitiateAcc = StoreInitiateAcc
655
656    memAccExecTemplate = eval(exec_template_base + 'MemAccExecute')
657    fullExecTemplate = eval(exec_template_base + 'Execute')
658    initiateAccTemplate = eval(exec_template_base + 'InitiateAcc')
659    completeAccTemplate = eval(exec_template_base + 'CompleteAcc')
660
661    # (header_output, decoder_output, decode_block, exec_output)
662    return (LoadStoreDeclare.subst(iop), LoadStoreConstructor.subst(iop),
663            decode_template.subst(iop),
664            EACompExecute.subst(ea_iop)
665            + memAccExecTemplate.subst(memacc_iop)
666            + fullExecTemplate.subst(iop)
667            + initiateAccTemplate.subst(initiateacc_iop)
668            + completeAccTemplate.subst(completeacc_iop))
669}};
670
671
672def format LoadOrNop(memacc_code, ea_code = {{ EA = Rb + disp; }},
673                     mem_flags = [], inst_flags = []) {{
674    (header_output, decoder_output, decode_block, exec_output) = \
675        LoadStoreBase(name, Name, ea_code, memacc_code, mem_flags, inst_flags,
676                      decode_template = LoadNopCheckDecode,
677                      exec_template_base = 'Load')
678}};
679
680
681// Note that the flags passed in apply only to the prefetch version
682def format LoadOrPrefetch(memacc_code, ea_code = {{ EA = Rb + disp; }},
683                          mem_flags = [], pf_flags = [], inst_flags = []) {{
684    # declare the load instruction object and generate the decode block
685    (header_output, decoder_output, decode_block, exec_output) = \
686        LoadStoreBase(name, Name, ea_code, memacc_code, mem_flags, inst_flags,
687                      decode_template = LoadPrefetchCheckDecode,
688                      exec_template_base = 'Load')
689
690    # Declare the prefetch instruction object.
691
692    # Make sure flag args are lists so we can mess with them.
693    mem_flags = makeList(mem_flags)
694    pf_flags = makeList(pf_flags)
695    inst_flags = makeList(inst_flags)
696
697    pf_mem_flags = mem_flags + pf_flags + ['NO_FAULT']
698    pf_inst_flags = inst_flags + ['IsMemRef', 'IsLoad',
699                                  'IsDataPrefetch', 'MemReadOp']
700
701    (pf_header_output, pf_decoder_output, _, pf_exec_output) = \
702        LoadStoreBase(name, Name + 'Prefetch', ea_code,
703                      'xc->prefetch(EA, memAccessFlags);',
704                      pf_mem_flags, pf_inst_flags, exec_template_base = 'Misc')
705
706    header_output += pf_header_output
707    decoder_output += pf_decoder_output
708    exec_output += pf_exec_output
709}};
710
711
712def format Store(memacc_code, ea_code = {{ EA = Rb + disp; }},
713                 mem_flags = [], inst_flags = []) {{
714    (header_output, decoder_output, decode_block, exec_output) = \
715        LoadStoreBase(name, Name, ea_code, memacc_code, mem_flags, inst_flags,
716                      exec_template_base = 'Store')
717}};
718
719
720def format StoreCond(memacc_code, postacc_code,
721                     ea_code = {{ EA = Rb + disp; }},
722                     mem_flags = [], inst_flags = []) {{
723    (header_output, decoder_output, decode_block, exec_output) = \
724        LoadStoreBase(name, Name, ea_code, memacc_code, mem_flags, inst_flags,
725                      postacc_code, exec_template_base = 'StoreCond')
726}};
727
728
729// Use 'MemoryNoDisp' as base: for wh64, fetch, ecb
730def format MiscPrefetch(ea_code, memacc_code,
731                        mem_flags = [], inst_flags = []) {{
732    (header_output, decoder_output, decode_block, exec_output) = \
733        LoadStoreBase(name, Name, ea_code, memacc_code, mem_flags, inst_flags,
734                      base_class = 'MemoryNoDisp', exec_template_base = 'Misc')
735}};
736
737
738