macromem.isa revision 6019
1// -*- mode:c++ -*-
2
3// Copyright (c) 2007-2008 The Florida State University
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: Stephen Hines
30
31////////////////////////////////////////////////////////////////////
32//
33// Macro Memory-format instructions
34//
35
36output header {{
37
38    /**
39     * Arm Macro Memory operations like LDM/STM
40     */
41    class ArmMacroMemoryOp : public PredMacroOp
42    {
43        protected:
44        /// Memory request flags.  See mem_req_base.hh.
45        unsigned memAccessFlags;
46        /// Pointer to EAComp object.
47        const StaticInstPtr eaCompPtr;
48        /// Pointer to MemAcc object.
49        const StaticInstPtr memAccPtr;
50
51        uint32_t reglist;
52        uint32_t ones;
53        uint32_t puswl,
54                 prepost,
55                 up,
56                 psruser,
57                 writeback,
58                 loadop;
59
60        ArmMacroMemoryOp(const char *mnem, MachInst _machInst, OpClass __opClass,
61                     StaticInstPtr _eaCompPtr = nullStaticInstPtr,
62                     StaticInstPtr _memAccPtr = nullStaticInstPtr)
63            : PredMacroOp(mnem, _machInst, __opClass),
64            memAccessFlags(0), eaCompPtr(_eaCompPtr), memAccPtr(_memAccPtr),
65            reglist(REGLIST), ones(0), puswl(PUSWL), prepost(PREPOST), up(UP),
66            psruser(PSRUSER), writeback(WRITEBACK), loadop(LOADOP)
67        {
68            ones = number_of_ones(reglist);
69            numMicroops = ones + writeback + 1;
70            // Remember that writeback adds a uop
71            microOps = new StaticInstPtr[numMicroops];
72        }
73    };
74
75    /**
76     * Arm Macro FPA operations to fix ldfd and stfd instructions
77     */
78    class ArmMacroFPAOp : public PredMacroOp
79    {
80        protected:
81        uint32_t puswl,
82                 prepost,
83                 up,
84                 psruser,
85                 writeback,
86                 loadop;
87        int32_t disp8;
88
89        ArmMacroFPAOp(const char *mnem, MachInst _machInst, OpClass __opClass)
90            : PredMacroOp(mnem, _machInst, __opClass),
91            puswl(PUSWL), prepost(PREPOST), up(UP),
92            psruser(PSRUSER), writeback(WRITEBACK), loadop(LOADOP),
93            disp8(IMMED_7_0 << 2)
94        {
95            numMicroops = 3 + writeback;
96            microOps = new StaticInstPtr[numMicroops];
97        }
98    };
99
100    /**
101     * Arm Macro FM operations to fix lfm and sfm
102     */
103    class ArmMacroFMOp : public PredMacroOp
104    {
105        protected:
106        uint32_t punwl,
107                 prepost,
108                 up,
109                 n1bit,
110                 writeback,
111                 loadop,
112                 n0bit,
113                 count;
114        int32_t disp8;
115
116        ArmMacroFMOp(const char *mnem, MachInst _machInst, OpClass __opClass)
117            : PredMacroOp(mnem, _machInst, __opClass),
118            punwl(PUNWL), prepost(PREPOST), up(UP),
119            n1bit(OPCODE_22), writeback(WRITEBACK), loadop(LOADOP),
120            n0bit(OPCODE_15), disp8(IMMED_7_0 << 2)
121        {
122            // Transfer 1-4 registers based on n1 and n0 bits (with 00 repr. 4)
123            count = (n1bit << 1) | n0bit;
124            if (count == 0)
125                count = 4;
126            numMicroops = (3*count) + writeback;
127            microOps = new StaticInstPtr[numMicroops];
128        }
129    };
130
131
132}};
133
134
135output decoder {{
136}};
137
138def template MacroStoreDeclare {{
139    /**
140     * Static instructions class for a store multiple instruction
141     */
142    class %(class_name)s : public %(base_class)s
143    {
144        public:
145            // Constructor
146            %(class_name)s(MachInst machInst);
147            %(BasicExecDeclare)s
148    };
149}};
150
151def template MacroStoreConstructor {{
152    inline %(class_name)s::%(class_name)s(MachInst machInst)
153        : %(base_class)s("%(mnemonic)s", machInst, %(op_class)s)
154    {
155        %(constructor)s;
156        uint32_t regs_to_handle = reglist;
157        uint32_t j = 0,
158                 start_addr = 0,
159                 end_addr = 0;
160
161        switch (puswl)
162        {
163            case 0x01: //     L ldmda_l
164                start_addr = (ones << 2) - 4;
165                end_addr = 0;
166                break;
167            case 0x03: //    WL ldmda_wl
168                start_addr = (ones << 2) - 4;
169                end_addr = 0;
170                break;
171            case 0x08: //  U    stmia_u
172                start_addr = 0;
173                end_addr = (ones << 2) - 4;
174                break;
175            case 0x09: //  U  L ldmia_ul
176                start_addr = 0;
177                end_addr = (ones << 2) - 4;
178                break;
179            case 0x0b: //  U WL ldmia
180                start_addr = 0;
181                end_addr = (ones << 2) - 4;
182                break;
183            case 0x11: // P   L ldmdb
184                start_addr = (ones << 2); // U-bit is already 0 for subtract
185                end_addr = 4; // negative 4
186                break;
187            case 0x12: // P  W  stmdb
188                start_addr = (ones << 2); // U-bit is already 0 for subtract
189                end_addr = 4; // negative 4
190                break;
191            case 0x18: // PU    stmib
192                start_addr = 4;
193                end_addr = (ones << 2) + 4;
194                break;
195            case 0x19: // PU  L ldmib
196                start_addr = 4;
197                end_addr = (ones << 2) + 4;
198                break;
199            default:
200                panic("Unhandled Load/Store Multiple Instruction");
201                break;
202        }
203
204        //TODO - Add addi_uop/subi_uop here to create starting addresses
205        //Just using addi with 0 offset makes a "copy" of Rn for our use
206        uint32_t newMachInst = 0;
207        newMachInst = machInst & 0xffff0000;
208        microOps[0] = new Addi_uop(newMachInst);
209
210        for (int i = 1; i < ones+1; i++)
211        {
212            // Get next available bit for transfer
213            while (! ( regs_to_handle & (1<<j)))
214                j++;
215            regs_to_handle &= ~(1<<j);
216
217            microOps[i] = gen_ldrstr_uop(machInst, loadop, j, start_addr);
218
219            if (up)
220                start_addr += 4;
221            else
222                start_addr -= 4;
223        }
224
225        /* TODO: Take a look at how these 2 values should meet together
226        if (start_addr != (end_addr - 4))
227        {
228            fprintf(stderr, "start_addr: %d\n", start_addr);
229            fprintf(stderr, "end_addr:   %d\n", end_addr);
230            panic("start_addr does not meet end_addr");
231        }
232        */
233
234        if (writeback)
235        {
236            uint32_t newMachInst = machInst & 0xf0000000;
237            uint32_t rn = (machInst >> 16) & 0x0f;
238            // 3322 2222 2222 1111 1111 11
239            // 1098 7654 3210 9876 5432 1098 7654 3210
240            // COND 0010 0100 [RN] [RD] 0000 [  IMM  ]
241            // sub rn, rn, imm
242            newMachInst |= 0x02400000;
243            newMachInst |= ((rn << 16) | (rn << 12));
244            newMachInst |= (ones << 2);
245            if (up)
246            {
247                microOps[numMicroops-1] = new Addi_rd_uop(newMachInst);
248            }
249            else
250            {
251                microOps[numMicroops-1] = new Subi_rd_uop(newMachInst);
252            }
253        }
254        microOps[numMicroops-1]->setLastMicroop();
255    }
256
257}};
258
259def template MacroStoreExecute {{
260    Fault %(class_name)s::execute(%(CPU_exec_context)s *xc, Trace::InstRecord *traceData) const
261    {
262        Fault fault = NoFault;
263
264        %(fp_enable_check)s;
265        %(op_decl)s;
266        %(op_rd)s;
267        %(code)s;
268        if (fault == NoFault)
269        {
270            %(op_wb)s;
271        }
272
273        return fault;
274    }
275}};
276
277def template MacroFPAConstructor {{
278    inline %(class_name)s::%(class_name)s(MachInst machInst)
279        : %(base_class)s("%(mnemonic)s", machInst, %(op_class)s)
280    {
281        %(constructor)s;
282
283        uint32_t start_addr = 0;
284
285        if (prepost)
286            start_addr = disp8;
287        else
288            start_addr = 0;
289
290        emit_ldfstf_uops(microOps, 0, machInst, loadop, up, start_addr);
291
292        if (writeback)
293        {
294            uint32_t newMachInst = machInst & 0xf0000000;
295            uint32_t rn = (machInst >> 16) & 0x0f;
296            // 3322 2222 2222 1111 1111 11
297            // 1098 7654 3210 9876 5432 1098 7654 3210
298            // COND 0010 0100 [RN] [RD] 0000 [  IMM  ]
299            // sub rn, rn, imm
300            newMachInst |= 0x02400000;
301            newMachInst |= ((rn << 16) | (rn << 12));
302            if (up)
303            {
304                newMachInst |= disp8;
305                microOps[numMicroops-1] = new Addi_rd_uop(newMachInst);
306            }
307            else
308            {
309                newMachInst |= disp8;
310                microOps[numMicroops-1] = new Subi_rd_uop(newMachInst);
311            }
312        }
313        microOps[numMicroops-1]->setLastMicroop();
314    }
315
316}};
317
318
319def template MacroFMConstructor {{
320    inline %(class_name)s::%(class_name)s(MachInst machInst)
321        : %(base_class)s("%(mnemonic)s", machInst, %(op_class)s)
322    {
323        %(constructor)s;
324
325        uint32_t start_addr = 0;
326
327        if (prepost)
328            start_addr = disp8;
329        else
330            start_addr = 0;
331
332        for (int i = 0; i < count; i++)
333        {
334            emit_ldfstf_uops(microOps, 3*i, machInst, loadop, up, start_addr);
335        }
336
337        if (writeback)
338        {
339            uint32_t newMachInst = machInst & 0xf0000000;
340            uint32_t rn = (machInst >> 16) & 0x0f;
341            // 3322 2222 2222 1111 1111 11
342            // 1098 7654 3210 9876 5432 1098 7654 3210
343            // COND 0010 0100 [RN] [RD] 0000 [  IMM  ]
344            // sub rn, rn, imm
345            newMachInst |= 0x02400000;
346            newMachInst |= ((rn << 16) | (rn << 12));
347            if (up)
348            {
349                newMachInst |= disp8;
350                microOps[numMicroops-1] = new Addi_rd_uop(newMachInst);
351            }
352            else
353            {
354                newMachInst |= disp8;
355                microOps[numMicroops-1] = new Subi_rd_uop(newMachInst);
356            }
357        }
358        microOps[numMicroops-1]->setLastMicroop();
359    }
360
361}};
362
363
364def format ArmMacroStore(code, mem_flags = [], inst_flag = [], *opt_flags) {{
365    iop = InstObjParams(name, Name, 'ArmMacroMemoryOp', code, opt_flags)
366    header_output = MacroStoreDeclare.subst(iop)
367    decoder_output = MacroStoreConstructor.subst(iop)
368    decode_block = BasicDecode.subst(iop)
369    exec_output = MacroStoreExecute.subst(iop)
370}};
371
372def format ArmMacroFPAOp(code, mem_flags = [], inst_flag = [], *opt_flags) {{
373    iop = InstObjParams(name, Name, 'ArmMacroFPAOp', code, opt_flags)
374    header_output = BasicDeclare.subst(iop)
375    decoder_output = MacroFPAConstructor.subst(iop)
376    decode_block = BasicDecode.subst(iop)
377    exec_output = PredOpExecute.subst(iop)
378}};
379
380def format ArmMacroFMOp(code, mem_flags = [], inst_flag = [], *opt_flags) {{
381    iop = InstObjParams(name, Name, 'ArmMacroFMOp', code, opt_flags)
382    header_output = BasicDeclare.subst(iop)
383    decoder_output = MacroFMConstructor.subst(iop)
384    decode_block = BasicDecode.subst(iop)
385    exec_output = PredOpExecute.subst(iop)
386}};
387
388
389
390