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