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        Request::Flags memAccessFlags;
47
48        /// Constructor
49        Memory(const char *mnem, ExtMachInst _machInst, OpClass __opClass)
50            : AlphaStaticInst(mnem, _machInst, __opClass)
51        {
52        }
53
54        std::string generateDisassembly(
55                Addr pc, const SymbolTable *symtab) const override;
56    };
57
58    /**
59     * Base class for memory-format instructions using a 32-bit
60     * displacement (i.e. most of them).
61     */
62    class MemoryDisp32 : public Memory
63    {
64      protected:
65        /// Displacement for EA calculation (signed).
66        int32_t disp;
67
68        /// Constructor.
69        MemoryDisp32(const char *mnem, ExtMachInst _machInst, OpClass __opClass)
70            : Memory(mnem, _machInst, __opClass),
71              disp(MEMDISP)
72        {
73        }
74    };
75
76
77    /**
78     * Base class for a few miscellaneous memory-format insts
79     * that don't interpret the disp field: wh64, fetch, fetch_m, ecb.
80     * None of these instructions has a destination register either.
81     */
82    class MemoryNoDisp : public Memory
83    {
84      protected:
85        /// Constructor
86        MemoryNoDisp(const char *mnem, ExtMachInst _machInst, OpClass __opClass)
87            : Memory(mnem, _machInst, __opClass)
88        {
89        }
90
91        std::string generateDisassembly(
92                Addr pc, const SymbolTable *symtab) const override;
93    };
94}};
95
96
97output decoder {{
98    std::string
99    Memory::generateDisassembly(Addr pc, const SymbolTable *symtab) const
100    {
101        return csprintf("%-10s %c%d,%d(r%d)", mnemonic,
102                        flags[IsFloating] ? 'f' : 'r', RA, MEMDISP, RB);
103    }
104
105    std::string
106    MemoryNoDisp::generateDisassembly(Addr pc, const SymbolTable *symtab) const
107    {
108        return csprintf("%-10s (r%d)", mnemonic, RB);
109    }
110}};
111
112def format LoadAddress(code) {{
113    iop = InstObjParams(name, Name, 'MemoryDisp32', code)
114    header_output = BasicDeclare.subst(iop)
115    decoder_output = BasicConstructor.subst(iop)
116    decode_block = BasicDecode.subst(iop)
117    exec_output = BasicExecute.subst(iop)
118}};
119
120
121def template LoadStoreDeclare {{
122    /**
123     * Static instruction class for "%(mnemonic)s".
124     */
125    class %(class_name)s : public %(base_class)s
126    {
127      public:
128
129        /// Constructor.
130        %(class_name)s(ExtMachInst machInst);
131
132        Fault execute(ExecContext *, Trace::InstRecord *) const override;
133        Fault initiateAcc(ExecContext *, Trace::InstRecord *) const override;
134        Fault completeAcc(PacketPtr, ExecContext *,
135                          Trace::InstRecord *) const override;
136    };
137}};
138
139def template LoadStoreConstructor {{
140    %(class_name)s::%(class_name)s(ExtMachInst machInst)
141         : %(base_class)s("%(mnemonic)s", machInst, %(op_class)s)
142    {
143        %(constructor)s;
144    }
145}};
146
147
148def template LoadExecute {{
149    Fault %(class_name)s::execute(ExecContext *xc,
150                                  Trace::InstRecord *traceData) const
151    {
152        Addr EA;
153        Fault fault = NoFault;
154
155        %(fp_enable_check)s;
156        %(op_decl)s;
157        %(op_rd)s;
158        %(ea_code)s;
159
160        if (fault == NoFault) {
161            fault = readMemAtomic(xc, traceData, EA, Mem, memAccessFlags);
162            %(memacc_code)s;
163        }
164
165        if (fault == NoFault) {
166            %(op_wb)s;
167        }
168
169        return fault;
170    }
171}};
172
173
174def template LoadInitiateAcc {{
175    Fault %(class_name)s::initiateAcc(ExecContext *xc,
176                                      Trace::InstRecord *traceData) const
177    {
178        Addr EA;
179        Fault fault = NoFault;
180
181        %(fp_enable_check)s;
182        %(op_src_decl)s;
183        %(op_rd)s;
184        %(ea_code)s;
185
186        if (fault == NoFault) {
187            fault = initiateMemRead(xc, traceData, EA, Mem, memAccessFlags);
188        }
189
190        return fault;
191    }
192}};
193
194
195def template LoadCompleteAcc {{
196    Fault %(class_name)s::completeAcc(PacketPtr pkt, ExecContext *xc,
197                                      Trace::InstRecord *traceData) const
198    {
199        Fault fault = NoFault;
200
201        %(fp_enable_check)s;
202        %(op_decl)s;
203
204        getMem(pkt, Mem, traceData);
205
206        if (fault == NoFault) {
207            %(memacc_code)s;
208        }
209
210        if (fault == NoFault) {
211            %(op_wb)s;
212        }
213
214        return fault;
215    }
216}};
217
218
219def template StoreExecute {{
220    Fault %(class_name)s::execute(ExecContext *xc,
221                                  Trace::InstRecord *traceData) const
222    {
223        Addr EA;
224        Fault fault = NoFault;
225
226        %(fp_enable_check)s;
227        %(op_decl)s;
228        %(op_rd)s;
229        %(ea_code)s;
230
231        if (fault == NoFault) {
232            %(memacc_code)s;
233        }
234
235        if (fault == NoFault) {
236            fault = writeMemAtomic(xc, traceData, Mem, EA,
237                    memAccessFlags, NULL);
238        }
239
240        if (fault == NoFault) {
241            %(postacc_code)s;
242        }
243
244        if (fault == NoFault) {
245            %(op_wb)s;
246        }
247
248        return fault;
249    }
250}};
251
252def template StoreCondExecute {{
253    Fault %(class_name)s::execute(ExecContext *xc,
254                                  Trace::InstRecord *traceData) const
255    {
256        Addr EA;
257        Fault fault = NoFault;
258        uint64_t write_result = 0;
259
260        %(fp_enable_check)s;
261        %(op_decl)s;
262        %(op_rd)s;
263        %(ea_code)s;
264
265        if (fault == NoFault) {
266            %(memacc_code)s;
267        }
268
269        if (fault == NoFault) {
270            fault = writeMemAtomic(xc, traceData, Mem, EA,
271                    memAccessFlags, &write_result);
272        }
273
274        if (fault == NoFault) {
275            %(postacc_code)s;
276        }
277
278        if (fault == NoFault) {
279            %(op_wb)s;
280        }
281
282        return fault;
283    }
284}};
285
286def template StoreInitiateAcc {{
287    Fault %(class_name)s::initiateAcc(ExecContext *xc,
288                                      Trace::InstRecord *traceData) const
289    {
290        Addr EA;
291        Fault fault = NoFault;
292
293        %(fp_enable_check)s;
294        %(op_decl)s;
295        %(op_rd)s;
296        %(ea_code)s;
297
298        if (fault == NoFault) {
299            %(memacc_code)s;
300        }
301
302        if (fault == NoFault) {
303            fault = writeMemTiming(xc, traceData, Mem, EA,
304                    memAccessFlags, NULL);
305        }
306
307        return fault;
308    }
309}};
310
311
312def template StoreCompleteAcc {{
313    Fault %(class_name)s::completeAcc(PacketPtr pkt, ExecContext *xc,
314                                      Trace::InstRecord *traceData) const
315    {
316        return NoFault;
317    }
318}};
319
320
321def template StoreCondCompleteAcc {{
322    Fault %(class_name)s::completeAcc(PacketPtr pkt, ExecContext *xc,
323                                      Trace::InstRecord *traceData) const
324    {
325        Fault fault = NoFault;
326
327        %(fp_enable_check)s;
328        %(op_dest_decl)s;
329
330        uint64_t write_result = pkt->req->getExtraData();
331
332        if (fault == NoFault) {
333            %(postacc_code)s;
334        }
335
336        if (fault == NoFault) {
337            %(op_wb)s;
338        }
339
340        return fault;
341    }
342}};
343
344
345def template MiscExecute {{
346    Fault %(class_name)s::execute(ExecContext *xc,
347                                  Trace::InstRecord *traceData) const
348    {
349        Addr EA M5_VAR_USED;
350        Fault fault = NoFault;
351
352        %(fp_enable_check)s;
353        %(op_decl)s;
354        %(op_rd)s;
355        %(ea_code)s;
356
357        warn_once("Prefetch instructions in Alpha do not do anything\n");
358        if (fault == NoFault) {
359            %(memacc_code)s;
360        }
361
362        return NoFault;
363    }
364}};
365
366// Prefetches in Alpha don't actually do anything
367// They just build an effective address and complete
368def template MiscInitiateAcc {{
369    Fault %(class_name)s::initiateAcc(ExecContext *xc,
370                                      Trace::InstRecord *traceData) const
371    {
372        warn("initiateAcc undefined: Misc instruction does not support split "
373             "access method!");
374        return NoFault;
375    }
376}};
377
378
379def template MiscCompleteAcc {{
380    Fault %(class_name)s::completeAcc(PacketPtr pkt, ExecContext *xc,
381                                      Trace::InstRecord *traceData) const
382    {
383        warn("completeAcc undefined: Misc instruction does not support split "
384             "access method!");
385
386        return NoFault;
387    }
388}};
389
390
391// load instructions use Ra as dest, so check for
392// Ra == 31 to detect nops
393def template LoadNopCheckDecode {{
394 {
395     AlphaStaticInst *i = new %(class_name)s(machInst);
396     if (RA == 31) {
397         i = makeNop(i);
398     }
399     return i;
400 }
401}};
402
403
404// for some load instructions, Ra == 31 indicates a prefetch (not a nop)
405def template LoadPrefetchCheckDecode {{
406 {
407     if (RA != 31) {
408         return new %(class_name)s(machInst);
409     }
410     else {
411         return new %(class_name)sPrefetch(machInst);
412     }
413 }
414}};
415
416
417let {{
418def LoadStoreBase(name, Name, ea_code, memacc_code, mem_flags, inst_flags,
419                  postacc_code = '', base_class = 'MemoryDisp32',
420                  decode_template = BasicDecode, exec_template_base = ''):
421    # Make sure flags are in lists (convert to lists if not).
422    mem_flags = makeList(mem_flags)
423    inst_flags = makeList(inst_flags)
424
425    iop = InstObjParams(name, Name, base_class,
426                        { 'ea_code':ea_code, 'memacc_code':memacc_code, 'postacc_code':postacc_code },
427                        inst_flags)
428
429    if mem_flags:
430        mem_flags = [ 'Request::%s' % flag for flag in mem_flags ]
431        s = '\n\tmemAccessFlags = ' + string.join(mem_flags, '|') + ';'
432        iop.constructor += s
433
434    # select templates
435
436    # The InitiateAcc template is the same for StoreCond templates as the
437    # corresponding Store template..
438    StoreCondInitiateAcc = StoreInitiateAcc
439
440    fullExecTemplate = eval(exec_template_base + 'Execute')
441    initiateAccTemplate = eval(exec_template_base + 'InitiateAcc')
442    completeAccTemplate = eval(exec_template_base + 'CompleteAcc')
443
444    # (header_output, decoder_output, decode_block, exec_output)
445    return (LoadStoreDeclare.subst(iop),
446            LoadStoreConstructor.subst(iop),
447            decode_template.subst(iop),
448            fullExecTemplate.subst(iop)
449            + initiateAccTemplate.subst(iop)
450            + completeAccTemplate.subst(iop))
451}};
452
453def format LoadOrNop(memacc_code, ea_code = {{ EA = Rb + disp; }},
454                     mem_flags = [], inst_flags = []) {{
455    (header_output, decoder_output, decode_block, exec_output) = \
456        LoadStoreBase(name, Name, ea_code, memacc_code, mem_flags, inst_flags,
457                      decode_template = LoadNopCheckDecode,
458                      exec_template_base = 'Load')
459}};
460
461
462// Note that the flags passed in apply only to the prefetch version
463def format LoadOrPrefetch(memacc_code, ea_code = {{ EA = Rb + disp; }},
464                          mem_flags = [], pf_flags = [], inst_flags = []) {{
465    # declare the load instruction object and generate the decode block
466    (header_output, decoder_output, decode_block, exec_output) = \
467        LoadStoreBase(name, Name, ea_code, memacc_code, mem_flags, inst_flags,
468                      decode_template = LoadPrefetchCheckDecode,
469                      exec_template_base = 'Load')
470
471    # Declare the prefetch instruction object.
472
473    # Make sure flag args are lists so we can mess with them.
474    mem_flags = makeList(mem_flags)
475    pf_flags = makeList(pf_flags)
476    inst_flags = makeList(inst_flags)
477
478    pf_mem_flags = mem_flags + pf_flags + ['PREFETCH']
479    pf_inst_flags = inst_flags
480
481    (pf_header_output, pf_decoder_output, _, pf_exec_output) = \
482        LoadStoreBase(name, Name + 'Prefetch', ea_code, ';',
483                      pf_mem_flags, pf_inst_flags, exec_template_base = 'Misc')
484
485    header_output += pf_header_output
486    decoder_output += pf_decoder_output
487    exec_output += pf_exec_output
488}};
489
490
491def format Store(memacc_code, ea_code = {{ EA = Rb + disp; }},
492                 mem_flags = [], inst_flags = []) {{
493    (header_output, decoder_output, decode_block, exec_output) = \
494        LoadStoreBase(name, Name, ea_code, memacc_code, mem_flags, inst_flags,
495                      exec_template_base = 'Store')
496}};
497
498
499def format StoreCond(memacc_code, postacc_code,
500                     ea_code = {{ EA = Rb + disp; }},
501                     mem_flags = [], inst_flags = []) {{
502    (header_output, decoder_output, decode_block, exec_output) = \
503        LoadStoreBase(name, Name, ea_code, memacc_code, mem_flags, inst_flags,
504                      postacc_code, exec_template_base = 'StoreCond')
505}};
506
507
508// Use 'MemoryNoDisp' as base: for wh64, fetch, ecb
509def format MiscPrefetch(ea_code, memacc_code,
510                        mem_flags = [], inst_flags = []) {{
511    (header_output, decoder_output, decode_block, exec_output) = \
512        LoadStoreBase(name, Name, ea_code, memacc_code, mem_flags, inst_flags,
513                      base_class = 'MemoryNoDisp', exec_template_base = 'Misc')
514}};
515
516
517