1// Copyright (c) 2006-2007 The Regents of The University of Michigan
2// All rights reserved.
3//
4// Redistribution and use in source and binary forms, with or without
5// modification, are permitted provided that the following conditions are
6// met: redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer;
8// redistributions in binary form must reproduce the above copyright
9// notice, this list of conditions and the following disclaimer in the
10// documentation and/or other materials provided with the distribution;
11// neither the name of the copyright holders nor the names of its
12// contributors may be used to endorse or promote products derived from
13// this software without specific prior written permission.
14//
15// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
18// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
19// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
21// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26//
27// Authors: Ali Saidi
28//          Gabe Black
29//          Steve Reinhardt
30
31////////////////////////////////////////////////////////////////////
32//
33// Mem utility templates and functions
34//
35
36// This template provides the execute functions for a load
37def template LoadExecute {{
38        Fault %(class_name)s::execute(ExecContext *xc,
39                Trace::InstRecord *traceData) const
40        {
41            Fault fault = NoFault;
42            Addr EA;
43            %(fp_enable_check)s;
44            %(op_decl)s;
45            %(op_rd)s;
46            %(ea_code)s;
47            DPRINTF(Sparc, "%s: The address is 0x%x\n", mnemonic, EA);
48            %(fault_check)s;
49            if (fault == NoFault) {
50                %(EA_trunc)s
51                fault = readMemAtomic(xc, traceData, EA, Mem, %(asi_val)s);
52            }
53            if (fault == NoFault) {
54                %(code)s;
55            }
56            if (fault == NoFault) {
57                // Write the resulting state to the execution context
58                %(op_wb)s;
59            }
60
61            return fault;
62        }
63}};
64
65def template LoadInitiateAcc {{
66        Fault %(class_name)s::initiateAcc(ExecContext * xc,
67                Trace::InstRecord * traceData) const
68        {
69            Fault fault = NoFault;
70            Addr EA;
71            %(fp_enable_check)s;
72            %(op_decl)s;
73            %(op_rd)s;
74            %(ea_code)s;
75            DPRINTF(Sparc, "%s: The address is 0x%x\n", mnemonic, EA);
76            %(fault_check)s;
77            if (fault == NoFault) {
78                %(EA_trunc)s
79                fault = initiateMemRead(xc, traceData, EA, Mem, %(asi_val)s);
80            }
81            return fault;
82        }
83}};
84
85def template LoadCompleteAcc {{
86        Fault %(class_name)s::completeAcc(PacketPtr pkt, ExecContext * xc,
87                Trace::InstRecord * traceData) const
88        {
89            Fault fault = NoFault;
90            %(op_decl)s;
91            %(op_rd)s;
92            getMem(pkt, Mem, traceData);
93            %(code)s;
94            if (fault == NoFault) {
95                %(op_wb)s;
96            }
97            return fault;
98        }
99}};
100
101// This template provides the execute functions for a store
102def template StoreExecute {{
103        Fault %(class_name)s::execute(ExecContext *xc,
104                Trace::InstRecord *traceData) const
105        {
106            Fault fault = NoFault;
107            // This is to support the conditional store in cas instructions.
108            // It should be optomized out in all the others
109            bool storeCond = true;
110            Addr EA;
111            %(fp_enable_check)s;
112            %(op_decl)s;
113            %(op_rd)s;
114            %(ea_code)s;
115            DPRINTF(Sparc, "%s: The address is 0x%x\n", mnemonic, EA);
116            %(fault_check)s;
117            if (fault == NoFault) {
118                %(code)s;
119            }
120            if (storeCond && fault == NoFault) {
121                %(EA_trunc)s
122                fault = writeMemAtomic(xc, traceData, Mem, EA, %(asi_val)s, 0);
123            }
124            if (fault == NoFault) {
125                // Write the resulting state to the execution context
126                %(op_wb)s;
127            }
128
129            return fault;
130        }
131}};
132
133def template StoreInitiateAcc {{
134        Fault %(class_name)s::initiateAcc(ExecContext * xc,
135                Trace::InstRecord * traceData) const
136        {
137            Fault fault = NoFault;
138            bool storeCond = true;
139            Addr EA;
140            %(fp_enable_check)s;
141            %(op_decl)s;
142
143            %(op_rd)s;
144            %(ea_code)s;
145            DPRINTF(Sparc, "%s: The address is 0x%x\n", mnemonic, EA);
146            %(fault_check)s;
147            if (fault == NoFault) {
148                %(code)s;
149            }
150            if (storeCond && fault == NoFault) {
151                %(EA_trunc)s
152                fault = writeMemTiming(xc, traceData, Mem, EA, %(asi_val)s, 0);
153            }
154            return fault;
155        }
156}};
157
158def template StoreCompleteAcc {{
159        Fault %(class_name)s::completeAcc(PacketPtr, ExecContext * xc,
160                Trace::InstRecord * traceData) const
161        {
162            return NoFault;
163        }
164}};
165
166// Here are some code snippets which check for various fault conditions
167let {{
168    LoadFuncs = [LoadExecute, LoadInitiateAcc, LoadCompleteAcc]
169    StoreFuncs = [StoreExecute, StoreInitiateAcc, StoreCompleteAcc]
170
171    # The LSB can be zero, since it's really the MSB in doubles and quads
172    # and we're dealing with doubles
173    BlockAlignmentFaultCheck = '''
174        if (RD & 0xe)
175            fault = std::make_shared<IllegalInstruction>();
176        else if (EA & 0x3f)
177            fault = std::make_shared<MemAddressNotAligned>();
178    '''
179    TwinAlignmentFaultCheck = '''
180        if (RD & 0x1)
181            fault = std::make_shared<IllegalInstruction>();
182        else if (EA & 0xf)
183            fault = std::make_shared<MemAddressNotAligned>();
184    '''
185    # XXX Need to take care of pstate.hpriv as well. The lower ASIs
186    # are split into ones that are available in priv and hpriv, and
187    # those that are only available in hpriv
188    AlternateASIPrivFaultCheck = '''
189        if ((!Pstate.priv && !Hpstate.hpriv &&
190             !asiIsUnPriv((ASI)EXT_ASI)) ||
191            (!Hpstate.hpriv && asiIsHPriv((ASI)EXT_ASI)))
192            fault = std::make_shared<PrivilegedAction>();
193        else if (asiIsAsIfUser((ASI)EXT_ASI) && !Pstate.priv)
194            fault = std::make_shared<PrivilegedAction>();
195    '''
196
197    TruncateEA = '''
198        if (!FullSystem) {
199            EA = Pstate.am ? EA<31:0> : EA;
200        }
201    '''
202}};
203
204// A simple function to generate the name of the macro op of a certain
205// instruction at a certain micropc
206let {{
207    def makeMicroName(name, microPc):
208            return name + "::" + name + "_" + str(microPc)
209}};
210
211// This function properly generates the execute functions for one of the
212// templates above. This is needed because in one case, ea computation,
213// fault checks and the actual code all occur in the same function,
214// and in the other they're distributed across two. Also note that for
215// execute functions, the name of the base class doesn't matter.
216let {{
217    def doSplitExecute(execute, name, Name, asi, opt_flags, microParam):
218        microParam["asi_val"] = asi;
219        iop = InstObjParams(name, Name, '', microParam, opt_flags)
220        (execf, initf, compf) = execute
221        return execf.subst(iop) + initf.subst(iop) + compf.subst(iop)
222
223
224    def doDualSplitExecute(code, postacc_code, eaRegCode, eaImmCode, execute,
225            faultCode, nameReg, nameImm, NameReg, NameImm, asi, opt_flags):
226        executeCode = ''
227        for (eaCode, name, Name) in (
228                (eaRegCode, nameReg, NameReg),
229                (eaImmCode, nameImm, NameImm)):
230            microParams = {"code": code, "postacc_code" : postacc_code,
231                "ea_code": eaCode, "fault_check": faultCode,
232                "EA_trunc" : TruncateEA}
233            executeCode += doSplitExecute(execute, name, Name,
234                    asi, opt_flags, microParams)
235        return executeCode
236}};
237