blob: 0dc50376da6a3632f1b95a5eb9ebed6d5f7e9258 [file] [log] [blame]
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -07001/* libs/pixelflinger/codeflinger/ARMAssembler.cpp
2**
3** Copyright 2006, The Android Open Source Project
4**
5** Licensed under the Apache License, Version 2.0 (the "License");
6** you may not use this file except in compliance with the License.
7** You may obtain a copy of the License at
8**
9** http://www.apache.org/licenses/LICENSE-2.0
10**
11** Unless required by applicable law or agreed to in writing, software
12** distributed under the License is distributed on an "AS IS" BASIS,
13** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14** See the License for the specific language governing permissions and
15** limitations under the License.
16*/
17
18#define LOG_TAG "ARMAssembler"
19
20#include <stdio.h>
21#include <stdlib.h>
22#include <cutils/log.h>
23#include <cutils/properties.h>
24
25#if defined(WITH_LIB_HARDWARE)
The Android Open Source Project2eef6022009-01-15 16:12:14 -080026#include <hardware_legacy/qemu_tracing.h>
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -070027#endif
28
29#include <private/pixelflinger/ggl_context.h>
30
31#include "codeflinger/ARMAssembler.h"
32#include "codeflinger/CodeCache.h"
33#include "codeflinger/disassem.h"
34
35// ----------------------------------------------------------------------------
36
37namespace android {
38
39// ----------------------------------------------------------------------------
40#if 0
41#pragma mark -
42#pragma mark ARMAssembler...
43#endif
44
45ARMAssembler::ARMAssembler(const sp<Assembly>& assembly)
46 : ARMAssemblerInterface(),
47 mAssembly(assembly)
48{
49 mBase = mPC = (uint32_t *)assembly->base();
50 mDuration = ggl_system_time();
51#if defined(WITH_LIB_HARDWARE)
52 mQemuTracing = true;
53#endif
54}
55
56ARMAssembler::~ARMAssembler()
57{
58}
59
60uint32_t* ARMAssembler::pc() const
61{
62 return mPC;
63}
64
65uint32_t* ARMAssembler::base() const
66{
67 return mBase;
68}
69
70void ARMAssembler::reset()
71{
72 mBase = mPC = (uint32_t *)mAssembly->base();
73 mBranchTargets.clear();
74 mLabels.clear();
75 mLabelsInverseMapping.clear();
76 mComments.clear();
77}
78
79// ----------------------------------------------------------------------------
80
81void ARMAssembler::disassemble(const char* name)
82{
83 if (name) {
84 printf("%s:\n", name);
85 }
86 size_t count = pc()-base();
87 uint32_t* i = base();
88 while (count--) {
89 ssize_t label = mLabelsInverseMapping.indexOfKey(i);
90 if (label >= 0) {
91 printf("%s:\n", mLabelsInverseMapping.valueAt(label));
92 }
93 ssize_t comment = mComments.indexOfKey(i);
94 if (comment >= 0) {
95 printf("; %s\n", mComments.valueAt(comment));
96 }
97 printf("%08x: %08x ", int(i), int(i[0]));
98 ::disassemble((u_int)i);
99 i++;
100 }
101}
102
103void ARMAssembler::comment(const char* string)
104{
105 mComments.add(mPC, string);
106}
107
108void ARMAssembler::label(const char* theLabel)
109{
110 mLabels.add(theLabel, mPC);
111 mLabelsInverseMapping.add(mPC, theLabel);
112}
113
114void ARMAssembler::B(int cc, const char* label)
115{
116 mBranchTargets.add(branch_target_t(label, mPC));
117 *mPC++ = (cc<<28) | (0xA<<24) | 0;
118}
119
120void ARMAssembler::BL(int cc, const char* label)
121{
122 mBranchTargets.add(branch_target_t(label, mPC));
123 *mPC++ = (cc<<28) | (0xB<<24) | 0;
124}
125
126#if 0
127#pragma mark -
128#pragma mark Prolog/Epilog & Generate...
129#endif
130
131
132void ARMAssembler::prolog()
133{
134 // write dummy prolog code
135 mPrologPC = mPC;
136 STM(AL, FD, SP, 1, LSAVED);
137}
138
139void ARMAssembler::epilog(uint32_t touched)
140{
141 touched &= LSAVED;
142 if (touched) {
143 // write prolog code
144 uint32_t* pc = mPC;
145 mPC = mPrologPC;
146 STM(AL, FD, SP, 1, touched | LLR);
147 mPC = pc;
148 // write epilog code
149 LDM(AL, FD, SP, 1, touched | LLR);
150 BX(AL, LR);
151 } else { // heh, no registers to save!
152 // write prolog code
153 uint32_t* pc = mPC;
154 mPC = mPrologPC;
155 MOV(AL, 0, R0, R0); // NOP
156 mPC = pc;
157 // write epilog code
158 BX(AL, LR);
159 }
160}
161
162int ARMAssembler::generate(const char* name)
163{
164 // fixup all the branches
165 size_t count = mBranchTargets.size();
166 while (count--) {
167 const branch_target_t& bt = mBranchTargets[count];
168 uint32_t* target_pc = mLabels.valueFor(bt.label);
169 LOG_ALWAYS_FATAL_IF(!target_pc,
170 "error resolving branch targets, target_pc is null");
171 int32_t offset = int32_t(target_pc - (bt.pc+2));
172 *bt.pc |= offset & 0xFFFFFF;
173 }
174
175 mAssembly->resize( int(pc()-base())*4 );
176
177 // the instruction cache is flushed by CodeCache
178 const int64_t duration = ggl_system_time() - mDuration;
179 const char * const format = "generated %s (%d ins) at [%p:%p] in %lld ns\n";
Steve Blockfe71a612012-01-04 19:19:03 +0000180 ALOGI(format, name, int(pc()-base()), base(), pc(), duration);
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700181
182#if defined(WITH_LIB_HARDWARE)
183 if (__builtin_expect(mQemuTracing, 0)) {
184 int err = qemu_add_mapping(int(base()), name);
185 mQemuTracing = (err >= 0);
186 }
187#endif
188
189 char value[PROPERTY_VALUE_MAX];
190 property_get("debug.pf.disasm", value, "0");
191 if (atoi(value) != 0) {
192 printf(format, name, int(pc()-base()), base(), pc(), duration);
193 disassemble(name);
194 }
195
196 return NO_ERROR;
197}
198
199uint32_t* ARMAssembler::pcForLabel(const char* label)
200{
201 return mLabels.valueFor(label);
202}
203
204// ----------------------------------------------------------------------------
205
206#if 0
207#pragma mark -
208#pragma mark Data Processing...
209#endif
210
211void ARMAssembler::dataProcessing(int opcode, int cc,
212 int s, int Rd, int Rn, uint32_t Op2)
213{
214 *mPC++ = (cc<<28) | (opcode<<21) | (s<<20) | (Rn<<16) | (Rd<<12) | Op2;
215}
216
217#if 0
218#pragma mark -
219#pragma mark Multiply...
220#endif
221
222// multiply...
223void ARMAssembler::MLA(int cc, int s,
224 int Rd, int Rm, int Rs, int Rn) {
225 if (Rd == Rm) { int t = Rm; Rm=Rs; Rs=t; }
226 LOG_FATAL_IF(Rd==Rm, "MLA(r%u,r%u,r%u,r%u)", Rd,Rm,Rs,Rn);
227 *mPC++ = (cc<<28) | (1<<21) | (s<<20) |
228 (Rd<<16) | (Rn<<12) | (Rs<<8) | 0x90 | Rm;
229}
230void ARMAssembler::MUL(int cc, int s,
231 int Rd, int Rm, int Rs) {
232 if (Rd == Rm) { int t = Rm; Rm=Rs; Rs=t; }
233 LOG_FATAL_IF(Rd==Rm, "MUL(r%u,r%u,r%u)", Rd,Rm,Rs);
234 *mPC++ = (cc<<28) | (s<<20) | (Rd<<16) | (Rs<<8) | 0x90 | Rm;
235}
236void ARMAssembler::UMULL(int cc, int s,
237 int RdLo, int RdHi, int Rm, int Rs) {
238 LOG_FATAL_IF(RdLo==Rm || RdHi==Rm || RdLo==RdHi,
239 "UMULL(r%u,r%u,r%u,r%u)", RdLo,RdHi,Rm,Rs);
240 *mPC++ = (cc<<28) | (1<<23) | (s<<20) |
241 (RdHi<<16) | (RdLo<<12) | (Rs<<8) | 0x90 | Rm;
242}
243void ARMAssembler::UMUAL(int cc, int s,
244 int RdLo, int RdHi, int Rm, int Rs) {
245 LOG_FATAL_IF(RdLo==Rm || RdHi==Rm || RdLo==RdHi,
246 "UMUAL(r%u,r%u,r%u,r%u)", RdLo,RdHi,Rm,Rs);
247 *mPC++ = (cc<<28) | (1<<23) | (1<<21) | (s<<20) |
248 (RdHi<<16) | (RdLo<<12) | (Rs<<8) | 0x90 | Rm;
249}
250void ARMAssembler::SMULL(int cc, int s,
251 int RdLo, int RdHi, int Rm, int Rs) {
252 LOG_FATAL_IF(RdLo==Rm || RdHi==Rm || RdLo==RdHi,
253 "SMULL(r%u,r%u,r%u,r%u)", RdLo,RdHi,Rm,Rs);
254 *mPC++ = (cc<<28) | (1<<23) | (1<<22) | (s<<20) |
255 (RdHi<<16) | (RdLo<<12) | (Rs<<8) | 0x90 | Rm;
256}
257void ARMAssembler::SMUAL(int cc, int s,
258 int RdLo, int RdHi, int Rm, int Rs) {
259 LOG_FATAL_IF(RdLo==Rm || RdHi==Rm || RdLo==RdHi,
260 "SMUAL(r%u,r%u,r%u,r%u)", RdLo,RdHi,Rm,Rs);
261 *mPC++ = (cc<<28) | (1<<23) | (1<<22) | (1<<21) | (s<<20) |
262 (RdHi<<16) | (RdLo<<12) | (Rs<<8) | 0x90 | Rm;
263}
264
265#if 0
266#pragma mark -
267#pragma mark Branches...
268#endif
269
270// branches...
271void ARMAssembler::B(int cc, uint32_t* pc)
272{
273 int32_t offset = int32_t(pc - (mPC+2));
274 *mPC++ = (cc<<28) | (0xA<<24) | (offset & 0xFFFFFF);
275}
276
277void ARMAssembler::BL(int cc, uint32_t* pc)
278{
279 int32_t offset = int32_t(pc - (mPC+2));
280 *mPC++ = (cc<<28) | (0xB<<24) | (offset & 0xFFFFFF);
281}
282
283void ARMAssembler::BX(int cc, int Rn)
284{
285 *mPC++ = (cc<<28) | 0x12FFF10 | Rn;
286}
287
288#if 0
289#pragma mark -
290#pragma mark Data Transfer...
291#endif
292
293// data transfert...
294void ARMAssembler::LDR(int cc, int Rd, int Rn, uint32_t offset) {
295 *mPC++ = (cc<<28) | (1<<26) | (1<<20) | (Rn<<16) | (Rd<<12) | offset;
296}
297void ARMAssembler::LDRB(int cc, int Rd, int Rn, uint32_t offset) {
298 *mPC++ = (cc<<28) | (1<<26) | (1<<22) | (1<<20) | (Rn<<16) | (Rd<<12) | offset;
299}
300void ARMAssembler::STR(int cc, int Rd, int Rn, uint32_t offset) {
301 *mPC++ = (cc<<28) | (1<<26) | (Rn<<16) | (Rd<<12) | offset;
302}
303void ARMAssembler::STRB(int cc, int Rd, int Rn, uint32_t offset) {
304 *mPC++ = (cc<<28) | (1<<26) | (1<<22) | (Rn<<16) | (Rd<<12) | offset;
305}
306
307void ARMAssembler::LDRH(int cc, int Rd, int Rn, uint32_t offset) {
308 *mPC++ = (cc<<28) | (1<<20) | (Rn<<16) | (Rd<<12) | 0xB0 | offset;
309}
310void ARMAssembler::LDRSB(int cc, int Rd, int Rn, uint32_t offset) {
311 *mPC++ = (cc<<28) | (1<<20) | (Rn<<16) | (Rd<<12) | 0xD0 | offset;
312}
313void ARMAssembler::LDRSH(int cc, int Rd, int Rn, uint32_t offset) {
314 *mPC++ = (cc<<28) | (1<<20) | (Rn<<16) | (Rd<<12) | 0xF0 | offset;
315}
316void ARMAssembler::STRH(int cc, int Rd, int Rn, uint32_t offset) {
317 *mPC++ = (cc<<28) | (Rn<<16) | (Rd<<12) | 0xB0 | offset;
318}
319
320#if 0
321#pragma mark -
322#pragma mark Block Data Transfer...
323#endif
324
325// block data transfer...
326void ARMAssembler::LDM(int cc, int dir,
327 int Rn, int W, uint32_t reg_list)
328{ // ED FD EA FA IB IA DB DA
329 const uint8_t P[8] = { 1, 0, 1, 0, 1, 0, 1, 0 };
330 const uint8_t U[8] = { 1, 1, 0, 0, 1, 1, 0, 0 };
331 *mPC++ = (cc<<28) | (4<<25) | (uint32_t(P[dir])<<24) |
332 (uint32_t(U[dir])<<23) | (1<<20) | (W<<21) | (Rn<<16) | reg_list;
333}
334
335void ARMAssembler::STM(int cc, int dir,
336 int Rn, int W, uint32_t reg_list)
Kan-Ru Chena7e96642010-05-04 15:53:33 +0800337{ // ED FD EA FA IB IA DB DA
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700338 const uint8_t P[8] = { 0, 1, 0, 1, 1, 0, 1, 0 };
339 const uint8_t U[8] = { 0, 0, 1, 1, 1, 1, 0, 0 };
340 *mPC++ = (cc<<28) | (4<<25) | (uint32_t(P[dir])<<24) |
341 (uint32_t(U[dir])<<23) | (0<<20) | (W<<21) | (Rn<<16) | reg_list;
342}
343
344#if 0
345#pragma mark -
346#pragma mark Special...
347#endif
348
349// special...
350void ARMAssembler::SWP(int cc, int Rn, int Rd, int Rm) {
351 *mPC++ = (cc<<28) | (2<<23) | (Rn<<16) | (Rd << 12) | 0x90 | Rm;
352}
353void ARMAssembler::SWPB(int cc, int Rn, int Rd, int Rm) {
354 *mPC++ = (cc<<28) | (2<<23) | (1<<22) | (Rn<<16) | (Rd << 12) | 0x90 | Rm;
355}
356void ARMAssembler::SWI(int cc, uint32_t comment) {
357 *mPC++ = (cc<<28) | (0xF<<24) | comment;
358}
359
360#if 0
361#pragma mark -
362#pragma mark DSP instructions...
363#endif
364
365// DSP instructions...
366void ARMAssembler::PLD(int Rn, uint32_t offset) {
367 LOG_ALWAYS_FATAL_IF(!((offset&(1<<24)) && !(offset&(1<<21))),
368 "PLD only P=1, W=0");
369 *mPC++ = 0xF550F000 | (Rn<<16) | offset;
370}
371
372void ARMAssembler::CLZ(int cc, int Rd, int Rm)
373{
374 *mPC++ = (cc<<28) | 0x16F0F10| (Rd<<12) | Rm;
375}
376
377void ARMAssembler::QADD(int cc, int Rd, int Rm, int Rn)
378{
379 *mPC++ = (cc<<28) | 0x1000050 | (Rn<<16) | (Rd<<12) | Rm;
380}
381
382void ARMAssembler::QDADD(int cc, int Rd, int Rm, int Rn)
383{
384 *mPC++ = (cc<<28) | 0x1400050 | (Rn<<16) | (Rd<<12) | Rm;
385}
386
387void ARMAssembler::QSUB(int cc, int Rd, int Rm, int Rn)
388{
389 *mPC++ = (cc<<28) | 0x1200050 | (Rn<<16) | (Rd<<12) | Rm;
390}
391
392void ARMAssembler::QDSUB(int cc, int Rd, int Rm, int Rn)
393{
394 *mPC++ = (cc<<28) | 0x1600050 | (Rn<<16) | (Rd<<12) | Rm;
395}
396
397void ARMAssembler::SMUL(int cc, int xy,
398 int Rd, int Rm, int Rs)
399{
400 *mPC++ = (cc<<28) | 0x1600080 | (Rd<<16) | (Rs<<8) | (xy<<4) | Rm;
401}
402
403void ARMAssembler::SMULW(int cc, int y,
404 int Rd, int Rm, int Rs)
405{
406 *mPC++ = (cc<<28) | 0x12000A0 | (Rd<<16) | (Rs<<8) | (y<<4) | Rm;
407}
408
409void ARMAssembler::SMLA(int cc, int xy,
410 int Rd, int Rm, int Rs, int Rn)
411{
412 *mPC++ = (cc<<28) | 0x1000080 | (Rd<<16) | (Rn<<12) | (Rs<<8) | (xy<<4) | Rm;
413}
414
415void ARMAssembler::SMLAL(int cc, int xy,
416 int RdHi, int RdLo, int Rs, int Rm)
417{
418 *mPC++ = (cc<<28) | 0x1400080 | (RdHi<<16) | (RdLo<<12) | (Rs<<8) | (xy<<4) | Rm;
419}
420
421void ARMAssembler::SMLAW(int cc, int y,
422 int Rd, int Rm, int Rs, int Rn)
423{
424 *mPC++ = (cc<<28) | 0x1200080 | (Rd<<16) | (Rn<<12) | (Rs<<8) | (y<<4) | Rm;
425}
426
Martyn Capewell96dbb4f2009-12-07 13:59:59 +0000427#if 0
428#pragma mark -
429#pragma mark Byte/half word extract and extend (ARMv6+ only)...
430#endif
431
432void ARMAssembler::UXTB16(int cc, int Rd, int Rm, int rotate)
433{
434 *mPC++ = (cc<<28) | 0x6CF0070 | (Rd<<12) | ((rotate >> 3) << 10) | Rm;
435}
Martyn Capewell4dc1fa82009-12-04 16:44:58 +0000436#if 0
437#pragma mark -
438#pragma mark Bit manipulation (ARMv7+ only)...
439#endif
440
441// Bit manipulation (ARMv7+ only)...
442void ARMAssembler::UBFX(int cc, int Rd, int Rn, int lsb, int width)
443{
444 *mPC++ = (cc<<28) | 0x7E00000 | ((width-1)<<16) | (Rd<<12) | (lsb<<7) | 0x50 | Rn;
445}
Martyn Capewell96dbb4f2009-12-07 13:59:59 +0000446
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700447}; // namespace android
448