mem.isa revision 3953:300d526414e6
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', 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(PacketPtr, %(CPU_exec_context)s *,
190                      Trace::InstRecord *) const;
191}};
192
193
194def template EACompConstructor {{
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        %(constructor)s;
202    }
203}};
204
205
206def template MemAccConstructor {{
207    inline %(class_name)s::MemAcc::MemAcc(ExtMachInst machInst)
208        : %(base_class)s("%(mnemonic)s (MemAcc)", machInst, %(op_class)s)
209    {
210        %(constructor)s;
211    }
212}};
213
214
215def template LoadStoreConstructor {{
216    inline %(class_name)s::%(class_name)s(ExtMachInst machInst)
217         : %(base_class)s("%(mnemonic)s", machInst, %(op_class)s,
218                          new EAComp(machInst), new MemAcc(machInst))
219    {
220        %(constructor)s;
221    }
222}};
223
224
225def template EACompExecute {{
226    Fault
227    %(class_name)s::EAComp::execute(%(CPU_exec_context)s *xc,
228                                   Trace::InstRecord *traceData) const
229    {
230        Addr EA;
231        Fault fault = NoFault;
232
233        %(fp_enable_check)s;
234        %(op_decl)s;
235        %(op_rd)s;
236        %(ea_code)s;
237
238        if (fault == NoFault) {
239            %(op_wb)s;
240            xc->setEA(EA);
241        }
242
243        return fault;
244    }
245}};
246
247def template LoadMemAccExecute {{
248    Fault
249    %(class_name)s::MemAcc::execute(%(CPU_exec_context)s *xc,
250                                   Trace::InstRecord *traceData) const
251    {
252        Addr EA;
253        Fault fault = NoFault;
254
255        %(fp_enable_check)s;
256        %(op_decl)s;
257        %(op_rd)s;
258        EA = xc->getEA();
259
260        if (fault == NoFault) {
261            fault = xc->read(EA, (uint%(mem_acc_size)d_t&)Mem, memAccessFlags);
262            %(memacc_code)s;
263        }
264
265        if (fault == NoFault) {
266            %(op_wb)s;
267        }
268
269        return fault;
270    }
271}};
272
273
274def template LoadExecute {{
275    Fault %(class_name)s::execute(%(CPU_exec_context)s *xc,
276                                  Trace::InstRecord *traceData) const
277    {
278        Addr EA;
279        Fault fault = NoFault;
280
281        %(fp_enable_check)s;
282        %(op_decl)s;
283        %(op_rd)s;
284        %(ea_code)s;
285
286        if (fault == NoFault) {
287            fault = xc->read(EA, (uint%(mem_acc_size)d_t&)Mem, memAccessFlags);
288            %(memacc_code)s;
289        }
290
291        if (fault == NoFault) {
292            %(op_wb)s;
293        }
294
295        return fault;
296    }
297}};
298
299
300def template LoadInitiateAcc {{
301    Fault %(class_name)s::initiateAcc(%(CPU_exec_context)s *xc,
302                                      Trace::InstRecord *traceData) const
303    {
304        Addr EA;
305        Fault fault = NoFault;
306
307        %(fp_enable_check)s;
308        %(op_src_decl)s;
309        %(op_rd)s;
310        %(ea_code)s;
311
312        if (fault == NoFault) {
313            fault = xc->read(EA, (uint%(mem_acc_size)d_t &)Mem, memAccessFlags);
314        }
315
316        return fault;
317    }
318}};
319
320
321def template LoadCompleteAcc {{
322    Fault %(class_name)s::completeAcc(PacketPtr pkt,
323                                      %(CPU_exec_context)s *xc,
324                                      Trace::InstRecord *traceData) const
325    {
326        Fault fault = NoFault;
327
328        %(fp_enable_check)s;
329        %(op_decl)s;
330
331        Mem = pkt->get<typeof(Mem)>();
332
333        if (fault == NoFault) {
334            %(memacc_code)s;
335        }
336
337        if (fault == NoFault) {
338            %(op_wb)s;
339        }
340
341        return fault;
342    }
343}};
344
345
346def template StoreMemAccExecute {{
347    Fault
348    %(class_name)s::MemAcc::execute(%(CPU_exec_context)s *xc,
349                                   Trace::InstRecord *traceData) const
350    {
351        Addr EA;
352        Fault fault = NoFault;
353        uint64_t write_result = 0;
354
355        %(fp_enable_check)s;
356        %(op_decl)s;
357        %(op_rd)s;
358        EA = xc->getEA();
359
360        if (fault == NoFault) {
361            %(memacc_code)s;
362        }
363
364        if (fault == NoFault) {
365            fault = xc->write((uint%(mem_acc_size)d_t&)Mem, EA,
366                              memAccessFlags, &write_result);
367            if (traceData) { traceData->setData(Mem); }
368        }
369
370        if (fault == NoFault) {
371            %(postacc_code)s;
372        }
373
374        if (fault == NoFault) {
375            %(op_wb)s;
376        }
377
378        return fault;
379    }
380}};
381
382
383def template StoreExecute {{
384    Fault %(class_name)s::execute(%(CPU_exec_context)s *xc,
385                                  Trace::InstRecord *traceData) const
386    {
387        Addr EA;
388        Fault fault = NoFault;
389        uint64_t write_result = 0;
390
391        %(fp_enable_check)s;
392        %(op_decl)s;
393        %(op_rd)s;
394        %(ea_code)s;
395
396        if (fault == NoFault) {
397            %(memacc_code)s;
398        }
399
400        if (fault == NoFault) {
401            fault = xc->write((uint%(mem_acc_size)d_t&)Mem, EA,
402                              memAccessFlags, &write_result);
403            if (traceData) { traceData->setData(Mem); }
404        }
405
406        if (fault == NoFault) {
407            %(postacc_code)s;
408        }
409
410        if (fault == NoFault) {
411            %(op_wb)s;
412        }
413
414        return fault;
415    }
416}};
417
418def template StoreInitiateAcc {{
419    Fault %(class_name)s::initiateAcc(%(CPU_exec_context)s *xc,
420                                      Trace::InstRecord *traceData) const
421    {
422        Addr EA;
423        Fault fault = NoFault;
424
425        %(fp_enable_check)s;
426        %(op_decl)s;
427        %(op_rd)s;
428        %(ea_code)s;
429
430        if (fault == NoFault) {
431            %(memacc_code)s;
432        }
433
434        if (fault == NoFault) {
435            fault = xc->write((uint%(mem_acc_size)d_t&)Mem, EA,
436                              memAccessFlags, NULL);
437            if (traceData) { traceData->setData(Mem); }
438        }
439
440        return fault;
441    }
442}};
443
444
445def template StoreCompleteAcc {{
446    Fault %(class_name)s::completeAcc(PacketPtr pkt,
447                                      %(CPU_exec_context)s *xc,
448                                      Trace::InstRecord *traceData) const
449    {
450        Fault fault = NoFault;
451
452        %(fp_enable_check)s;
453        %(op_dest_decl)s;
454
455        if (fault == NoFault) {
456            %(postacc_code)s;
457        }
458
459        if (fault == NoFault) {
460            %(op_wb)s;
461        }
462
463        return fault;
464    }
465}};
466
467
468def template StoreCondCompleteAcc {{
469    Fault %(class_name)s::completeAcc(PacketPtr pkt,
470                                      %(CPU_exec_context)s *xc,
471                                      Trace::InstRecord *traceData) const
472    {
473        Fault fault = NoFault;
474
475        %(fp_enable_check)s;
476        %(op_dest_decl)s;
477
478        uint64_t write_result = pkt->req->getScResult();
479
480        if (fault == NoFault) {
481            %(postacc_code)s;
482        }
483
484        if (fault == NoFault) {
485            %(op_wb)s;
486        }
487
488        return fault;
489    }
490}};
491
492
493def template MiscMemAccExecute {{
494    Fault %(class_name)s::MemAcc::execute(%(CPU_exec_context)s *xc,
495                                          Trace::InstRecord *traceData) const
496    {
497        Addr EA;
498        Fault fault = NoFault;
499
500        %(fp_enable_check)s;
501        %(op_decl)s;
502        %(op_rd)s;
503        EA = xc->getEA();
504
505        if (fault == NoFault) {
506            %(memacc_code)s;
507        }
508
509        return NoFault;
510    }
511}};
512
513def template MiscExecute {{
514    Fault %(class_name)s::execute(%(CPU_exec_context)s *xc,
515                                  Trace::InstRecord *traceData) const
516    {
517        Addr EA;
518        Fault fault = NoFault;
519
520        %(fp_enable_check)s;
521        %(op_decl)s;
522        %(op_rd)s;
523        %(ea_code)s;
524
525        if (fault == NoFault) {
526            %(memacc_code)s;
527        }
528
529        return NoFault;
530    }
531}};
532
533def template MiscInitiateAcc {{
534    Fault %(class_name)s::initiateAcc(%(CPU_exec_context)s *xc,
535                                      Trace::InstRecord *traceData) const
536    {
537        warn("Misc instruction does not support split access method!");
538        return NoFault;
539    }
540}};
541
542
543def template MiscCompleteAcc {{
544    Fault %(class_name)s::completeAcc(PacketPtr pkt,
545                                      %(CPU_exec_context)s *xc,
546                                      Trace::InstRecord *traceData) const
547    {
548        warn("Misc instruction does not support split access method!");
549
550        return NoFault;
551    }
552}};
553
554// load instructions use Ra as dest, so check for
555// Ra == 31 to detect nops
556def template LoadNopCheckDecode {{
557 {
558     AlphaStaticInst *i = new %(class_name)s(machInst);
559     if (RA == 31) {
560         i = makeNop(i);
561     }
562     return i;
563 }
564}};
565
566
567// for some load instructions, Ra == 31 indicates a prefetch (not a nop)
568def template LoadPrefetchCheckDecode {{
569 {
570     if (RA != 31) {
571         return new %(class_name)s(machInst);
572     }
573     else {
574         return new %(class_name)sPrefetch(machInst);
575     }
576 }
577}};
578
579
580let {{
581def LoadStoreBase(name, Name, ea_code, memacc_code, mem_flags, inst_flags,
582                  postacc_code = '', base_class = 'MemoryDisp32',
583                  decode_template = BasicDecode, exec_template_base = ''):
584    # Make sure flags are in lists (convert to lists if not).
585    mem_flags = makeList(mem_flags)
586    inst_flags = makeList(inst_flags)
587
588    # add hook to get effective addresses into execution trace output.
589    ea_code += '\nif (traceData) { traceData->setAddr(EA); }\n'
590
591    # Some CPU models execute the memory operation as an atomic unit,
592    # while others want to separate them into an effective address
593    # computation and a memory access operation.  As a result, we need
594    # to generate three StaticInst objects.  Note that the latter two
595    # are nested inside the larger "atomic" one.
596
597    # Generate InstObjParams for each of the three objects.  Note that
598    # they differ only in the set of code objects contained (which in
599    # turn affects the object's overall operand list).
600    iop = InstObjParams(name, Name, base_class,
601                        { 'ea_code':ea_code, 'memacc_code':memacc_code, 'postacc_code':postacc_code },
602                        inst_flags)
603    ea_iop = InstObjParams(name, Name, base_class,
604                        { 'ea_code':ea_code },
605                        inst_flags)
606    memacc_iop = InstObjParams(name, Name, base_class,
607                        { 'memacc_code':memacc_code, 'postacc_code':postacc_code },
608                        inst_flags)
609
610    if mem_flags:
611        s = '\n\tmemAccessFlags = ' + string.join(mem_flags, '|') + ';'
612        iop.constructor += s
613        memacc_iop.constructor += s
614
615    # select templates
616
617    # define aliases... most StoreCond templates are the same as the
618    # corresponding Store templates (only CompleteAcc is different).
619    StoreCondMemAccExecute = StoreMemAccExecute
620    StoreCondExecute = StoreExecute
621    StoreCondInitiateAcc = StoreInitiateAcc
622
623    memAccExecTemplate = eval(exec_template_base + 'MemAccExecute')
624    fullExecTemplate = eval(exec_template_base + 'Execute')
625    initiateAccTemplate = eval(exec_template_base + 'InitiateAcc')
626    completeAccTemplate = eval(exec_template_base + 'CompleteAcc')
627
628    # (header_output, decoder_output, decode_block, exec_output)
629    return (LoadStoreDeclare.subst(iop),
630            EACompConstructor.subst(ea_iop)
631            + MemAccConstructor.subst(memacc_iop)
632            + LoadStoreConstructor.subst(iop),
633            decode_template.subst(iop),
634            EACompExecute.subst(ea_iop)
635            + memAccExecTemplate.subst(memacc_iop)
636            + fullExecTemplate.subst(iop)
637            + initiateAccTemplate.subst(iop)
638            + completeAccTemplate.subst(iop))
639}};
640
641def format LoadOrNop(memacc_code, ea_code = {{ EA = Rb + disp; }},
642                     mem_flags = [], inst_flags = []) {{
643    (header_output, decoder_output, decode_block, exec_output) = \
644        LoadStoreBase(name, Name, ea_code, memacc_code, mem_flags, inst_flags,
645                      decode_template = LoadNopCheckDecode,
646                      exec_template_base = 'Load')
647}};
648
649
650// Note that the flags passed in apply only to the prefetch version
651def format LoadOrPrefetch(memacc_code, ea_code = {{ EA = Rb + disp; }},
652                          mem_flags = [], pf_flags = [], inst_flags = []) {{
653    # declare the load instruction object and generate the decode block
654    (header_output, decoder_output, decode_block, exec_output) = \
655        LoadStoreBase(name, Name, ea_code, memacc_code, mem_flags, inst_flags,
656                      decode_template = LoadPrefetchCheckDecode,
657                      exec_template_base = 'Load')
658
659    # Declare the prefetch instruction object.
660
661    # Make sure flag args are lists so we can mess with them.
662    mem_flags = makeList(mem_flags)
663    pf_flags = makeList(pf_flags)
664    inst_flags = makeList(inst_flags)
665
666    pf_mem_flags = mem_flags + pf_flags + ['NO_FAULT']
667    pf_inst_flags = inst_flags + ['IsMemRef', 'IsLoad',
668                                  'IsDataPrefetch', 'MemReadOp']
669
670    (pf_header_output, pf_decoder_output, _, pf_exec_output) = \
671        LoadStoreBase(name, Name + 'Prefetch', ea_code,
672                      'xc->prefetch(EA, memAccessFlags);',
673                      pf_mem_flags, pf_inst_flags, exec_template_base = 'Misc')
674
675    header_output += pf_header_output
676    decoder_output += pf_decoder_output
677    exec_output += pf_exec_output
678}};
679
680
681def format Store(memacc_code, ea_code = {{ EA = Rb + disp; }},
682                 mem_flags = [], inst_flags = []) {{
683    (header_output, decoder_output, decode_block, exec_output) = \
684        LoadStoreBase(name, Name, ea_code, memacc_code, mem_flags, inst_flags,
685                      exec_template_base = 'Store')
686}};
687
688
689def format StoreCond(memacc_code, postacc_code,
690                     ea_code = {{ EA = Rb + disp; }},
691                     mem_flags = [], inst_flags = []) {{
692    (header_output, decoder_output, decode_block, exec_output) = \
693        LoadStoreBase(name, Name, ea_code, memacc_code, mem_flags, inst_flags,
694                      postacc_code, exec_template_base = 'StoreCond')
695}};
696
697
698// Use 'MemoryNoDisp' as base: for wh64, fetch, ecb
699def format MiscPrefetch(ea_code, memacc_code,
700                        mem_flags = [], inst_flags = []) {{
701    (header_output, decoder_output, decode_block, exec_output) = \
702        LoadStoreBase(name, Name, ea_code, memacc_code, mem_flags, inst_flags,
703                      base_class = 'MemoryNoDisp', exec_template_base = 'Misc')
704}};
705
706
707