From 606d4aecfb6a1e911dac207caeba617d1379c1f7 Mon Sep 17 00:00:00 2001 From: Elliott Hughes Date: Thu, 5 Nov 2015 18:55:20 +0000 Subject: [PATCH] Revert "Revert "Add MIPS64r6 support for libpixelflinger"" This reverts commit 7fd121788a892a0dfd4a9594304cad85fe366349. Change-Id: Ic1204a8407c235b07c643764d5f2800631fecd72 --- libpixelflinger/Android.mk | 9 + libpixelflinger/arch-mips/col32cb16blend.S | 134 ++ libpixelflinger/arch-mips/t32cb16blend.S | 373 ++--- libpixelflinger/arch-mips64/col32cb16blend.S | 108 ++ libpixelflinger/arch-mips64/t32cb16blend.S | 172 ++ .../codeflinger/ARMAssemblerInterface.h | 5 +- libpixelflinger/codeflinger/GGLAssembler.cpp | 9 +- .../codeflinger/MIPS64Assembler.cpp | 1452 +++++++++++++++++ libpixelflinger/codeflinger/MIPS64Assembler.h | 429 +++++ libpixelflinger/codeflinger/MIPSAssembler.cpp | 4 +- libpixelflinger/codeflinger/MIPSAssembler.h | 30 +- libpixelflinger/codeflinger/mips64_disassem.c | 582 +++++++ libpixelflinger/codeflinger/mips64_disassem.h | 56 + libpixelflinger/codeflinger/mips_disassem.c | 8 +- libpixelflinger/codeflinger/mips_opcode.h | 220 ++- .../private/pixelflinger/ggl_context.h | 4 +- .../include/private/pixelflinger/ggl_fixed.h | 246 +++ libpixelflinger/scanline.cpp | 24 +- libpixelflinger/tests/arch-mips/Android.mk | 6 + .../tests/arch-mips/col32cb16blend/Android.mk | 18 + .../col32cb16blend/col32cb16blend_test.c | 125 ++ .../tests/arch-mips/t32cb16blend/Android.mk | 18 + .../t32cb16blend/t32cb16blend_test.c | 134 ++ libpixelflinger/tests/arch-mips64/Android.mk | 3 + .../tests/arch-mips64/assembler/Android.mk | 21 + .../assembler/asm_mips_test_jacket.S | 93 ++ .../assembler/mips64_assembler_test.cpp | 644 ++++++++ .../arch-mips64/col32cb16blend/Android.mk | 18 + .../col32cb16blend/col32cb16blend_test.c | 125 ++ .../tests/arch-mips64/disassembler/Android.mk | 16 + .../disassembler/mips64_disassembler_test.cpp | 218 +++ libpixelflinger/tests/codegen/codegen.cpp | 10 +- 32 files changed, 5035 insertions(+), 279 deletions(-) create mode 100644 libpixelflinger/arch-mips/col32cb16blend.S create mode 100644 libpixelflinger/arch-mips64/col32cb16blend.S create mode 100644 libpixelflinger/arch-mips64/t32cb16blend.S create mode 100644 libpixelflinger/codeflinger/MIPS64Assembler.cpp create mode 100644 libpixelflinger/codeflinger/MIPS64Assembler.h create mode 100644 libpixelflinger/codeflinger/mips64_disassem.c create mode 100644 libpixelflinger/codeflinger/mips64_disassem.h create mode 100644 libpixelflinger/tests/arch-mips/Android.mk create mode 100644 libpixelflinger/tests/arch-mips/col32cb16blend/Android.mk create mode 100644 libpixelflinger/tests/arch-mips/col32cb16blend/col32cb16blend_test.c create mode 100644 libpixelflinger/tests/arch-mips/t32cb16blend/Android.mk create mode 100644 libpixelflinger/tests/arch-mips/t32cb16blend/t32cb16blend_test.c create mode 100644 libpixelflinger/tests/arch-mips64/Android.mk create mode 100644 libpixelflinger/tests/arch-mips64/assembler/Android.mk create mode 100644 libpixelflinger/tests/arch-mips64/assembler/asm_mips_test_jacket.S create mode 100644 libpixelflinger/tests/arch-mips64/assembler/mips64_assembler_test.cpp create mode 100644 libpixelflinger/tests/arch-mips64/col32cb16blend/Android.mk create mode 100644 libpixelflinger/tests/arch-mips64/col32cb16blend/col32cb16blend_test.c create mode 100644 libpixelflinger/tests/arch-mips64/disassembler/Android.mk create mode 100644 libpixelflinger/tests/arch-mips64/disassembler/mips64_disassembler_test.cpp diff --git a/libpixelflinger/Android.mk b/libpixelflinger/Android.mk index 65a3fdfcf..9a937f8f4 100644 --- a/libpixelflinger/Android.mk +++ b/libpixelflinger/Android.mk @@ -50,6 +50,14 @@ PIXELFLINGER_SRC_FILES_mips := \ arch-mips/t32cb16blend.S \ endif + +PIXELFLINGER_SRC_FILES_mips64 := \ + codeflinger/MIPSAssembler.cpp \ + codeflinger/MIPS64Assembler.cpp \ + codeflinger/mips64_disassem.c \ + arch-mips64/col32cb16blend.S \ + arch-mips64/t32cb16blend.S \ + # # Shared library # @@ -59,6 +67,7 @@ LOCAL_SRC_FILES := $(PIXELFLINGER_SRC_FILES) LOCAL_SRC_FILES_arm := $(PIXELFLINGER_SRC_FILES_arm) LOCAL_SRC_FILES_arm64 := $(PIXELFLINGER_SRC_FILES_arm64) LOCAL_SRC_FILES_mips := $(PIXELFLINGER_SRC_FILES_mips) +LOCAL_SRC_FILES_mips64 := $(PIXELFLINGER_SRC_FILES_mips64) LOCAL_CFLAGS := $(PIXELFLINGER_CFLAGS) LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include LOCAL_C_INCLUDES += $(LOCAL_EXPORT_C_INCLUDE_DIRS) \ diff --git a/libpixelflinger/arch-mips/col32cb16blend.S b/libpixelflinger/arch-mips/col32cb16blend.S new file mode 100644 index 000000000..5d18e5533 --- /dev/null +++ b/libpixelflinger/arch-mips/col32cb16blend.S @@ -0,0 +1,134 @@ +/* +** Copyright 2015, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + + .macro pixel dreg src f sR sG sB shift + +#if __mips==32 && __mips_isa_rev>=2 + /* extract red */ + ext $t4,\src,\shift+11,5 + mul $t4,$t4,\f + + /* extract green */ + ext $t5,\src,\shift+5,6 + mul $t5,$t5,\f + + /* extract blue */ + ext $t6,\src,\shift,5 + mul $t6,$t6,\f +#else + /* extract red */ + srl $t4,\src,\shift+11 + andi $t4, 0x1f + mul $t4,$t4,\f + + /* extract green */ + srl $t5,\src,\shift+5 + andi $t5, 0x3f + mul $t5,$t5,\f + + /* extract blue */ + srl $t6,\src,\shift + andi $t6, 0x1f + mul $t6,$t6,\f +#endif + + srl $t4,$t4,8 + srl $t5,$t5,8 + srl $t6,$t6,8 + addu $t4,$t4,\sR + addu $t5,$t5,\sG + addu \dreg,$t6,\sB + sll $t4,$t4,11 + sll $t5,$t5,5 + or \dreg,\dreg,$t4 + or \dreg,\dreg,$t5 + andi \dreg, 0xffff + .endm + + .text + .align + + .global scanline_col32cb16blend_mips + .ent scanline_col32cb16blend_mips +scanline_col32cb16blend_mips: + + /* check if count is zero */ + srl $v0,$a1,24 /* sA */ + beqz $a2,done + li $t4, 0x100 + srl $v1,$v0,7 + addu $v0,$v1,$v0 + subu $v0,$t4,$v0 /* f */ +#if __mips==32 && __mips_isa_rev>=2 + ext $a3,$a1,3,5 /* sR */ + ext $t0,$a1,10,6 /* sG */ + ext $t1,$a1,19,5 /* sB */ +#else + srl $a3, $a1, 3 + andi $a3, 0x1f /* sR */ + srl $t0, $a1, 10 + andi $t0, 0x3f /* sG */ + srl $t1, $a1, 19 + andi $t1, 0x1f /* sB */ +#endif + + /* check if cnt is at least 4 */ + addiu $a2,$a2,-4 + bltz $a2,tail + +loop_4pixels: + lw $t7,0($a0) + lw $t8,4($a0) + addiu $a0,$a0,8 + addiu $a2,$a2,-4 + pixel $t2 $t7 $v0 $a3 $t0 $t1 0 + pixel $t3 $t7 $v0 $a3 $t0 $t1 16 +#if __mips==32 && __mips_isa_rev>=2 + ins $t2,$t3,16,16 +#else + sll $t3, 16 + or $t2, $t2, $t3 +#endif + pixel $t7 $t8 $v0 $a3 $t0 $t1 0 + pixel $t3 $t8 $v0 $a3 $t0 $t1 16 +#if __mips==32 && __mips_isa_rev>=2 + ins $t7,$t3,16,16 +#else + sll $t3, 16 + or $t7, $t7, $t3 +#endif + sw $t2,-8($a0) + sw $t7,-4($a0) + bgez $a2, loop_4pixels + +tail: + /* the pixel count underran, restore it now */ + addiu $a2,$a2,4 + + /* handle the last 0..3 pixels */ + beqz $a2,done + +loop_1pixel: + lhu $t7,0($a0) + addiu $a0,$a0,2 + addiu $a2,$a2,-1 + pixel $t2 $t7 $v0 $a3 $t0 $t1 0 + sh $t2, -2($a0) + bnez $a2,loop_1pixel + +done: + j $ra + .end scanline_col32cb16blend_mips diff --git a/libpixelflinger/arch-mips/t32cb16blend.S b/libpixelflinger/arch-mips/t32cb16blend.S index c911fbba2..236a2c96e 100644 --- a/libpixelflinger/arch-mips/t32cb16blend.S +++ b/libpixelflinger/arch-mips/t32cb16blend.S @@ -33,232 +33,241 @@ */ #if __mips==32 && __mips_isa_rev>=2 - .macro pixel dreg src fb shift - /* - * sA = s >> 24 - * f = 0x100 - (sA + (sA>>7)) - */ -DBG .set noat -DBG rdhwr $at,$2 -DBG .set at + .macro pixel dreg src fb shift + /* + * sA = s >> 24 + * f = 0x100 - (sA + (sA>>7)) + */ +DBG .set noat +DBG rdhwr $at,$2 +DBG .set at - srl $t7,\src,24 - srl $t6,$t7,7 - addu $t7,$t6 - li $t6,0x100 - subu $t7,$t6,$t7 + srl $t7,\src,24 + srl $t6,$t7,7 + addu $t7,$t6 + li $t6,0x100 + subu $t7,$t6,$t7 - /* red */ - ext $t8,\dreg,\shift+6+5,5 # dst[\shift:15..11] - mul $t6,$t8,$t7 - ext $t0,\dreg,\shift+5,6 # start green extraction dst[\shift:10..5] - ext $t8,\src,3,5 # src[7..3] - srl $t6,8 - addu $t8,$t6 - ins \fb,$t8,\shift+6+5,5 # dst[\shift:15..11] + /* red */ + ext $t8,\dreg,\shift+6+5,5 # dst[\shift:15..11] + mul $t6,$t8,$t7 + ext $t0,\dreg,\shift+5,6 # start green extraction dst[\shift:10..5] + ext $t8,\src,3,5 # src[7..3] + srl $t6,8 + addu $t8,$t6 +.if \shift!=0 + sll $t8,\shift+11 + or \fb,$t8 +.else + sll \fb,$t8,11 +.endif - /* green */ - mul $t8,$t0,$t7 - ext $t0,\dreg,\shift,5 # start blue extraction dst[\shift:4..0] - ext $t6,\src,2+8,6 # src[15..10] - srl $t8,8 - addu $t8,$t6 + /* green */ + mul $t8,$t0,$t7 + ext $t0,\dreg,\shift,5 # start blue extraction dst[\shift:4..0] + ext $t6,\src,2+8,6 # src[15..10] + srl $t8,8 + addu $t8,$t6 - /* blue */ - mul $t0,$t0,$t7 - ins \fb,$t8,\shift+5,6 # finish green insertion dst[\shift:10..5] - ext $t6,\src,(3+8+8),5 - srl $t8,$t0,8 - addu $t8,$t6 - ins \fb,$t8,\shift,5 + /* blue */ + mul $t0,$t0,$t7 + sll $t8, $t8, \shift+5 + or \fb, \fb, $t8 + ext $t6,\src,(3+8+8),5 + srl $t8,$t0,8 + addu $t8,$t6 + sll $t8, $t8, \shift + or \fb, \fb, $t8 -DBG .set noat -DBG rdhwr $t8,$2 -DBG subu $t8,$at -DBG sltu $at,$t8,$v0 -DBG movn $v0,$t8,$at -DBG sgtu $at,$t8,$v1 -DBG movn $v1,$t8,$at -DBG .set at - .endm +DBG .set noat +DBG rdhwr $t8,$2 +DBG subu $t8,$at +DBG sltu $at,$t8,$v0 +DBG movn $v0,$t8,$at +DBG sgtu $at,$t8,$v1 +DBG movn $v1,$t8,$at +DBG .set at + .endm #else - .macro pixel dreg src fb shift - /* - * sA = s >> 24 - * f = 0x100 - (sA + (sA>>7)) - */ -DBG .set push -DBG .set noat -DBG .set mips32r2 -DBG rdhwr $at,$2 -DBG .set pop + .macro pixel dreg src fb shift + /* + * sA = s >> 24 + * f = 0x100 - (sA + (sA>>7)) + */ +DBG .set push +DBG .set noat +DBG .set mips32r2 +DBG rdhwr $at,$2 +DBG .set pop - srl $t7,\src,24 - srl $t6,$t7,7 - addu $t7,$t6 - li $t6,0x100 - subu $t7,$t6,$t7 + srl $t7,\src,24 + srl $t6,$t7,7 + addu $t7,$t6 + li $t6,0x100 + subu $t7,$t6,$t7 - /* - * red - * dR = (d >> (6 + 5)) & 0x1f; - * dR = (f*dR)>>8 - * sR = (s >> ( 3)) & 0x1f; - * sR += dR - * fb |= sR << 11 - */ - srl $t8,\dreg,\shift+6+5 + /* + * red + * dR = (d >> (6 + 5)) & 0x1f; + * dR = (f*dR)>>8 + * sR = (s >> ( 3)) & 0x1f; + * sR += dR + * fb |= sR << 11 + */ + srl $t8,\dreg,\shift+6+5 .if \shift==0 - and $t8,0x1f + and $t8,0x1f .endif - mul $t8,$t8,$t7 - srl $t6,\src,3 - and $t6,0x1f - srl $t8,8 - addu $t8,$t6 + mul $t8,$t8,$t7 + srl $t6,\src,3 + and $t6,0x1f + srl $t8,8 + addu $t8,$t6 .if \shift!=0 - sll $t8,\shift+11 - or \fb,$t8 + sll $t8,\shift+11 + or \fb,$t8 .else - sll \fb,$t8,11 + sll \fb,$t8,11 .endif /* - * green - * dG = (d >> 5) & 0x3f - * dG = (f*dG) >> 8 - * sG = (s >> ( 8+2))&0x3F; - */ - srl $t8,\dreg,\shift+5 - and $t8,0x3f - mul $t8,$t8,$t7 - srl $t6,\src,8+2 - and $t6,0x3f - srl $t8,8 - addu $t8,$t6 - sll $t8,\shift + 5 - or \fb,$t8 + * green + * dG = (d >> 5) & 0x3f + * dG = (f*dG) >> 8 + * sG = (s >> ( 8+2))&0x3F; + */ + srl $t8,\dreg,\shift+5 + and $t8,0x3f + mul $t8,$t8,$t7 + srl $t6,\src,8+2 + and $t6,0x3f + srl $t8,8 + addu $t8,$t6 + sll $t8,\shift + 5 + or \fb,$t8 - /* blue */ + /* blue */ .if \shift!=0 - srl $t8,\dreg,\shift - and $t8,0x1f + srl $t8,\dreg,\shift + and $t8,0x1f .else - and $t8,\dreg,0x1f + and $t8,\dreg,0x1f .endif - mul $t8,$t8,$t7 - srl $t6,\src,(8+8+3) - and $t6,0x1f - srl $t8,8 - addu $t8,$t6 + mul $t8,$t8,$t7 + srl $t6,\src,(8+8+3) + and $t6,0x1f + srl $t8,8 + addu $t8,$t6 .if \shift!=0 - sll $t8,\shift + sll $t8,\shift .endif - or \fb,$t8 -DBG .set push -DBG .set noat -DBG .set mips32r2 -DBG rdhwr $t8,$2 -DBG subu $t8,$at -DBG sltu $at,$t8,$v0 -DBG movn $v0,$t8,$at -DBG sgtu $at,$t8,$v1 -DBG movn $v1,$t8,$at -DBG .set pop - .endm + or \fb,$t8 +DBG .set push +DBG .set noat +DBG .set mips32r2 +DBG rdhwr $t8,$2 +DBG subu $t8,$at +DBG sltu $at,$t8,$v0 +DBG movn $v0,$t8,$at +DBG sgtu $at,$t8,$v1 +DBG movn $v1,$t8,$at +DBG .set pop + .endm #endif - .text - .align + .text + .align - .global scanline_t32cb16blend_mips - .ent scanline_t32cb16blend_mips + .global scanline_t32cb16blend_mips + .ent scanline_t32cb16blend_mips scanline_t32cb16blend_mips: -DBG li $v0,0xffffffff -DBG li $v1,0 - /* Align the destination if necessary */ - and $t0,$a0,3 - beqz $t0,aligned +DBG li $v0,0xffffffff +DBG li $v1,0 + /* Align the destination if necessary */ + and $t0,$a0,3 + beqz $t0,aligned - /* as long as there is at least one pixel */ - beqz $a2,done + /* as long as there is at least one pixel */ + beqz $a2,done - lw $t4,($a1) - addu $a0,2 - addu $a1,4 - beqz $t4,1f - lhu $t3,-2($a0) - pixel $t3,$t4,$t1,0 - sh $t1,-2($a0) -1: subu $a2,1 + lw $t4,($a1) + addu $a0,2 + addu $a1,4 + beqz $t4,1f + lhu $t3,-2($a0) + pixel $t3,$t4,$t1,0 + sh $t1,-2($a0) +1: subu $a2,1 aligned: - /* Check to see if its worth unrolling the loop */ - subu $a2,4 - bltz $a2,tail + /* Check to see if its worth unrolling the loop */ + subu $a2,4 + bltz $a2,tail - /* Process 4 pixels at a time */ + /* Process 4 pixels at a time */ fourpixels: - /* 1st pair of pixels */ - lw $t4,0($a1) - lw $t5,4($a1) - addu $a0,8 - addu $a1,16 + /* 1st pair of pixels */ + lw $t4,0($a1) + lw $t5,4($a1) + addu $a0,8 + addu $a1,16 - /* both are zero, skip this pair */ - or $t3,$t4,$t5 - beqz $t3,1f + /* both are zero, skip this pair */ + or $t3,$t4,$t5 + beqz $t3,1f - /* load the destination */ - lw $t3,-8($a0) + /* load the destination */ + lw $t3,-8($a0) - pixel $t3,$t4,$t1,0 - pixel $t3,$t5,$t1,16 - sw $t1,-8($a0) + pixel $t3,$t4,$t1,0 + andi $t1, 0xFFFF + pixel $t3,$t5,$t1,16 + sw $t1,-8($a0) 1: - /* 2nd pair of pixels */ - lw $t4,-8($a1) - lw $t5,-4($a1) + /* 2nd pair of pixels */ + lw $t4,-8($a1) + lw $t5,-4($a1) - /* both are zero, skip this pair */ - or $t3,$t4,$t5 - beqz $t3,1f + /* both are zero, skip this pair */ + or $t3,$t4,$t5 + beqz $t3,1f - /* load the destination */ - lw $t3,-4($a0) + /* load the destination */ + lw $t3,-4($a0) - pixel $t3,$t4,$t1,0 - pixel $t3,$t5,$t1,16 - sw $t1,-4($a0) + pixel $t3,$t4,$t1,0 + andi $t1, 0xFFFF + pixel $t3,$t5,$t1,16 + sw $t1,-4($a0) -1: subu $a2,4 - bgtz $a2,fourpixels +1: subu $a2,4 + bgtz $a2,fourpixels tail: - /* the pixel count underran, restore it now */ - addu $a2,4 + /* the pixel count underran, restore it now */ + addu $a2,4 - /* handle the last 0..3 pixels */ - beqz $a2,done + /* handle the last 0..3 pixels */ + beqz $a2,done onepixel: - lw $t4,($a1) - addu $a0,2 - addu $a1,4 - beqz $t4,1f - lhu $t3,-2($a0) - pixel $t3,$t4,$t1,0 - sh $t1,-2($a0) -1: subu $a2,1 - bnez $a2,onepixel + lw $t4,($a1) + addu $a0,2 + addu $a1,4 + beqz $t4,1f + lhu $t3,-2($a0) + pixel $t3,$t4,$t1,0 + sh $t1,-2($a0) +1: subu $a2,1 + bnez $a2,onepixel done: -DBG .set push -DBG .set mips32r2 -DBG rdhwr $a0,$3 -DBG mul $v0,$a0 -DBG mul $v1,$a0 -DBG .set pop - j $ra - .end scanline_t32cb16blend_mips +DBG .set push +DBG .set mips32r2 +DBG rdhwr $a0,$3 +DBG mul $v0,$a0 +DBG mul $v1,$a0 +DBG .set pop + j $ra + .end scanline_t32cb16blend_mips diff --git a/libpixelflinger/arch-mips64/col32cb16blend.S b/libpixelflinger/arch-mips64/col32cb16blend.S new file mode 100644 index 000000000..fea44911d --- /dev/null +++ b/libpixelflinger/arch-mips64/col32cb16blend.S @@ -0,0 +1,108 @@ +/* +** Copyright 2015, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + + .macro pixel dreg src f sR sG sB shift + + /* extract red */ +.if \shift < 32 + dext $t0,\src,\shift+11,5 +.else + dextu $t0,\src,\shift+11,5 +.endif + mul $t0,$t0,\f + + /* extract green */ +.if \shift < 32 + dext $t1,\src,\shift+5,6 +.else + dextu $t1,\src,\shift+5,6 +.endif + mul $t1,$t1,\f + + /* extract blue */ +.if \shift < 32 + dext $t2,\src,\shift,5 +.else + dextu $t2,\src,\shift,5 +.endif + mul $t2,$t2,\f + + srl $t0,$t0,8 + srl $t1,$t1,8 + srl $t2,$t2,8 + addu $t0,$t0,\sR + addu $t1,$t1,\sG + addu \dreg,$t2,\sB + sll $t0,$t0,11 + sll $t1,$t1,5 + or \dreg,\dreg,$t0 + or \dreg,\dreg,$t1 + .endm + + .text + .align + + .global scanline_col32cb16blend_mips64 + .ent scanline_col32cb16blend_mips64 +scanline_col32cb16blend_mips64: + + /* check if count is zero */ + srl $v0,$a1,24 /* sA */ + beqz $a2,done + li $t0, 0x100 + srl $v1,$v0,7 + addu $v0,$v1,$v0 + subu $v0,$t0,$v0 /* f */ + ext $a3,$a1,3,5 /* sR */ + ext $a4,$a1,10,6 /* sG */ + ext $a5,$a1,19,5 /* sB */ + + /* check if cnt is at least 4 */ + addiu $a2,$a2,-4 + bltz $a2,tail + +loop_4pixels: + ld $t3,0($a0) + daddiu $a0,$a0,8 + addiu $a2,$a2,-4 + pixel $a6 $t3 $v0 $a3 $a4 $a5 0 + pixel $a7 $t3 $v0 $a3 $a4 $a5 16 + pixel $t8 $t3 $v0 $a3 $a4 $a5 32 + pixel $t9 $t3 $v0 $a3 $a4 $a5 48 + dins $a6,$a7,16,16 + dinsu $a6,$t8,32,16 + dinsu $a6,$t9,48,16 + sd $a6,-8($a0) + bgez $a2, loop_4pixels + +tail: + /* the pixel count underran, restore it now */ + addiu $a2,$a2,4 + + /* handle the last 0..3 pixels */ + beqz $a2,done + +loop_1pixel: + lhu $t3,0($a0) + daddiu $a0,$a0,2 + addiu $a2,$a2,-1 + pixel $a6 $t3 $v0 $a3 $a4 $a5 0 + sh $a6, -2($a0) + bnez $a2,loop_1pixel + +done: + j $ra + .end scanline_col32cb16blend_mips64 diff --git a/libpixelflinger/arch-mips64/t32cb16blend.S b/libpixelflinger/arch-mips64/t32cb16blend.S new file mode 100644 index 000000000..d2f4d4905 --- /dev/null +++ b/libpixelflinger/arch-mips64/t32cb16blend.S @@ -0,0 +1,172 @@ +/* +** Copyright 2015, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + +#ifdef DEBUG +#define DBG +#else +#define DBG # +#endif + +/* + * blend one of 2 16bpp RGB pixels held in dreg selected by shift + * with the 32bpp ABGR pixel held in src and store the result in fb + * + * Assumes that the dreg data is little endian and that + * the the second pixel (shift==16) will be merged into + * the fb result + * + * Uses $a4,$t2,$t3,$t8 + */ + + .macro pixel dreg src fb shift + /* + * sA = s >> 24 + * f = 0x100 - (sA + (sA>>7)) + */ + srl $t3,\src,24 + srl $t2,$t3,7 + addu $t3,$t2 + li $t2,0x100 + subu $t3,$t2,$t3 + + /* red */ + ext $t8,\dreg,\shift+6+5,5 # dst[\shift:15..11] + mul $t2,$t8,$t3 + ext $a4,\dreg,\shift+5,6 # start green extraction dst[\shift:10..5] + ext $t8,\src,3,5 # src[7..3] + srl $t2,8 + addu $t8,$t2 +.if \shift!=0 + sll $t8,\shift+11 # dst[\shift:15..11] + or \fb,$t8 +.else + sll \fb,$t8,11 +.endif + + /* green */ + mul $t8,$a4,$t3 + ext $a4,\dreg,\shift,5 # start blue extraction dst[\shift:4..0] + ext $t2,\src,2+8,6 # src[15..10] + srl $t8,8 + addu $t8,$t2 + + /* blue */ + mul $a4,$a4,$t3 + sll $t8, $t8, \shift+5 # finish green insertion dst[\shift:10..5] + or \fb, \fb, $t8 + ext $t2,\src,(3+8+8),5 + srl $t8,$a4,8 + addu $t8,$t2 + sll $t8, $t8, \shift + or \fb, \fb, $t8 + .endm + + .text + .align + + .global scanline_t32cb16blend_mips64 + .ent scanline_t32cb16blend_mips64 +scanline_t32cb16blend_mips64: + daddiu $sp, $sp, -40 +DBG li $v0,0xffffffff +DBG li $v1,0 + /* Align the destination if necessary */ + and $a4,$a0,3 + beqz $a4,aligned + + /* as long as there is at least one pixel */ + beqz $a2,done + + lw $t0,($a1) + daddu $a0,2 + daddu $a1,4 + beqz $t0,1f + lhu $a7,-2($a0) + pixel $a7,$t0,$a5,0 + sh $a5,-2($a0) +1: subu $a2,1 + +aligned: + /* Check to see if its worth unrolling the loop */ + subu $a2,4 + bltz $a2,tail + + /* Process 4 pixels at a time */ +fourpixels: + /* 1st pair of pixels */ + lw $t0,0($a1) + lw $t1,4($a1) + daddu $a0,8 + daddu $a1,16 + + /* both are zero, skip this pair */ + or $a7,$t0,$t1 + beqz $a7,1f + + /* load the destination */ + lw $a7,-8($a0) + + pixel $a7,$t0,$a5,0 + andi $a5, 0xFFFF + pixel $a7,$t1,$a5,16 + sw $a5,-8($a0) + +1: + /* 2nd pair of pixels */ + lw $t0,-8($a1) + lw $t1,-4($a1) + + /* both are zero, skip this pair */ + or $a7,$t0,$t1 + beqz $a7,1f + + /* load the destination */ + lw $a7,-4($a0) + + pixel $a7,$t0,$a5,0 + andi $a5, 0xFFFF + pixel $a7,$t1,$a5,16 + sw $a5,-4($a0) + +1: subu $a2,4 + bgtz $a2,fourpixels + +tail: + /* the pixel count underran, restore it now */ + addu $a2,4 + + /* handle the last 0..3 pixels */ + beqz $a2,done +onepixel: + lw $t0,($a1) + daddu $a0,2 + daddu $a1,4 + beqz $t0,1f + lhu $a7,-2($a0) + pixel $a7,$t0,$a5,0 + sh $a5,-2($a0) +1: subu $a2,1 + bnez $a2,onepixel +done: +DBG .set push +DBG .set mips32r2 +DBG rdhwr $a0,$3 +DBG mul $v0,$a0 +DBG mul $v1,$a0 +DBG .set pop + daddiu $sp, $sp, 40 + j $ra + .end scanline_t32cb16blend_mips64 diff --git a/libpixelflinger/codeflinger/ARMAssemblerInterface.h b/libpixelflinger/codeflinger/ARMAssemblerInterface.h index 40cbfcfb9..72935acd2 100644 --- a/libpixelflinger/codeflinger/ARMAssemblerInterface.h +++ b/libpixelflinger/codeflinger/ARMAssemblerInterface.h @@ -63,7 +63,7 @@ public: }; enum { - CODEGEN_ARCH_ARM = 1, CODEGEN_ARCH_MIPS, CODEGEN_ARCH_ARM64 + CODEGEN_ARCH_ARM = 1, CODEGEN_ARCH_MIPS, CODEGEN_ARCH_ARM64, CODEGEN_ARCH_MIPS64 }; // ----------------------------------------------------------------------- @@ -115,7 +115,8 @@ public: // data processing... enum { opAND, opEOR, opSUB, opRSB, opADD, opADC, opSBC, opRSC, - opTST, opTEQ, opCMP, opCMN, opORR, opMOV, opBIC, opMVN + opTST, opTEQ, opCMP, opCMN, opORR, opMOV, opBIC, opMVN, + opADD64, opSUB64 }; virtual void diff --git a/libpixelflinger/codeflinger/GGLAssembler.cpp b/libpixelflinger/codeflinger/GGLAssembler.cpp index 325caba8a..346779f47 100644 --- a/libpixelflinger/codeflinger/GGLAssembler.cpp +++ b/libpixelflinger/codeflinger/GGLAssembler.cpp @@ -893,7 +893,8 @@ void GGLAssembler::build_and_immediate(int d, int s, uint32_t mask, int bits) return; } - if (getCodegenArch() == CODEGEN_ARCH_MIPS) { + if ((getCodegenArch() == CODEGEN_ARCH_MIPS) || + (getCodegenArch() == CODEGEN_ARCH_MIPS64)) { // MIPS can do 16-bit imm in 1 instr, 32-bit in 3 instr // the below ' while (mask)' code is buggy on mips // since mips returns true on isValidImmediate() @@ -1057,7 +1058,8 @@ RegisterAllocator::RegisterFile& RegisterAllocator::registerFile() RegisterAllocator::RegisterFile::RegisterFile(int codegen_arch) : mRegs(0), mTouched(0), mStatus(0), mArch(codegen_arch), mRegisterOffset(0) { - if (mArch == ARMAssemblerInterface::CODEGEN_ARCH_MIPS) { + if ((mArch == ARMAssemblerInterface::CODEGEN_ARCH_MIPS) || + (mArch == ARMAssemblerInterface::CODEGEN_ARCH_MIPS64)) { mRegisterOffset = 2; // ARM has regs 0..15, MIPS offset to 2..17 } reserve(ARMAssemblerInterface::SP); @@ -1067,7 +1069,8 @@ RegisterAllocator::RegisterFile::RegisterFile(int codegen_arch) RegisterAllocator::RegisterFile::RegisterFile(const RegisterFile& rhs, int codegen_arch) : mRegs(rhs.mRegs), mTouched(rhs.mTouched), mArch(codegen_arch), mRegisterOffset(0) { - if (mArch == ARMAssemblerInterface::CODEGEN_ARCH_MIPS) { + if ((mArch == ARMAssemblerInterface::CODEGEN_ARCH_MIPS) || + (mArch == ARMAssemblerInterface::CODEGEN_ARCH_MIPS64)) { mRegisterOffset = 2; // ARM has regs 0..15, MIPS offset to 2..17 } } diff --git a/libpixelflinger/codeflinger/MIPS64Assembler.cpp b/libpixelflinger/codeflinger/MIPS64Assembler.cpp new file mode 100644 index 000000000..a5305cca2 --- /dev/null +++ b/libpixelflinger/codeflinger/MIPS64Assembler.cpp @@ -0,0 +1,1452 @@ +/* libs/pixelflinger/codeflinger/MIPS64Assembler.cpp +** +** Copyright 2015, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + + +/* MIPS64 assembler and ARM->MIPS64 assembly translator +** +** The approach is utilize MIPSAssembler generator, using inherited MIPS64Assembler +** that overrides just the specific MIPS64r6 instructions. +** For now ArmToMips64Assembler is copied over from ArmToMipsAssembler class, +** changing some MIPS64r6 related stuff. +** +*/ + + +#define LOG_TAG "MIPS64Assembler" + +#include +#include +#include +#include + +#if defined(WITH_LIB_HARDWARE) +#include +#endif + +#include + +#include "MIPS64Assembler.h" +#include "CodeCache.h" +#include "mips64_disassem.h" + + +#define NOT_IMPLEMENTED() LOG_ALWAYS_FATAL("Arm instruction %s not yet implemented\n", __func__) + + +// ---------------------------------------------------------------------------- + +namespace android { + +// ---------------------------------------------------------------------------- +#if 0 +#pragma mark - +#pragma mark ArmToMips64Assembler... +#endif + +ArmToMips64Assembler::ArmToMips64Assembler(const sp& assembly, + char *abuf, int linesz, int instr_count) + : ARMAssemblerInterface(), + mArmDisassemblyBuffer(abuf), + mArmLineLength(linesz), + mArmInstrCount(instr_count), + mInum(0), + mAssembly(assembly) +{ + mMips = new MIPS64Assembler(assembly, this); + mArmPC = (uint32_t **) malloc(ARM_MAX_INSTUCTIONS * sizeof(uint32_t *)); + init_conditional_labels(); +} + +ArmToMips64Assembler::ArmToMips64Assembler(void* assembly) + : ARMAssemblerInterface(), + mArmDisassemblyBuffer(NULL), + mInum(0), + mAssembly(NULL) +{ + mMips = new MIPS64Assembler(assembly, this); + mArmPC = (uint32_t **) malloc(ARM_MAX_INSTUCTIONS * sizeof(uint32_t *)); + init_conditional_labels(); +} + +ArmToMips64Assembler::~ArmToMips64Assembler() +{ + delete mMips; + free((void *) mArmPC); +} + +uint32_t* ArmToMips64Assembler::pc() const +{ + return mMips->pc(); +} + +uint32_t* ArmToMips64Assembler::base() const +{ + return mMips->base(); +} + +void ArmToMips64Assembler::reset() +{ + cond.labelnum = 0; + mInum = 0; + mMips->reset(); +} + +int ArmToMips64Assembler::getCodegenArch() +{ + return CODEGEN_ARCH_MIPS64; +} + +void ArmToMips64Assembler::comment(const char* string) +{ + mMips->comment(string); +} + +void ArmToMips64Assembler::label(const char* theLabel) +{ + mMips->label(theLabel); +} + +void ArmToMips64Assembler::disassemble(const char* name) +{ + mMips->disassemble(name); +} + +void ArmToMips64Assembler::init_conditional_labels() +{ + int i; + for (i=0;i<99; ++i) { + sprintf(cond.label[i], "cond_%d", i); + } +} + + + +#if 0 +#pragma mark - +#pragma mark Prolog/Epilog & Generate... +#endif + +void ArmToMips64Assembler::prolog() +{ + mArmPC[mInum++] = pc(); // save starting PC for this instr + + mMips->DADDIU(R_sp, R_sp, -(5 * 8)); + mMips->SD(R_s0, R_sp, 0); + mMips->SD(R_s1, R_sp, 8); + mMips->SD(R_s2, R_sp, 16); + mMips->SD(R_s3, R_sp, 24); + mMips->SD(R_s4, R_sp, 32); + mMips->MOVE(R_v0, R_a0); // move context * passed in a0 to v0 (arm r0) +} + +void ArmToMips64Assembler::epilog(uint32_t touched) +{ + mArmPC[mInum++] = pc(); // save starting PC for this instr + + mMips->LD(R_s0, R_sp, 0); + mMips->LD(R_s1, R_sp, 8); + mMips->LD(R_s2, R_sp, 16); + mMips->LD(R_s3, R_sp, 24); + mMips->LD(R_s4, R_sp, 32); + mMips->DADDIU(R_sp, R_sp, (5 * 8)); + mMips->JR(R_ra); + +} + +int ArmToMips64Assembler::generate(const char* name) +{ + return mMips->generate(name); +} + +void ArmToMips64Assembler::fix_branches() +{ + mMips->fix_branches(); +} + +uint32_t* ArmToMips64Assembler::pcForLabel(const char* label) +{ + return mMips->pcForLabel(label); +} + +void ArmToMips64Assembler::set_condition(int mode, int R1, int R2) { + if (mode == 2) { + cond.type = SBIT_COND; + } else { + cond.type = CMP_COND; + } + cond.r1 = R1; + cond.r2 = R2; +} + +//---------------------------------------------------------- + +#if 0 +#pragma mark - +#pragma mark Addressing modes & shifters... +#endif + + +// do not need this for MIPS, but it is in the Interface (virtual) +int ArmToMips64Assembler::buildImmediate( + uint32_t immediate, uint32_t& rot, uint32_t& imm) +{ + // for MIPS, any 32-bit immediate is OK + rot = 0; + imm = immediate; + return 0; +} + +// shifters... + +bool ArmToMips64Assembler::isValidImmediate(uint32_t immediate) +{ + // for MIPS, any 32-bit immediate is OK + return true; +} + +uint32_t ArmToMips64Assembler::imm(uint32_t immediate) +{ + amode.value = immediate; + return AMODE_IMM; +} + +uint32_t ArmToMips64Assembler::reg_imm(int Rm, int type, uint32_t shift) +{ + amode.reg = Rm; + amode.stype = type; + amode.value = shift; + return AMODE_REG_IMM; +} + +uint32_t ArmToMips64Assembler::reg_rrx(int Rm) +{ + // reg_rrx mode is not used in the GLLAssember code at this time + return AMODE_UNSUPPORTED; +} + +uint32_t ArmToMips64Assembler::reg_reg(int Rm, int type, int Rs) +{ + // reg_reg mode is not used in the GLLAssember code at this time + return AMODE_UNSUPPORTED; +} + + +// addressing modes... +// LDR(B)/STR(B)/PLD (immediate and Rm can be negative, which indicate U=0) +uint32_t ArmToMips64Assembler::immed12_pre(int32_t immed12, int W) +{ + LOG_ALWAYS_FATAL_IF(abs(immed12) >= 0x800, + "LDR(B)/STR(B)/PLD immediate too big (%08x)", + immed12); + amode.value = immed12; + amode.writeback = W; + return AMODE_IMM_12_PRE; +} + +uint32_t ArmToMips64Assembler::immed12_post(int32_t immed12) +{ + LOG_ALWAYS_FATAL_IF(abs(immed12) >= 0x800, + "LDR(B)/STR(B)/PLD immediate too big (%08x)", + immed12); + + amode.value = immed12; + return AMODE_IMM_12_POST; +} + +uint32_t ArmToMips64Assembler::reg_scale_pre(int Rm, int type, + uint32_t shift, int W) +{ + LOG_ALWAYS_FATAL_IF(W | type | shift, "reg_scale_pre adv modes not yet implemented"); + + amode.reg = Rm; + // amode.stype = type; // more advanced modes not used in GGLAssembler yet + // amode.value = shift; + // amode.writeback = W; + return AMODE_REG_SCALE_PRE; +} + +uint32_t ArmToMips64Assembler::reg_scale_post(int Rm, int type, uint32_t shift) +{ + LOG_ALWAYS_FATAL("adr mode reg_scale_post not yet implemented\n"); + return AMODE_UNSUPPORTED; +} + +// LDRH/LDRSB/LDRSH/STRH (immediate and Rm can be negative, which indicate U=0) +uint32_t ArmToMips64Assembler::immed8_pre(int32_t immed8, int W) +{ + LOG_ALWAYS_FATAL("adr mode immed8_pre not yet implemented\n"); + + LOG_ALWAYS_FATAL_IF(abs(immed8) >= 0x100, + "LDRH/LDRSB/LDRSH/STRH immediate too big (%08x)", + immed8); + return AMODE_IMM_8_PRE; +} + +uint32_t ArmToMips64Assembler::immed8_post(int32_t immed8) +{ + LOG_ALWAYS_FATAL_IF(abs(immed8) >= 0x100, + "LDRH/LDRSB/LDRSH/STRH immediate too big (%08x)", + immed8); + amode.value = immed8; + return AMODE_IMM_8_POST; +} + +uint32_t ArmToMips64Assembler::reg_pre(int Rm, int W) +{ + LOG_ALWAYS_FATAL_IF(W, "reg_pre writeback not yet implemented"); + amode.reg = Rm; + return AMODE_REG_PRE; +} + +uint32_t ArmToMips64Assembler::reg_post(int Rm) +{ + LOG_ALWAYS_FATAL("adr mode reg_post not yet implemented\n"); + return AMODE_UNSUPPORTED; +} + + + +// ---------------------------------------------------------------------------- + +#if 0 +#pragma mark - +#pragma mark Data Processing... +#endif + + +static const char * const dpOpNames[] = { + "AND", "EOR", "SUB", "RSB", "ADD", "ADC", "SBC", "RSC", + "TST", "TEQ", "CMP", "CMN", "ORR", "MOV", "BIC", "MVN" +}; + +// check if the operand registers from a previous CMP or S-bit instruction +// would be overwritten by this instruction. If so, move the value to a +// safe register. +// Note that we cannot tell at _this_ instruction time if a future (conditional) +// instruction will _also_ use this value (a defect of the simple 1-pass, one- +// instruction-at-a-time translation). Therefore we must be conservative and +// save the value before it is overwritten. This costs an extra MOVE instr. + +void ArmToMips64Assembler::protectConditionalOperands(int Rd) +{ + if (Rd == cond.r1) { + mMips->MOVE(R_cmp, cond.r1); + cond.r1 = R_cmp; + } + if (cond.type == CMP_COND && Rd == cond.r2) { + mMips->MOVE(R_cmp2, cond.r2); + cond.r2 = R_cmp2; + } +} + + +// interprets the addressing mode, and generates the common code +// used by the majority of data-processing ops. Many MIPS instructions +// have a register-based form and a different immediate form. See +// opAND below for an example. (this could be inlined) +// +// this works with the imm(), reg_imm() methods above, which are directly +// called by the GLLAssembler. +// note: _signed parameter defaults to false (un-signed) +// note: tmpReg parameter defaults to 1, MIPS register AT +int ArmToMips64Assembler::dataProcAdrModes(int op, int& source, bool _signed, int tmpReg) +{ + if (op < AMODE_REG) { + source = op; + return SRC_REG; + } else if (op == AMODE_IMM) { + if ((!_signed && amode.value > 0xffff) + || (_signed && ((int)amode.value < -32768 || (int)amode.value > 32767) )) { + mMips->LUI(tmpReg, (amode.value >> 16)); + if (amode.value & 0x0000ffff) { + mMips->ORI(tmpReg, tmpReg, (amode.value & 0x0000ffff)); + } + source = tmpReg; + return SRC_REG; + } else { + source = amode.value; + return SRC_IMM; + } + } else if (op == AMODE_REG_IMM) { + switch (amode.stype) { + case LSL: mMips->SLL(tmpReg, amode.reg, amode.value); break; + case LSR: mMips->SRL(tmpReg, amode.reg, amode.value); break; + case ASR: mMips->SRA(tmpReg, amode.reg, amode.value); break; + case ROR: mMips->ROTR(tmpReg, amode.reg, amode.value); break; + } + source = tmpReg; + return SRC_REG; + } else { // adr mode RRX is not used in GGL Assembler at this time + // we are screwed, this should be exception, assert-fail or something + LOG_ALWAYS_FATAL("adr mode reg_rrx not yet implemented\n"); + return SRC_ERROR; + } +} + + +void ArmToMips64Assembler::dataProcessing(int opcode, int cc, + int s, int Rd, int Rn, uint32_t Op2) +{ + int src; // src is modified by dataProcAdrModes() - passed as int& + + if (cc != AL) { + protectConditionalOperands(Rd); + // the branch tests register(s) set by prev CMP or instr with 'S' bit set + // inverse the condition to jump past this conditional instruction + ArmToMips64Assembler::B(cc^1, cond.label[++cond.labelnum]); + } else { + mArmPC[mInum++] = pc(); // save starting PC for this instr + } + + switch (opcode) { + case opAND: + if (dataProcAdrModes(Op2, src) == SRC_REG) { + mMips->AND(Rd, Rn, src); + } else { // adr mode was SRC_IMM + mMips->ANDI(Rd, Rn, src); + } + break; + + case opADD: + // set "signed" to true for adr modes + if (dataProcAdrModes(Op2, src, true) == SRC_REG) { + mMips->ADDU(Rd, Rn, src); + } else { // adr mode was SRC_IMM + mMips->ADDIU(Rd, Rn, src); + } + break; + + case opSUB: + // set "signed" to true for adr modes + if (dataProcAdrModes(Op2, src, true) == SRC_REG) { + mMips->SUBU(Rd, Rn, src); + } else { // adr mode was SRC_IMM + mMips->SUBIU(Rd, Rn, src); + } + break; + + case opADD64: + // set "signed" to true for adr modes + if (dataProcAdrModes(Op2, src, true) == SRC_REG) { + mMips->DADDU(Rd, Rn, src); + } else { // adr mode was SRC_IMM + mMips->DADDIU(Rd, Rn, src); + } + break; + + case opSUB64: + // set "signed" to true for adr modes + if (dataProcAdrModes(Op2, src, true) == SRC_REG) { + mMips->DSUBU(Rd, Rn, src); + } else { // adr mode was SRC_IMM + mMips->DSUBIU(Rd, Rn, src); + } + break; + + case opEOR: + if (dataProcAdrModes(Op2, src) == SRC_REG) { + mMips->XOR(Rd, Rn, src); + } else { // adr mode was SRC_IMM + mMips->XORI(Rd, Rn, src); + } + break; + + case opORR: + if (dataProcAdrModes(Op2, src) == SRC_REG) { + mMips->OR(Rd, Rn, src); + } else { // adr mode was SRC_IMM + mMips->ORI(Rd, Rn, src); + } + break; + + case opBIC: + if (dataProcAdrModes(Op2, src) == SRC_IMM) { + // if we are 16-bit imnmediate, load to AT reg + mMips->ORI(R_at, 0, src); + src = R_at; + } + mMips->NOT(R_at, src); + mMips->AND(Rd, Rn, R_at); + break; + + case opRSB: + if (dataProcAdrModes(Op2, src) == SRC_IMM) { + // if we are 16-bit imnmediate, load to AT reg + mMips->ORI(R_at, 0, src); + src = R_at; + } + mMips->SUBU(Rd, src, Rn); // subu with the parameters reversed + break; + + case opMOV: + if (Op2 < AMODE_REG) { // op2 is reg # in this case + mMips->MOVE(Rd, Op2); + } else if (Op2 == AMODE_IMM) { + if (amode.value > 0xffff) { + mMips->LUI(Rd, (amode.value >> 16)); + if (amode.value & 0x0000ffff) { + mMips->ORI(Rd, Rd, (amode.value & 0x0000ffff)); + } + } else { + mMips->ORI(Rd, 0, amode.value); + } + } else if (Op2 == AMODE_REG_IMM) { + switch (amode.stype) { + case LSL: mMips->SLL(Rd, amode.reg, amode.value); break; + case LSR: mMips->SRL(Rd, amode.reg, amode.value); break; + case ASR: mMips->SRA(Rd, amode.reg, amode.value); break; + case ROR: mMips->ROTR(Rd, amode.reg, amode.value); break; + } + } + else { + // adr mode RRX is not used in GGL Assembler at this time + mMips->UNIMPL(); + } + break; + + case opMVN: // this is a 1's complement: NOT + if (Op2 < AMODE_REG) { // op2 is reg # in this case + mMips->NOR(Rd, Op2, 0); // NOT is NOR with 0 + break; + } else if (Op2 == AMODE_IMM) { + if (amode.value > 0xffff) { + mMips->LUI(Rd, (amode.value >> 16)); + if (amode.value & 0x0000ffff) { + mMips->ORI(Rd, Rd, (amode.value & 0x0000ffff)); + } + } else { + mMips->ORI(Rd, 0, amode.value); + } + } else if (Op2 == AMODE_REG_IMM) { + switch (amode.stype) { + case LSL: mMips->SLL(Rd, amode.reg, amode.value); break; + case LSR: mMips->SRL(Rd, amode.reg, amode.value); break; + case ASR: mMips->SRA(Rd, amode.reg, amode.value); break; + case ROR: mMips->ROTR(Rd, amode.reg, amode.value); break; + } + } + else { + // adr mode RRX is not used in GGL Assembler at this time + mMips->UNIMPL(); + } + mMips->NOR(Rd, Rd, 0); // NOT is NOR with 0 + break; + + case opCMP: + // Either operand of a CMP instr could get overwritten by a subsequent + // conditional instruction, which is ok, _UNLESS_ there is a _second_ + // conditional instruction. Under MIPS, this requires doing the comparison + // again (SLT), and the original operands must be available. (and this + // pattern of multiple conditional instructions from same CMP _is_ used + // in GGL-Assembler) + // + // For now, if a conditional instr overwrites the operands, we will + // move them to dedicated temp regs. This is ugly, and inefficient, + // and should be optimized. + // + // WARNING: making an _Assumption_ that CMP operand regs will NOT be + // trashed by intervening NON-conditional instructions. In the general + // case this is legal, but it is NOT currently done in GGL-Assembler. + + cond.type = CMP_COND; + cond.r1 = Rn; + if (dataProcAdrModes(Op2, src, false, R_cmp2) == SRC_REG) { + cond.r2 = src; + } else { // adr mode was SRC_IMM + mMips->ORI(R_cmp2, R_zero, src); + cond.r2 = R_cmp2; + } + + break; + + + case opTST: + case opTEQ: + case opCMN: + case opADC: + case opSBC: + case opRSC: + mMips->UNIMPL(); // currently unused in GGL Assembler code + break; + } + + if (cc != AL) { + mMips->label(cond.label[cond.labelnum]); + } + if (s && opcode != opCMP) { + cond.type = SBIT_COND; + cond.r1 = Rd; + } +} + + + +#if 0 +#pragma mark - +#pragma mark Multiply... +#endif + +// multiply, accumulate +void ArmToMips64Assembler::MLA(int cc, int s, + int Rd, int Rm, int Rs, int Rn) { + + //ALOGW("MLA"); + mArmPC[mInum++] = pc(); // save starting PC for this instr + + mMips->MUL(R_at, Rm, Rs); + mMips->ADDU(Rd, R_at, Rn); + if (s) { + cond.type = SBIT_COND; + cond.r1 = Rd; + } +} + +void ArmToMips64Assembler::MUL(int cc, int s, + int Rd, int Rm, int Rs) { + mArmPC[mInum++] = pc(); + mMips->MUL(Rd, Rm, Rs); + if (s) { + cond.type = SBIT_COND; + cond.r1 = Rd; + } +} + +void ArmToMips64Assembler::UMULL(int cc, int s, + int RdLo, int RdHi, int Rm, int Rs) { + mArmPC[mInum++] = pc(); + mMips->MUH(RdHi, Rm, Rs); + mMips->MUL(RdLo, Rm, Rs); + + if (s) { + cond.type = SBIT_COND; + cond.r1 = RdHi; // BUG... + LOG_ALWAYS_FATAL("Condition on UMULL must be on 64-bit result\n"); + } +} + +void ArmToMips64Assembler::UMUAL(int cc, int s, + int RdLo, int RdHi, int Rm, int Rs) { + LOG_FATAL_IF(RdLo==Rm || RdHi==Rm || RdLo==RdHi, + "UMUAL(r%u,r%u,r%u,r%u)", RdLo,RdHi,Rm,Rs); + // *mPC++ = (cc<<28) | (1<<23) | (1<<21) | (s<<20) | + // (RdHi<<16) | (RdLo<<12) | (Rs<<8) | 0x90 | Rm; + mArmPC[mInum++] = pc(); + mMips->NOP2(); + NOT_IMPLEMENTED(); + if (s) { + cond.type = SBIT_COND; + cond.r1 = RdHi; // BUG... + LOG_ALWAYS_FATAL("Condition on UMULL must be on 64-bit result\n"); + } +} + +void ArmToMips64Assembler::SMULL(int cc, int s, + int RdLo, int RdHi, int Rm, int Rs) { + LOG_FATAL_IF(RdLo==Rm || RdHi==Rm || RdLo==RdHi, + "SMULL(r%u,r%u,r%u,r%u)", RdLo,RdHi,Rm,Rs); + // *mPC++ = (cc<<28) | (1<<23) | (1<<22) | (s<<20) | + // (RdHi<<16) | (RdLo<<12) | (Rs<<8) | 0x90 | Rm; + mArmPC[mInum++] = pc(); + mMips->NOP2(); + NOT_IMPLEMENTED(); + if (s) { + cond.type = SBIT_COND; + cond.r1 = RdHi; // BUG... + LOG_ALWAYS_FATAL("Condition on SMULL must be on 64-bit result\n"); + } +} +void ArmToMips64Assembler::SMUAL(int cc, int s, + int RdLo, int RdHi, int Rm, int Rs) { + LOG_FATAL_IF(RdLo==Rm || RdHi==Rm || RdLo==RdHi, + "SMUAL(r%u,r%u,r%u,r%u)", RdLo,RdHi,Rm,Rs); + // *mPC++ = (cc<<28) | (1<<23) | (1<<22) | (1<<21) | (s<<20) | + // (RdHi<<16) | (RdLo<<12) | (Rs<<8) | 0x90 | Rm; + mArmPC[mInum++] = pc(); + mMips->NOP2(); + NOT_IMPLEMENTED(); + if (s) { + cond.type = SBIT_COND; + cond.r1 = RdHi; // BUG... + LOG_ALWAYS_FATAL("Condition on SMUAL must be on 64-bit result\n"); + } +} + + + +#if 0 +#pragma mark - +#pragma mark Branches... +#endif + +// branches... + +void ArmToMips64Assembler::B(int cc, const char* label) +{ + mArmPC[mInum++] = pc(); + if (cond.type == SBIT_COND) { cond.r2 = R_zero; } + + switch(cc) { + case EQ: mMips->BEQ(cond.r1, cond.r2, label); break; + case NE: mMips->BNE(cond.r1, cond.r2, label); break; + case HS: mMips->BGEU(cond.r1, cond.r2, label); break; + case LO: mMips->BLTU(cond.r1, cond.r2, label); break; + case MI: mMips->BLT(cond.r1, cond.r2, label); break; + case PL: mMips->BGE(cond.r1, cond.r2, label); break; + + case HI: mMips->BGTU(cond.r1, cond.r2, label); break; + case LS: mMips->BLEU(cond.r1, cond.r2, label); break; + case GE: mMips->BGE(cond.r1, cond.r2, label); break; + case LT: mMips->BLT(cond.r1, cond.r2, label); break; + case GT: mMips->BGT(cond.r1, cond.r2, label); break; + case LE: mMips->BLE(cond.r1, cond.r2, label); break; + case AL: mMips->B(label); break; + case NV: /* B Never - no instruction */ break; + + case VS: + case VC: + default: + LOG_ALWAYS_FATAL("Unsupported cc: %02x\n", cc); + break; + } +} + +void ArmToMips64Assembler::BL(int cc, const char* label) +{ + LOG_ALWAYS_FATAL("branch-and-link not supported yet\n"); + mArmPC[mInum++] = pc(); +} + +// no use for Branches with integer PC, but they're in the Interface class .... +void ArmToMips64Assembler::B(int cc, uint32_t* to_pc) +{ + LOG_ALWAYS_FATAL("branch to absolute PC not supported, use Label\n"); + mArmPC[mInum++] = pc(); +} + +void ArmToMips64Assembler::BL(int cc, uint32_t* to_pc) +{ + LOG_ALWAYS_FATAL("branch to absolute PC not supported, use Label\n"); + mArmPC[mInum++] = pc(); +} + +void ArmToMips64Assembler::BX(int cc, int Rn) +{ + LOG_ALWAYS_FATAL("branch to absolute PC not supported, use Label\n"); + mArmPC[mInum++] = pc(); +} + + + +#if 0 +#pragma mark - +#pragma mark Data Transfer... +#endif + +// data transfer... +void ArmToMips64Assembler::LDR(int cc, int Rd, int Rn, uint32_t offset) +{ + mArmPC[mInum++] = pc(); + // work-around for ARM default address mode of immed12_pre(0) + if (offset > AMODE_UNSUPPORTED) offset = 0; + switch (offset) { + case 0: + amode.value = 0; + amode.writeback = 0; + // fall thru to next case .... + case AMODE_IMM_12_PRE: + if (Rn == ARMAssemblerInterface::SP) { + Rn = R_sp; // convert LDR via Arm SP to LW via Mips SP + } + mMips->LW(Rd, Rn, amode.value); + if (amode.writeback) { // OPTIONAL writeback on pre-index mode + mMips->DADDIU(Rn, Rn, amode.value); + } + break; + case AMODE_IMM_12_POST: + if (Rn == ARMAssemblerInterface::SP) { + Rn = R_sp; // convert STR thru Arm SP to STR thru Mips SP + } + mMips->LW(Rd, Rn, 0); + mMips->DADDIU(Rn, Rn, amode.value); + break; + case AMODE_REG_SCALE_PRE: + // we only support simple base + index, no advanced modes for this one yet + mMips->DADDU(R_at, Rn, amode.reg); + mMips->LW(Rd, R_at, 0); + break; + } +} + +void ArmToMips64Assembler::LDRB(int cc, int Rd, int Rn, uint32_t offset) +{ + mArmPC[mInum++] = pc(); + // work-around for ARM default address mode of immed12_pre(0) + if (offset > AMODE_UNSUPPORTED) offset = 0; + switch (offset) { + case 0: + amode.value = 0; + amode.writeback = 0; + // fall thru to next case .... + case AMODE_IMM_12_PRE: + mMips->LBU(Rd, Rn, amode.value); + if (amode.writeback) { // OPTIONAL writeback on pre-index mode + mMips->DADDIU(Rn, Rn, amode.value); + } + break; + case AMODE_IMM_12_POST: + mMips->LBU(Rd, Rn, 0); + mMips->DADDIU(Rn, Rn, amode.value); + break; + case AMODE_REG_SCALE_PRE: + // we only support simple base + index, no advanced modes for this one yet + mMips->DADDU(R_at, Rn, amode.reg); + mMips->LBU(Rd, R_at, 0); + break; + } + +} + +void ArmToMips64Assembler::STR(int cc, int Rd, int Rn, uint32_t offset) +{ + mArmPC[mInum++] = pc(); + // work-around for ARM default address mode of immed12_pre(0) + if (offset > AMODE_UNSUPPORTED) offset = 0; + switch (offset) { + case 0: + amode.value = 0; + amode.writeback = 0; + // fall thru to next case .... + case AMODE_IMM_12_PRE: + if (Rn == ARMAssemblerInterface::SP) { + Rn = R_sp; // convert STR thru Arm SP to SW thru Mips SP + } + if (amode.writeback) { // OPTIONAL writeback on pre-index mode + // If we will writeback, then update the index reg, then store. + // This correctly handles stack-push case. + mMips->DADDIU(Rn, Rn, amode.value); + mMips->SW(Rd, Rn, 0); + } else { + // No writeback so store offset by value + mMips->SW(Rd, Rn, amode.value); + } + break; + case AMODE_IMM_12_POST: + mMips->SW(Rd, Rn, 0); + mMips->DADDIU(Rn, Rn, amode.value); // post index always writes back + break; + case AMODE_REG_SCALE_PRE: + // we only support simple base + index, no advanced modes for this one yet + mMips->DADDU(R_at, Rn, amode.reg); + mMips->SW(Rd, R_at, 0); + break; + } +} + +void ArmToMips64Assembler::STRB(int cc, int Rd, int Rn, uint32_t offset) +{ + mArmPC[mInum++] = pc(); + // work-around for ARM default address mode of immed12_pre(0) + if (offset > AMODE_UNSUPPORTED) offset = 0; + switch (offset) { + case 0: + amode.value = 0; + amode.writeback = 0; + // fall thru to next case .... + case AMODE_IMM_12_PRE: + mMips->SB(Rd, Rn, amode.value); + if (amode.writeback) { // OPTIONAL writeback on pre-index mode + mMips->DADDIU(Rn, Rn, amode.value); + } + break; + case AMODE_IMM_12_POST: + mMips->SB(Rd, Rn, 0); + mMips->DADDIU(Rn, Rn, amode.value); + break; + case AMODE_REG_SCALE_PRE: + // we only support simple base + index, no advanced modes for this one yet + mMips->DADDU(R_at, Rn, amode.reg); + mMips->SB(Rd, R_at, 0); + break; + } +} + +void ArmToMips64Assembler::LDRH(int cc, int Rd, int Rn, uint32_t offset) +{ + mArmPC[mInum++] = pc(); + // work-around for ARM default address mode of immed8_pre(0) + if (offset > AMODE_UNSUPPORTED) offset = 0; + switch (offset) { + case 0: + amode.value = 0; + // fall thru to next case .... + case AMODE_IMM_8_PRE: // no support yet for writeback + mMips->LHU(Rd, Rn, amode.value); + break; + case AMODE_IMM_8_POST: + mMips->LHU(Rd, Rn, 0); + mMips->DADDIU(Rn, Rn, amode.value); + break; + case AMODE_REG_PRE: + // we only support simple base +/- index + if (amode.reg >= 0) { + mMips->DADDU(R_at, Rn, amode.reg); + } else { + mMips->DSUBU(R_at, Rn, abs(amode.reg)); + } + mMips->LHU(Rd, R_at, 0); + break; + } +} + +void ArmToMips64Assembler::LDRSB(int cc, int Rd, int Rn, uint32_t offset) +{ + mArmPC[mInum++] = pc(); + mMips->NOP2(); + NOT_IMPLEMENTED(); +} + +void ArmToMips64Assembler::LDRSH(int cc, int Rd, int Rn, uint32_t offset) +{ + mArmPC[mInum++] = pc(); + mMips->NOP2(); + NOT_IMPLEMENTED(); +} + +void ArmToMips64Assembler::STRH(int cc, int Rd, int Rn, uint32_t offset) +{ + mArmPC[mInum++] = pc(); + // work-around for ARM default address mode of immed8_pre(0) + if (offset > AMODE_UNSUPPORTED) offset = 0; + switch (offset) { + case 0: + amode.value = 0; + // fall thru to next case .... + case AMODE_IMM_8_PRE: // no support yet for writeback + mMips->SH(Rd, Rn, amode.value); + break; + case AMODE_IMM_8_POST: + mMips->SH(Rd, Rn, 0); + mMips->DADDIU(Rn, Rn, amode.value); + break; + case AMODE_REG_PRE: + // we only support simple base +/- index + if (amode.reg >= 0) { + mMips->DADDU(R_at, Rn, amode.reg); + } else { + mMips->DSUBU(R_at, Rn, abs(amode.reg)); + } + mMips->SH(Rd, R_at, 0); + break; + } +} + + + +#if 0 +#pragma mark - +#pragma mark Block Data Transfer... +#endif + +// block data transfer... +void ArmToMips64Assembler::LDM(int cc, int dir, + int Rn, int W, uint32_t reg_list) +{ // ED FD EA FA IB IA DB DA + // const uint8_t P[8] = { 1, 0, 1, 0, 1, 0, 1, 0 }; + // const uint8_t U[8] = { 1, 1, 0, 0, 1, 1, 0, 0 }; + // *mPC++ = (cc<<28) | (4<<25) | (uint32_t(P[dir])<<24) | + // (uint32_t(U[dir])<<23) | (1<<20) | (W<<21) | (Rn<<16) | reg_list; + mArmPC[mInum++] = pc(); + mMips->NOP2(); + NOT_IMPLEMENTED(); +} + +void ArmToMips64Assembler::STM(int cc, int dir, + int Rn, int W, uint32_t reg_list) +{ // FA EA FD ED IB IA DB DA + // const uint8_t P[8] = { 0, 1, 0, 1, 1, 0, 1, 0 }; + // const uint8_t U[8] = { 0, 0, 1, 1, 1, 1, 0, 0 }; + // *mPC++ = (cc<<28) | (4<<25) | (uint32_t(P[dir])<<24) | + // (uint32_t(U[dir])<<23) | (0<<20) | (W<<21) | (Rn<<16) | reg_list; + mArmPC[mInum++] = pc(); + mMips->NOP2(); + NOT_IMPLEMENTED(); +} + + + +#if 0 +#pragma mark - +#pragma mark Special... +#endif + +// special... +void ArmToMips64Assembler::SWP(int cc, int Rn, int Rd, int Rm) { + // *mPC++ = (cc<<28) | (2<<23) | (Rn<<16) | (Rd << 12) | 0x90 | Rm; + mArmPC[mInum++] = pc(); + mMips->NOP2(); + NOT_IMPLEMENTED(); +} + +void ArmToMips64Assembler::SWPB(int cc, int Rn, int Rd, int Rm) { + // *mPC++ = (cc<<28) | (2<<23) | (1<<22) | (Rn<<16) | (Rd << 12) | 0x90 | Rm; + mArmPC[mInum++] = pc(); + mMips->NOP2(); + NOT_IMPLEMENTED(); +} + +void ArmToMips64Assembler::SWI(int cc, uint32_t comment) { + // *mPC++ = (cc<<28) | (0xF<<24) | comment; + mArmPC[mInum++] = pc(); + mMips->NOP2(); + NOT_IMPLEMENTED(); +} + + +#if 0 +#pragma mark - +#pragma mark DSP instructions... +#endif + +// DSP instructions... +void ArmToMips64Assembler::PLD(int Rn, uint32_t offset) { + LOG_ALWAYS_FATAL_IF(!((offset&(1<<24)) && !(offset&(1<<21))), + "PLD only P=1, W=0"); + // *mPC++ = 0xF550F000 | (Rn<<16) | offset; + mArmPC[mInum++] = pc(); + mMips->NOP2(); + NOT_IMPLEMENTED(); +} + +void ArmToMips64Assembler::CLZ(int cc, int Rd, int Rm) +{ + mArmPC[mInum++] = pc(); + mMips->CLZ(Rd, Rm); +} + +void ArmToMips64Assembler::QADD(int cc, int Rd, int Rm, int Rn) +{ + // *mPC++ = (cc<<28) | 0x1000050 | (Rn<<16) | (Rd<<12) | Rm; + mArmPC[mInum++] = pc(); + mMips->NOP2(); + NOT_IMPLEMENTED(); +} + +void ArmToMips64Assembler::QDADD(int cc, int Rd, int Rm, int Rn) +{ + // *mPC++ = (cc<<28) | 0x1400050 | (Rn<<16) | (Rd<<12) | Rm; + mArmPC[mInum++] = pc(); + mMips->NOP2(); + NOT_IMPLEMENTED(); +} + +void ArmToMips64Assembler::QSUB(int cc, int Rd, int Rm, int Rn) +{ + // *mPC++ = (cc<<28) | 0x1200050 | (Rn<<16) | (Rd<<12) | Rm; + mArmPC[mInum++] = pc(); + mMips->NOP2(); + NOT_IMPLEMENTED(); +} + +void ArmToMips64Assembler::QDSUB(int cc, int Rd, int Rm, int Rn) +{ + // *mPC++ = (cc<<28) | 0x1600050 | (Rn<<16) | (Rd<<12) | Rm; + mArmPC[mInum++] = pc(); + mMips->NOP2(); + NOT_IMPLEMENTED(); +} + +// 16 x 16 signed multiply (like SMLAxx without the accumulate) +void ArmToMips64Assembler::SMUL(int cc, int xy, + int Rd, int Rm, int Rs) +{ + mArmPC[mInum++] = pc(); + + // the 16 bits may be in the top or bottom half of 32-bit source reg, + // as defined by the codes BB, BT, TB, TT (compressed param xy) + // where x corresponds to Rm and y to Rs + + // select half-reg for Rm + if (xy & xyTB) { + // use top 16-bits + mMips->SRA(R_at, Rm, 16); + } else { + // use bottom 16, but sign-extend to 32 + mMips->SEH(R_at, Rm); + } + // select half-reg for Rs + if (xy & xyBT) { + // use top 16-bits + mMips->SRA(R_at2, Rs, 16); + } else { + // use bottom 16, but sign-extend to 32 + mMips->SEH(R_at2, Rs); + } + mMips->MUL(Rd, R_at, R_at2); +} + +// signed 32b x 16b multiple, save top 32-bits of 48-bit result +void ArmToMips64Assembler::SMULW(int cc, int y, + int Rd, int Rm, int Rs) +{ + mArmPC[mInum++] = pc(); + + // the selector yT or yB refers to reg Rs + if (y & yT) { + // zero the bottom 16-bits, with 2 shifts, it can affect result + mMips->SRL(R_at, Rs, 16); + mMips->SLL(R_at, R_at, 16); + + } else { + // move low 16-bit half, to high half + mMips->SLL(R_at, Rs, 16); + } + mMips->MUH(Rd, Rm, R_at); +} + +// 16 x 16 signed multiply, accumulate: Rd = Rm{16} * Rs{16} + Rn +void ArmToMips64Assembler::SMLA(int cc, int xy, + int Rd, int Rm, int Rs, int Rn) +{ + mArmPC[mInum++] = pc(); + + // the 16 bits may be in the top or bottom half of 32-bit source reg, + // as defined by the codes BB, BT, TB, TT (compressed param xy) + // where x corresponds to Rm and y to Rs + + // select half-reg for Rm + if (xy & xyTB) { + // use top 16-bits + mMips->SRA(R_at, Rm, 16); + } else { + // use bottom 16, but sign-extend to 32 + mMips->SEH(R_at, Rm); + } + // select half-reg for Rs + if (xy & xyBT) { + // use top 16-bits + mMips->SRA(R_at2, Rs, 16); + } else { + // use bottom 16, but sign-extend to 32 + mMips->SEH(R_at2, Rs); + } + + mMips->MUL(R_at, R_at, R_at2); + mMips->ADDU(Rd, R_at, Rn); +} + +void ArmToMips64Assembler::SMLAL(int cc, int xy, + int RdHi, int RdLo, int Rs, int Rm) +{ + // *mPC++ = (cc<<28) | 0x1400080 | (RdHi<<16) | (RdLo<<12) | (Rs<<8) | (xy<<4) | Rm; + mArmPC[mInum++] = pc(); + mMips->NOP2(); + NOT_IMPLEMENTED(); +} + +void ArmToMips64Assembler::SMLAW(int cc, int y, + int Rd, int Rm, int Rs, int Rn) +{ + // *mPC++ = (cc<<28) | 0x1200080 | (Rd<<16) | (Rn<<12) | (Rs<<8) | (y<<4) | Rm; + mArmPC[mInum++] = pc(); + mMips->NOP2(); + NOT_IMPLEMENTED(); +} + +// used by ARMv6 version of GGLAssembler::filter32 +void ArmToMips64Assembler::UXTB16(int cc, int Rd, int Rm, int rotate) +{ + mArmPC[mInum++] = pc(); + + //Rd[31:16] := ZeroExtend((Rm ROR (8 * sh))[23:16]), + //Rd[15:0] := ZeroExtend((Rm ROR (8 * sh))[7:0]). sh 0-3. + + mMips->ROTR(R_at2, Rm, rotate * 8); + mMips->LUI(R_at, 0xFF); + mMips->ORI(R_at, R_at, 0xFF); + mMips->AND(Rd, R_at2, R_at); +} + +void ArmToMips64Assembler::UBFX(int cc, int Rd, int Rn, int lsb, int width) +{ + /* Placeholder for UBFX */ + mArmPC[mInum++] = pc(); + + mMips->NOP2(); + NOT_IMPLEMENTED(); +} + +// ---------------------------------------------------------------------------- +// Address Processing... +// ---------------------------------------------------------------------------- + +void ArmToMips64Assembler::ADDR_ADD(int cc, + int s, int Rd, int Rn, uint32_t Op2) +{ +// if(cc != AL){ NOT_IMPLEMENTED(); return;} //Not required +// if(s != 0) { NOT_IMPLEMENTED(); return;} //Not required + dataProcessing(opADD64, cc, s, Rd, Rn, Op2); +} + +void ArmToMips64Assembler::ADDR_SUB(int cc, + int s, int Rd, int Rn, uint32_t Op2) +{ +// if(cc != AL){ NOT_IMPLEMENTED(); return;} //Not required +// if(s != 0) { NOT_IMPLEMENTED(); return;} //Not required + dataProcessing(opSUB64, cc, s, Rd, Rn, Op2); +} + +void ArmToMips64Assembler::ADDR_LDR(int cc, int Rd, int Rn, uint32_t offset) { + mArmPC[mInum++] = pc(); + // work-around for ARM default address mode of immed12_pre(0) + if (offset > AMODE_UNSUPPORTED) offset = 0; + switch (offset) { + case 0: + amode.value = 0; + amode.writeback = 0; + // fall thru to next case .... + case AMODE_IMM_12_PRE: + if (Rn == ARMAssemblerInterface::SP) { + Rn = R_sp; // convert LDR via Arm SP to LW via Mips SP + } + mMips->LD(Rd, Rn, amode.value); + if (amode.writeback) { // OPTIONAL writeback on pre-index mode + mMips->DADDIU(Rn, Rn, amode.value); + } + break; + case AMODE_IMM_12_POST: + if (Rn == ARMAssemblerInterface::SP) { + Rn = R_sp; // convert STR thru Arm SP to STR thru Mips SP + } + mMips->LD(Rd, Rn, 0); + mMips->DADDIU(Rn, Rn, amode.value); + break; + case AMODE_REG_SCALE_PRE: + // we only support simple base + index, no advanced modes for this one yet + mMips->DADDU(R_at, Rn, amode.reg); + mMips->LD(Rd, R_at, 0); + break; + } +} + +void ArmToMips64Assembler::ADDR_STR(int cc, int Rd, int Rn, uint32_t offset) { + mArmPC[mInum++] = pc(); + // work-around for ARM default address mode of immed12_pre(0) + if (offset > AMODE_UNSUPPORTED) offset = 0; + switch (offset) { + case 0: + amode.value = 0; + amode.writeback = 0; + // fall thru to next case .... + case AMODE_IMM_12_PRE: + if (Rn == ARMAssemblerInterface::SP) { + Rn = R_sp; // convert STR thru Arm SP to SW thru Mips SP + } + if (amode.writeback) { // OPTIONAL writeback on pre-index mode + // If we will writeback, then update the index reg, then store. + // This correctly handles stack-push case. + mMips->DADDIU(Rn, Rn, amode.value); + mMips->SD(Rd, Rn, 0); + } else { + // No writeback so store offset by value + mMips->SD(Rd, Rn, amode.value); + } + break; + case AMODE_IMM_12_POST: + mMips->SD(Rd, Rn, 0); + mMips->DADDIU(Rn, Rn, amode.value); // post index always writes back + break; + case AMODE_REG_SCALE_PRE: + // we only support simple base + index, no advanced modes for this one yet + mMips->DADDU(R_at, Rn, amode.reg); + mMips->SD(Rd, R_at, 0); + break; + } +} + +#if 0 +#pragma mark - +#pragma mark MIPS Assembler... +#endif + + +//************************************************************************** +//************************************************************************** +//************************************************************************** + + +/* MIPS64 assembler +** this is a subset of mips64r6, targeted specifically at ARM instruction +** replacement in the pixelflinger/codeflinger code. +** +** This class is extended from MIPSAssembler class and overrides only +** MIPS64r6 specific stuff. +*/ + +MIPS64Assembler::MIPS64Assembler(const sp& assembly, ArmToMips64Assembler *parent) + : mParent(parent), + MIPSAssembler::MIPSAssembler(assembly, NULL) +{ +} + +MIPS64Assembler::MIPS64Assembler(void* assembly, ArmToMips64Assembler *parent) + : mParent(parent), + MIPSAssembler::MIPSAssembler(NULL, NULL) +{ + mBase = mPC = (uint32_t *)assembly; +} + +MIPS64Assembler::~MIPS64Assembler() +{ +} + +void MIPS64Assembler::reset() +{ + if (mAssembly != NULL) { + mBase = mPC = (uint32_t *)mAssembly->base(); + } else { + mPC = mBase = base(); + } + mBranchTargets.clear(); + mLabels.clear(); + mLabelsInverseMapping.clear(); + mComments.clear(); +} + + +void MIPS64Assembler::disassemble(const char* name) +{ + char di_buf[140]; + + bool arm_disasm_fmt = (mParent->mArmDisassemblyBuffer == NULL) ? false : true; + + typedef char dstr[40]; + dstr *lines = (dstr *)mParent->mArmDisassemblyBuffer; + + if (mParent->mArmDisassemblyBuffer != NULL) { + for (int i=0; imArmInstrCount; ++i) { + string_detab(lines[i]); + } + } + + // iArm is an index to Arm instructions 1...n for this assembly sequence + // mArmPC[iArm] holds the value of the Mips-PC for the first MIPS + // instruction corresponding to that Arm instruction number + + int iArm = 0; + size_t count = pc()-base(); + uint32_t* mipsPC = base(); + + while (count--) { + ssize_t label = mLabelsInverseMapping.indexOfKey(mipsPC); + if (label >= 0) { + ALOGW("%s:\n", mLabelsInverseMapping.valueAt(label)); + } + ssize_t comment = mComments.indexOfKey(mipsPC); + if (comment >= 0) { + ALOGW("; %s\n", mComments.valueAt(comment)); + } + ::mips_disassem(mipsPC, di_buf, arm_disasm_fmt); + string_detab(di_buf); + string_pad(di_buf, 30); + ALOGW("%08lx: %08x %s", uintptr_t(mipsPC), uint32_t(*mipsPC), di_buf); + mipsPC++; + } +} + +void MIPS64Assembler::fix_branches() +{ + // fixup all the branches + size_t count = mBranchTargets.size(); + while (count--) { + const branch_target_t& bt = mBranchTargets[count]; + uint32_t* target_pc = mLabels.valueFor(bt.label); + LOG_ALWAYS_FATAL_IF(!target_pc, + "error resolving branch targets, target_pc is null"); + int32_t offset = int32_t(target_pc - (bt.pc+1)); + *bt.pc |= offset & 0x00FFFF; + } +} + +void MIPS64Assembler::DADDU(int Rd, int Rs, int Rt) +{ + *mPC++ = (spec_op< +#include + +#include "utils/KeyedVector.h" +#include "utils/Vector.h" +#include "tinyutils/smartpointer.h" + +#include "ARMAssemblerInterface.h" +#include "MIPSAssembler.h" +#include "CodeCache.h" + +namespace android { + +class MIPS64Assembler; // forward reference + +// this class mimics ARMAssembler interface +// intent is to translate each ARM instruction to 1 or more MIPS instr +// implementation calls MIPS64Assembler class to generate mips code +class ArmToMips64Assembler : public ARMAssemblerInterface +{ +public: + ArmToMips64Assembler(const sp& assembly, + char *abuf = 0, int linesz = 0, int instr_count = 0); + ArmToMips64Assembler(void* assembly); + virtual ~ArmToMips64Assembler(); + + uint32_t* base() const; + uint32_t* pc() const; + void disassemble(const char* name); + + virtual void reset(); + + virtual int generate(const char* name); + virtual int getCodegenArch(); + + virtual void prolog(); + virtual void epilog(uint32_t touched); + virtual void comment(const char* string); + // for testing purposes + void fix_branches(); + void set_condition(int mode, int R1, int R2); + + + // ----------------------------------------------------------------------- + // shifters and addressing modes + // ----------------------------------------------------------------------- + + // shifters... + virtual bool isValidImmediate(uint32_t immed); + virtual int buildImmediate(uint32_t i, uint32_t& rot, uint32_t& imm); + + virtual uint32_t imm(uint32_t immediate); + virtual uint32_t reg_imm(int Rm, int type, uint32_t shift); + virtual uint32_t reg_rrx(int Rm); + virtual uint32_t reg_reg(int Rm, int type, int Rs); + + // addressing modes... + // LDR(B)/STR(B)/PLD + // (immediate and Rm can be negative, which indicates U=0) + virtual uint32_t immed12_pre(int32_t immed12, int W=0); + virtual uint32_t immed12_post(int32_t immed12); + virtual uint32_t reg_scale_pre(int Rm, int type=0, uint32_t shift=0, int W=0); + virtual uint32_t reg_scale_post(int Rm, int type=0, uint32_t shift=0); + + // LDRH/LDRSB/LDRSH/STRH + // (immediate and Rm can be negative, which indicates U=0) + virtual uint32_t immed8_pre(int32_t immed8, int W=0); + virtual uint32_t immed8_post(int32_t immed8); + virtual uint32_t reg_pre(int Rm, int W=0); + virtual uint32_t reg_post(int Rm); + + + + + virtual void dataProcessing(int opcode, int cc, int s, + int Rd, int Rn, + uint32_t Op2); + virtual void MLA(int cc, int s, + int Rd, int Rm, int Rs, int Rn); + virtual void MUL(int cc, int s, + int Rd, int Rm, int Rs); + virtual void UMULL(int cc, int s, + int RdLo, int RdHi, int Rm, int Rs); + virtual void UMUAL(int cc, int s, + int RdLo, int RdHi, int Rm, int Rs); + virtual void SMULL(int cc, int s, + int RdLo, int RdHi, int Rm, int Rs); + virtual void SMUAL(int cc, int s, + int RdLo, int RdHi, int Rm, int Rs); + + virtual void B(int cc, uint32_t* pc); + virtual void BL(int cc, uint32_t* pc); + virtual void BX(int cc, int Rn); + virtual void label(const char* theLabel); + virtual void B(int cc, const char* label); + virtual void BL(int cc, const char* label); + + virtual uint32_t* pcForLabel(const char* label); + + virtual void LDR (int cc, int Rd, + int Rn, uint32_t offset = 0); + virtual void LDRB(int cc, int Rd, + int Rn, uint32_t offset = 0); + virtual void STR (int cc, int Rd, + int Rn, uint32_t offset = 0); + virtual void STRB(int cc, int Rd, + int Rn, uint32_t offset = 0); + virtual void LDRH (int cc, int Rd, + int Rn, uint32_t offset = 0); + virtual void LDRSB(int cc, int Rd, + int Rn, uint32_t offset = 0); + virtual void LDRSH(int cc, int Rd, + int Rn, uint32_t offset = 0); + virtual void STRH (int cc, int Rd, + int Rn, uint32_t offset = 0); + + virtual void LDM(int cc, int dir, + int Rn, int W, uint32_t reg_list); + virtual void STM(int cc, int dir, + int Rn, int W, uint32_t reg_list); + + virtual void SWP(int cc, int Rn, int Rd, int Rm); + virtual void SWPB(int cc, int Rn, int Rd, int Rm); + virtual void SWI(int cc, uint32_t comment); + + virtual void PLD(int Rn, uint32_t offset); + virtual void CLZ(int cc, int Rd, int Rm); + virtual void QADD(int cc, int Rd, int Rm, int Rn); + virtual void QDADD(int cc, int Rd, int Rm, int Rn); + virtual void QSUB(int cc, int Rd, int Rm, int Rn); + virtual void QDSUB(int cc, int Rd, int Rm, int Rn); + virtual void SMUL(int cc, int xy, + int Rd, int Rm, int Rs); + virtual void SMULW(int cc, int y, + int Rd, int Rm, int Rs); + virtual void SMLA(int cc, int xy, + int Rd, int Rm, int Rs, int Rn); + virtual void SMLAL(int cc, int xy, + int RdHi, int RdLo, int Rs, int Rm); + virtual void SMLAW(int cc, int y, + int Rd, int Rm, int Rs, int Rn); + + // byte/half word extract... + virtual void UXTB16(int cc, int Rd, int Rm, int rotate); + + // bit manipulation... + virtual void UBFX(int cc, int Rd, int Rn, int lsb, int width); + + // Address loading/storing/manipulation + virtual void ADDR_LDR(int cc, int Rd, int Rn, uint32_t offset = __immed12_pre(0)); + virtual void ADDR_STR(int cc, int Rd, int Rn, uint32_t offset = __immed12_pre(0)); + virtual void ADDR_ADD(int cc, int s, int Rd, int Rn, uint32_t Op2); + virtual void ADDR_SUB(int cc, int s, int Rd, int Rn, uint32_t Op2); + + // this is some crap to share is MIPS64Assembler class for debug + char * mArmDisassemblyBuffer; + int mArmLineLength; + int mArmInstrCount; + + int mInum; // current arm instuction number (0..n) + uint32_t** mArmPC; // array: PC for 1st mips instr of + // each translated ARM instr + + +private: + ArmToMips64Assembler(const ArmToMips64Assembler& rhs); + ArmToMips64Assembler& operator = (const ArmToMips64Assembler& rhs); + + void init_conditional_labels(void); + + void protectConditionalOperands(int Rd); + + // reg__tmp set to MIPS AT, reg 1 + int dataProcAdrModes(int op, int& source, bool sign = false, int reg_tmp = 1); + + sp mAssembly; + MIPS64Assembler* mMips; + + + enum misc_constants_t { + ARM_MAX_INSTUCTIONS = 512 // based on ASSEMBLY_SCRATCH_SIZE + }; + + enum { + SRC_REG = 0, + SRC_IMM, + SRC_ERROR = -1 + }; + + enum addr_modes { + // start above the range of legal mips reg #'s (0-31) + AMODE_REG = 0x20, + AMODE_IMM, AMODE_REG_IMM, // for data processing + AMODE_IMM_12_PRE, AMODE_IMM_12_POST, // for load/store + AMODE_REG_SCALE_PRE, AMODE_IMM_8_PRE, + AMODE_IMM_8_POST, AMODE_REG_PRE, + AMODE_UNSUPPORTED + }; + + struct addr_mode_t { // address modes for current ARM instruction + int reg; + int stype; + uint32_t value; + bool writeback; // writeback the adr reg after modification + } amode; + + enum cond_types { + CMP_COND = 1, + SBIT_COND + }; + + struct cond_mode_t { // conditional-execution info for current ARM instruction + cond_types type; + int r1; + int r2; + int labelnum; + char label[100][10]; + } cond; +}; + + + + +// ---------------------------------------------------------------------------- +// ---------------------------------------------------------------------------- +// ---------------------------------------------------------------------------- + +// This is the basic MIPS64 assembler, which just creates the opcodes in memory. +// All the more complicated work is done in ArmToMips64Assember above. +// Inherits MIPSAssembler class, and overrides only MIPS64r6 specific stuff + +class MIPS64Assembler : public MIPSAssembler +{ +public: + MIPS64Assembler(const sp& assembly, ArmToMips64Assembler *parent); + MIPS64Assembler(void* assembly, ArmToMips64Assembler *parent); + virtual ~MIPS64Assembler(); + + virtual void reset(); + virtual void disassemble(const char* name); + + void fix_branches(); + + // ------------------------------------------------------------------------ + // MIPS64AssemblerInterface... + // ------------------------------------------------------------------------ + +#if 0 +#pragma mark - +#pragma mark Arithmetic... +#endif + + void DADDU(int Rd, int Rs, int Rt); + void DADDIU(int Rt, int Rs, int16_t imm); + void DSUBU(int Rd, int Rs, int Rt); + void DSUBIU(int Rt, int Rs, int16_t imm); + virtual void MUL(int Rd, int Rs, int Rt); + void MUH(int Rd, int Rs, int Rt); + +#if 0 +#pragma mark - +#pragma mark Logical... +#endif + + virtual void CLO(int Rd, int Rs); + virtual void CLZ(int Rd, int Rs); + +#if 0 +#pragma mark - +#pragma mark Load/store... +#endif + + void LD(int Rt, int Rbase, int16_t offset); + void SD(int Rt, int Rbase, int16_t offset); + virtual void LUI(int Rt, int16_t offset); + +#if 0 +#pragma mark - +#pragma mark Branch... +#endif + + void JR(int Rs); + + +protected: + // void string_detab(char *s); + // void string_pad(char *s, int padded_len); + + ArmToMips64Assembler *mParent; + sp mAssembly; + uint32_t* mBase; + uint32_t* mPC; + uint32_t* mPrologPC; + int64_t mDuration; +#if defined(WITH_LIB_HARDWARE) + bool mQemuTracing; +#endif + + struct branch_target_t { + inline branch_target_t() : label(0), pc(0) { } + inline branch_target_t(const char* l, uint32_t* p) + : label(l), pc(p) { } + const char* label; + uint32_t* pc; + }; + + Vector mBranchTargets; + KeyedVector< const char*, uint32_t* > mLabels; + KeyedVector< uint32_t*, const char* > mLabelsInverseMapping; + KeyedVector< uint32_t*, const char* > mComments; + + + // opcode field of all instructions + enum opcode_field { + spec_op, regimm_op, j_op, jal_op, // 0x00 - 0x03 + beq_op, bne_op, pop06_op, pop07_op, // 0x04 - 0x07 + pop10_op, addiu_op, slti_op, sltiu_op, // 0x08 - 0x0b + andi_op, ori_op, xori_op, aui_op, // 0x0c - 0x0f + cop0_op, cop1_op, cop2_op, rsrv_opc_0, // 0x10 - 0x13 + rsrv_opc_1, rsrv_opc_2, pop26_op, pop27_op, // 0x14 - 0x17 + pop30_op, daddiu_op, rsrv_opc_3, rsrv_opc_4, // 0x18 - 0x1b + rsrv_opc_5, daui_op, msa_op, spec3_op, // 0x1c - 0x1f + lb_op, lh_op, rsrv_opc_6, lw_op, // 0x20 - 0x23 + lbu_op, lhu_op, rsrv_opc_7, lwu_op, // 0x24 - 0x27 + sb_op, sh_op, rsrv_opc_8, sw_op, // 0x28 - 0x2b + rsrv_opc_9, rsrv_opc_10, rsrv_opc_11, rsrv_opc_12, // 0x2c - 0x2f + rsrv_opc_13, lwc1_op, bc_op, rsrv_opc_14, // 0x2c - 0x2f + rsrv_opc_15, ldc1_op, pop66_op, ld_op, // 0x30 - 0x33 + rsrv_opc_16, swc1_op, balc_op, pcrel_op, // 0x34 - 0x37 + rsrv_opc_17, sdc1_op, pop76_op, sd_op // 0x38 - 0x3b + }; + + + // func field for special opcode + enum func_spec_op { + sll_fn, rsrv_spec_0, srl_fn, sra_fn, + sllv_fn, lsa_fn, srlv_fn, srav_fn, + rsrv_spec_1, jalr_fn, rsrv_spec_2, rsrv_spec_3, + syscall_fn, break_fn, sdbbp_fn, sync_fn, + clz_fn, clo_fn, dclz_fn, dclo_fn, + dsllv_fn, dlsa_fn, dsrlv_fn, dsrav_fn, + sop30_fn, sop31_fn, sop32_fn, sop33_fn, + sop34_fn, sop35_fn, sop36_fn, sop37_fn, + add_fn, addu_fn, sub_fn, subu_fn, + and_fn, or_fn, xor_fn, nor_fn, + rsrv_spec_4, rsrv_spec_5, slt_fn, sltu_fn, + dadd_fn, daddu_fn, dsub_fn, dsubu_fn, + tge_fn, tgeu_fn, tlt_fn, tltu_fn, + teq_fn, seleqz_fn, tne_fn, selnez_fn, + dsll_fn, rsrv_spec_6, dsrl_fn, dsra_fn, + dsll32_fn, rsrv_spec_7, dsrl32_fn, dsra32_fn + }; + + // func field for spec3 opcode + enum func_spec3_op { + ext_fn, dextm_fn, dextu_fn, dext_fn, + ins_fn, dinsm_fn, dinsu_fn, dins_fn, + cachee_fn = 0x1b, sbe_fn, she_fn, sce_fn, swe_fn, + bshfl_fn, prefe_fn = 0x23, dbshfl_fn, cache_fn, sc_fn, scd_fn, + lbue_fn, lhue_fn, lbe_fn = 0x2c, lhe_fn, lle_fn, lwe_fn, + pref_fn = 0x35, ll_fn, lld_fn, rdhwr_fn = 0x3b + }; + + // sa field for spec3 opcodes, with BSHFL function + enum func_spec3_bshfl { + bitswap_fn, + wsbh_fn = 0x02, + dshd_fn = 0x05, + seb_fn = 0x10, + seh_fn = 0x18 + }; + + // rt field of regimm opcodes. + enum regimm_fn { + bltz_fn, bgez_fn, + dahi_fn = 0x6, + nal_fn = 0x10, bal_fn, bltzall_fn, bgezall_fn, + sigrie_fn = 0x17, + dati_fn = 0x1e, synci_fn + }; + + enum muldiv_fn { + mul_fn = 0x02, muh_fn + }; + + enum mips_inst_shifts { + OP_SHF = 26, + JTARGET_SHF = 0, + RS_SHF = 21, + RT_SHF = 16, + RD_SHF = 11, + RE_SHF = 6, + SA_SHF = RE_SHF, // synonym + IMM_SHF = 0, + FUNC_SHF = 0, + + // mask values + MSK_16 = 0xffff, + + + CACHEOP_SHF = 18, + CACHESEL_SHF = 16, + }; +}; + + +}; // namespace android + +#endif //ANDROID_MIPS64ASSEMBLER_H diff --git a/libpixelflinger/codeflinger/MIPSAssembler.cpp b/libpixelflinger/codeflinger/MIPSAssembler.cpp index a88d2fe00..daa231fe0 100644 --- a/libpixelflinger/codeflinger/MIPSAssembler.cpp +++ b/libpixelflinger/codeflinger/MIPSAssembler.cpp @@ -1358,7 +1358,7 @@ void MIPSAssembler::disassemble(const char* name) ::mips_disassem(mipsPC, di_buf, arm_disasm_fmt); string_detab(di_buf); string_pad(di_buf, 30); - ALOGW("%08x: %08x %s", uint32_t(mipsPC), uint32_t(*mipsPC), di_buf); + ALOGW("%08x: %08x %s", uintptr_t(mipsPC), uint32_t(*mipsPC), di_buf); mipsPC++; } } @@ -1407,7 +1407,7 @@ int MIPSAssembler::generate(const char* name) #if defined(WITH_LIB_HARDWARE) if (__builtin_expect(mQemuTracing, 0)) { - int err = qemu_add_mapping(int(base()), name); + int err = qemu_add_mapping(uintptr_t(base()), name); mQemuTracing = (err >= 0); } #endif diff --git a/libpixelflinger/codeflinger/MIPSAssembler.h b/libpixelflinger/codeflinger/MIPSAssembler.h index 8fea8cb12..06cb0d0df 100644 --- a/libpixelflinger/codeflinger/MIPSAssembler.h +++ b/libpixelflinger/codeflinger/MIPSAssembler.h @@ -244,20 +244,20 @@ public: MIPSAssembler(const sp& assembly, ArmToMipsAssembler *parent); virtual ~MIPSAssembler(); - uint32_t* base() const; - uint32_t* pc() const; - void reset(); + virtual uint32_t* base() const; + virtual uint32_t* pc() const; + virtual void reset(); - void disassemble(const char* name); + virtual void disassemble(const char* name); - void prolog(); - void epilog(uint32_t touched); - int generate(const char* name); - void comment(const char* string); - void label(const char* string); + virtual void prolog(); + virtual void epilog(uint32_t touched); + virtual int generate(const char* name); + virtual void comment(const char* string); + virtual void label(const char* string); // valid only after generate() has been called - uint32_t* pcForLabel(const char* label); + virtual uint32_t* pcForLabel(const char* label); // ------------------------------------------------------------------------ @@ -399,9 +399,9 @@ public: -private: - void string_detab(char *s); - void string_pad(char *s, int padded_len); +protected: + virtual void string_detab(char *s); + virtual void string_pad(char *s, int padded_len); ArmToMipsAssembler *mParent; sp mAssembly; @@ -537,7 +537,11 @@ private: enum mips_regnames { R_zero = 0, R_at, R_v0, R_v1, R_a0, R_a1, R_a2, R_a3, +#if __mips_isa_rev < 6 R_t0, R_t1, R_t2, R_t3, R_t4, R_t5, R_t6, R_t7, +#else + R_a4, R_a5, R_a6, R_a7, R_t0, R_t1, R_t2, R_t3, +#endif R_s0, R_s1, R_s2, R_s3, R_s4, R_s5, R_s6, R_s7, R_t8, R_t9, R_k0, R_k1, R_gp, R_sp, R_s8, R_ra, R_lr = R_s8, diff --git a/libpixelflinger/codeflinger/mips64_disassem.c b/libpixelflinger/codeflinger/mips64_disassem.c new file mode 100644 index 000000000..44b7fe7cd --- /dev/null +++ b/libpixelflinger/codeflinger/mips64_disassem.c @@ -0,0 +1,582 @@ +/* $NetBSD: db_disasm.c,v 1.19 2007/02/28 04:21:53 thorpej Exp $ */ + +/*- + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Ralph Campbell. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * from: @(#)kadb.c 8.1 (Berkeley) 6/10/93 + */ + +#include +#include +#include +#include +#include + +#include +#include "mips_opcode.h" + +#include + +static char *sprintf_buffer; +static int sprintf_buf_len; + + +typedef uint64_t db_addr_t; +static void db_printf(const char* fmt, ...); + +static const char * const op_name[64] = { +/* 0 */ "spec", "bcond", "j", "jal", "beq", "bne", "blez", "bgtz", +/* 8 */ "pop10", "addiu", "slti", "sltiu", "andi", "ori", "xori", "aui", +/*16 */ "cop0", "cop1", "cop2", "?", "?", "?", "pop26", "pop27", +/*24 */ "pop30", "daddiu", "?", "?", "?", "daui", "msa", "op37", +/*32 */ "lb", "lh", "?", "lw", "lbu", "lhu", "?", "lwu", +/*40 */ "sb", "sh", "?", "sw", "?", "?", "?", "?", +/*48 */ "?", "lwc1", "bc", "?", "?", "ldc1", "pop66", "ld", +/*56 */ "?", "swc1", "balc", "pcrel", "?", "sdc1", "pop76", "sd" +}; + +static const char * const spec_name[64] = { +/* 0 */ "sll", "?", "srl", "sra", "sllv", "?", "srlv", "srav", +/* 8 */ "?", "jalr", "?", "?", "syscall", "break", "sdbpp", "sync", +/*16 */ "clz", "clo", "dclz", "dclo", "dsllv", "dlsa", "dsrlv", "dsrav", +/*24 */ "sop30", "sop31", "sop32", "sop33", "sop34", "sop35", "sop36", "sop37", +/*32 */ "add", "addu", "sub", "subu", "and", "or", "xor", "nor", +/*40 */ "?", "?", "slt", "sltu", "dadd", "daddu", "dsub", "dsubu", +/*48 */ "tge", "tgeu", "tlt", "tltu", "teq", "seleqz", "tne", "selnez", +/*56 */ "dsll", "?", "dsrl", "dsra", "dsll32", "?", "dsrl32", "dsra32" +}; + +static const char * const bcond_name[32] = { +/* 0 */ "bltz", "bgez", "?", "?", "?", "?", "dahi", "?", +/* 8 */ "?", "?", "?", "?", "?", "?", "?", "?", +/*16 */ "nal", "bal", "?", "?", "?", "?", "?", "sigrie", +/*24 */ "?", "?", "?", "?", "?", "?", "dati", "synci", +}; + +static const char * const cop1_name[64] = { +/* 0 */ "fadd", "fsub", "fmpy", "fdiv", "fsqrt","fabs", "fmov", "fneg", +/* 8 */ "fop08","fop09","fop0a","fop0b","fop0c","fop0d","fop0e","fop0f", +/*16 */ "fop10","fop11","fop12","fop13","fop14","fop15","fop16","fop17", +/*24 */ "fop18","fop19","fop1a","fop1b","fop1c","fop1d","fop1e","fop1f", +/*32 */ "fcvts","fcvtd","fcvte","fop23","fcvtw","fop25","fop26","fop27", +/*40 */ "fop28","fop29","fop2a","fop2b","fop2c","fop2d","fop2e","fop2f", +/*48 */ "fcmp.f","fcmp.un","fcmp.eq","fcmp.ueq","fcmp.olt","fcmp.ult", + "fcmp.ole","fcmp.ule", +/*56 */ "fcmp.sf","fcmp.ngle","fcmp.seq","fcmp.ngl","fcmp.lt","fcmp.nge", + "fcmp.le","fcmp.ngt" +}; + +static const char * const fmt_name[16] = { + "s", "d", "e", "fmt3", + "w", "fmt5", "fmt6", "fmt7", + "fmt8", "fmt9", "fmta", "fmtb", + "fmtc", "fmtd", "fmte", "fmtf" +}; + +static char * const mips_reg_name[32] = { + "zero", "at", "v0", "v1", "a0", "a1", "a2", "a3", + "a4", "a5", "a6", "a7", "t0", "t1", "t2", "t3", + "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7", + "t8", "t9", "k0", "k1", "gp", "sp", "s8", "ra" +}; + +static char * alt_arm_reg_name[32] = { // hacked names for comparison with ARM code + "zero", "at", "r0", "r1", "r2", "r3", "r4", "r5", + "r6", "r7", "r8", "r9", "r10", "r11", "r12", "r13", + "r14", "r15", "at2", "cmp", "s4", "s5", "s6", "s7", + "t8", "t9", "k0", "k1", "gp", "sp", "s8", "ra" +}; + +static char ** reg_name = &mips_reg_name[0]; + +static const char * const c0_opname[64] = { + "c0op00","tlbr", "tlbwi", "c0op03","c0op04","c0op05","tlbwr", "c0op07", + "tlbp", "c0op11","c0op12","c0op13","c0op14","c0op15","c0op16","c0op17", + "rfe", "c0op21","c0op22","c0op23","c0op24","c0op25","c0op26","c0op27", + "eret", "c0op31","c0op32","c0op33","c0op34","c0op35","c0op36","c0op37", + "c0op40","c0op41","c0op42","c0op43","c0op44","c0op45","c0op46","c0op47", + "c0op50","c0op51","c0op52","c0op53","c0op54","c0op55","c0op56","c0op57", + "c0op60","c0op61","c0op62","c0op63","c0op64","c0op65","c0op66","c0op67", + "c0op70","c0op71","c0op72","c0op73","c0op74","c0op75","c0op77","c0op77", +}; + +static const char * const c0_reg[32] = { + "index", "random", "tlblo0", "tlblo1", + "context", "pagemask", "wired", "cp0r7", + "badvaddr", "count", "tlbhi", "compare", + "status", "cause", "epc", "prid", + "config", "lladdr", "watchlo", "watchhi", + "xcontext", "cp0r21", "cp0r22", "debug", + "depc", "perfcnt", "ecc", "cacheerr", + "taglo", "taghi", "errepc", "desave" +}; + +static void print_addr(db_addr_t); +db_addr_t mips_disassem(db_addr_t loc, char *di_buffer, int alt_dis_format); + + +/* + * Disassemble instruction 'insn' nominally at 'loc'. + * 'loc' may in fact contain a breakpoint instruction. + */ +static db_addr_t +db_disasm_insn(int insn, db_addr_t loc, bool altfmt) +{ + bool bdslot = false; + InstFmt i; + + i.word = insn; + + switch (i.JType.op) { + case OP_SPECIAL: + if (i.word == 0) { + db_printf("nop"); + break; + } + if (i.word == 0x0080) { + db_printf("NIY"); + break; + } + if (i.word == 0x00c0) { + db_printf("NOT IMPL"); + break; + } + /* Special cases -------------------------------------------------- + * "addu" is a "move" only in 32-bit mode. What's the correct + * answer - never decode addu/daddu as "move"? + */ + if ( (i.RType.func == OP_ADDU && i.RType.rt == 0) || + (i.RType.func == OP_OR && i.RType.rt == 0) ) { + db_printf("move\t%s,%s", + reg_name[i.RType.rd], + reg_name[i.RType.rs]); + break; + } + + if (i.RType.func == OP_SRL && (i.RType.rs & 1) == 1) { + db_printf("rotr\t%s,%s,%d", reg_name[i.RType.rd], + reg_name[i.RType.rt], i.RType.shamt); + break; + } + if (i.RType.func == OP_SRLV && (i.RType.shamt & 1) == 1) { + db_printf("rotrv\t%s,%s,%s", reg_name[i.RType.rd], + reg_name[i.RType.rt], reg_name[i.RType.rs]); + break; + } + + if (i.RType.func == OP_SOP30) { + if (i.RType.shamt == OP_MUL) { + db_printf("mul"); + } else if (i.RType.shamt == OP_MUH) { + db_printf("muh"); + } + db_printf("\t%s,%s,%s", reg_name[i.RType.rd], + reg_name[i.RType.rs], reg_name[i.RType.rt]); + break; + } + if (i.RType.func == OP_SOP31) { + if (i.RType.shamt == OP_MUL) { + db_printf("mulu"); + } else if (i.RType.shamt == OP_MUH) { + db_printf("muhu"); + } + db_printf("\t%s,%s,%s", reg_name[i.RType.rd], + reg_name[i.RType.rs], reg_name[i.RType.rt]); + break; + } + + if (i.RType.func == OP_JALR && i.RType.rd == 0) { + db_printf("jr\t%s", reg_name[i.RType.rs]); + bdslot = true; + break; + } + + db_printf("%s", spec_name[i.RType.func]); + switch (i.RType.func) { + case OP_SLL: + case OP_SRL: + case OP_SRA: + case OP_DSLL: + + case OP_DSRL: + case OP_DSRA: + case OP_DSLL32: + case OP_DSRL32: + case OP_DSRA32: + db_printf("\t%s,%s,%d", + reg_name[i.RType.rd], + reg_name[i.RType.rt], + i.RType.shamt); + break; + + case OP_SLLV: + case OP_SRLV: + case OP_SRAV: + case OP_DSLLV: + case OP_DSRLV: + case OP_DSRAV: + db_printf("\t%s,%s,%s", + reg_name[i.RType.rd], + reg_name[i.RType.rt], + reg_name[i.RType.rs]); + break; + + case OP_CLZ: + case OP_CLO: + case OP_DCLZ: + case OP_DCLO: + db_printf("\t%s,%s", + reg_name[i.RType.rd], + reg_name[i.RType.rs]); + break; + + case OP_JALR: + db_printf("\t"); + if (i.RType.rd != 31) { + db_printf("%s,", reg_name[i.RType.rd]); + } + db_printf("%s", reg_name[i.RType.rs]); + bdslot = true; + break; + + case OP_SYSCALL: + case OP_SYNC: + break; + + case OP_BREAK: + db_printf("\t%d", (i.RType.rs << 5) | i.RType.rt); + break; + + default: + db_printf("\t%s,%s,%s", + reg_name[i.RType.rd], + reg_name[i.RType.rs], + reg_name[i.RType.rt]); + } + break; + + case OP_SPECIAL3: + if (i.RType.func == OP_EXT) + db_printf("ext\t%s,%s,%d,%d", + reg_name[i.RType.rt], + reg_name[i.RType.rs], + i.RType.shamt, + i.RType.rd+1); + else if (i.RType.func == OP_DEXT) + db_printf("dext\t%s,%s,%d,%d", + reg_name[i.RType.rt], + reg_name[i.RType.rs], + i.RType.shamt, + i.RType.rd+1); + else if (i.RType.func == OP_DEXTM) + db_printf("dextm\t%s,%s,%d,%d", + reg_name[i.RType.rt], + reg_name[i.RType.rs], + i.RType.shamt, + i.RType.rd+33); + else if (i.RType.func == OP_DEXTU) + db_printf("dextu\t%s,%s,%d,%d", + reg_name[i.RType.rt], + reg_name[i.RType.rs], + i.RType.shamt+32, + i.RType.rd+1); + else if (i.RType.func == OP_INS) + db_printf("ins\t%s,%s,%d,%d", + reg_name[i.RType.rt], + reg_name[i.RType.rs], + i.RType.shamt, + i.RType.rd-i.RType.shamt+1); + else if (i.RType.func == OP_DINS) + db_printf("dins\t%s,%s,%d,%d", + reg_name[i.RType.rt], + reg_name[i.RType.rs], + i.RType.shamt, + i.RType.rd-i.RType.shamt+1); + else if (i.RType.func == OP_DINSM) + db_printf("dinsm\t%s,%s,%d,%d", + reg_name[i.RType.rt], + reg_name[i.RType.rs], + i.RType.shamt, + i.RType.rd-i.RType.shamt+33); + else if (i.RType.func == OP_DINSU) + db_printf("dinsu\t%s,%s,%d,%d", + reg_name[i.RType.rt], + reg_name[i.RType.rs], + i.RType.shamt+32, + i.RType.rd-i.RType.shamt+1); + else if (i.RType.func == OP_BSHFL && i.RType.shamt == OP_WSBH) + db_printf("wsbh\t%s,%s", + reg_name[i.RType.rd], + reg_name[i.RType.rt]); + else if (i.RType.func == OP_BSHFL && i.RType.shamt == OP_SEB) + db_printf("seb\t%s,%s", + reg_name[i.RType.rd], + reg_name[i.RType.rt]); + else if (i.RType.func == OP_BSHFL && i.RType.shamt == OP_SEH) + db_printf("seh\t%s,%s", + reg_name[i.RType.rd], + reg_name[i.RType.rt]); + else if (i.RType.func == OP_RDHWR) + db_printf("rdhwr\t%s,%s", + reg_name[i.RType.rd], + reg_name[i.RType.rt]); + else + db_printf("Unknown"); + break; + + case OP_BCOND: + db_printf("%s\t%s,", bcond_name[i.IType.rt], + reg_name[i.IType.rs]); + goto pr_displ; + + case OP_BLEZ: + case OP_BGTZ: + db_printf("%s\t%s,", op_name[i.IType.op], + reg_name[i.IType.rs]); + goto pr_displ; + + case OP_BEQ: + if (i.IType.rs == 0 && i.IType.rt == 0) { + db_printf("b\t"); + goto pr_displ; + } + /* FALLTHROUGH */ + case OP_BNE: + db_printf("%s\t%s,%s,", op_name[i.IType.op], + reg_name[i.IType.rs], + reg_name[i.IType.rt]); + pr_displ: + print_addr(loc + 4 + ((short)i.IType.imm << 2)); + bdslot = true; + break; + + case OP_COP0: + switch (i.RType.rs) { + case OP_BCx: + case OP_BCy: + + db_printf("bc0%c\t", + "ft"[i.RType.rt & COPz_BC_TF_MASK]); + goto pr_displ; + + case OP_MT: + db_printf("mtc0\t%s,%s", + reg_name[i.RType.rt], + c0_reg[i.RType.rd]); + break; + + case OP_DMT: + db_printf("dmtc0\t%s,%s", + reg_name[i.RType.rt], + c0_reg[i.RType.rd]); + break; + + case OP_MF: + db_printf("mfc0\t%s,%s", + reg_name[i.RType.rt], + c0_reg[i.RType.rd]); + break; + + case OP_DMF: + db_printf("dmfc0\t%s,%s", + reg_name[i.RType.rt], + c0_reg[i.RType.rd]); + break; + + default: + db_printf("%s", c0_opname[i.FRType.func]); + } + break; + + case OP_COP1: + switch (i.RType.rs) { + case OP_BCx: + case OP_BCy: + db_printf("bc1%c\t", + "ft"[i.RType.rt & COPz_BC_TF_MASK]); + goto pr_displ; + + case OP_MT: + db_printf("mtc1\t%s,f%d", + reg_name[i.RType.rt], + i.RType.rd); + break; + + case OP_MF: + db_printf("mfc1\t%s,f%d", + reg_name[i.RType.rt], + i.RType.rd); + break; + + case OP_CT: + db_printf("ctc1\t%s,f%d", + reg_name[i.RType.rt], + i.RType.rd); + break; + + case OP_CF: + db_printf("cfc1\t%s,f%d", + reg_name[i.RType.rt], + i.RType.rd); + break; + + default: + db_printf("%s.%s\tf%d,f%d,f%d", + cop1_name[i.FRType.func], + fmt_name[i.FRType.fmt], + i.FRType.fd, i.FRType.fs, i.FRType.ft); + } + break; + + case OP_J: + case OP_JAL: + db_printf("%s\t", op_name[i.JType.op]); + print_addr((loc & 0xFFFFFFFFF0000000) | (i.JType.target << 2)); + bdslot = true; + break; + + case OP_LWC1: + case OP_SWC1: + db_printf("%s\tf%d,", op_name[i.IType.op], + i.IType.rt); + goto loadstore; + + case OP_LB: + case OP_LH: + case OP_LW: + case OP_LD: + case OP_LBU: + case OP_LHU: + case OP_LWU: + case OP_SB: + case OP_SH: + case OP_SW: + case OP_SD: + db_printf("%s\t%s,", op_name[i.IType.op], + reg_name[i.IType.rt]); + loadstore: + db_printf("%d(%s)", (short)i.IType.imm, + reg_name[i.IType.rs]); + break; + + case OP_ORI: + case OP_XORI: + if (i.IType.rs == 0) { + db_printf("li\t%s,0x%x", + reg_name[i.IType.rt], + i.IType.imm); + break; + } + /* FALLTHROUGH */ + case OP_ANDI: + db_printf("%s\t%s,%s,0x%x", op_name[i.IType.op], + reg_name[i.IType.rt], + reg_name[i.IType.rs], + i.IType.imm); + break; + + case OP_AUI: + if (i.IType.rs == 0) { + db_printf("lui\t%s,0x%x", reg_name[i.IType.rt], + i.IType.imm); + } else { + db_printf("%s\t%s,%s,%d", op_name[i.IType.op], + reg_name[i.IType.rt], reg_name[i.IType.rs], + (short)i.IType.imm); + } + break; + + case OP_ADDIU: + case OP_DADDIU: + if (i.IType.rs == 0) { + db_printf("li\t%s,%d", + reg_name[i.IType.rt], + (short)i.IType.imm); + break; + } + /* FALLTHROUGH */ + default: + db_printf("%s\t%s,%s,%d", op_name[i.IType.op], + reg_name[i.IType.rt], + reg_name[i.IType.rs], + (short)i.IType.imm); + } + // db_printf("\n"); + // if (bdslot) { + // db_printf(" bd: "); + // mips_disassem(loc+4); + // return (loc + 8); + // } + return (loc + 4); +} + +static void +print_addr(db_addr_t loc) +{ + db_printf("0x%08lx", loc); +} + +static void db_printf(const char* fmt, ...) +{ + int cnt; + va_list argp; + va_start(argp, fmt); + if (sprintf_buffer) { + cnt = vsnprintf(sprintf_buffer, sprintf_buf_len, fmt, argp); + sprintf_buffer += cnt; + sprintf_buf_len -= cnt; + } else { + vprintf(fmt, argp); + } +} + +/* + * Disassemble instruction at 'loc'. + * Return address of start of next instruction. + * Since this function is used by 'examine' and by 'step' + * "next instruction" does NOT mean the next instruction to + * be executed but the 'linear' next instruction. + */ +db_addr_t +mips_disassem(db_addr_t loc, char *di_buffer, int alt_dis_format) +{ + u_int32_t instr; + + if (alt_dis_format) { // use ARM register names for disassembly + reg_name = &alt_arm_reg_name[0]; + } + + sprintf_buffer = di_buffer; // quick 'n' dirty printf() vs sprintf() + sprintf_buf_len = 39; // should be passed in + + instr = *(u_int32_t *)loc; + return (db_disasm_insn(instr, loc, false)); +} diff --git a/libpixelflinger/codeflinger/mips64_disassem.h b/libpixelflinger/codeflinger/mips64_disassem.h new file mode 100644 index 000000000..c94f04f9b --- /dev/null +++ b/libpixelflinger/codeflinger/mips64_disassem.h @@ -0,0 +1,56 @@ +/* $NetBSD: db_disasm.c,v 1.19 2007/02/28 04:21:53 thorpej Exp $ */ + +/*- + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Ralph Campbell. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * from: @(#)kadb.c 8.1 (Berkeley) 6/10/93 + */ + + + +#ifndef ANDROID_MIPS_DISASSEM_H +#define ANDROID_MIPS_DISASSEM_H + +#include + +#if __cplusplus +extern "C" { +#endif + +/* Prototypes for callable functions */ + +void mips_disassem(uint32_t *location, char *di_buffer, int alt_fmt); + +#if __cplusplus +} +#endif + +#endif /* !ANDROID_MIPS_DISASSEM_H */ diff --git a/libpixelflinger/codeflinger/mips_disassem.c b/libpixelflinger/codeflinger/mips_disassem.c index 4ab9bd35d..3007b1534 100644 --- a/libpixelflinger/codeflinger/mips_disassem.c +++ b/libpixelflinger/codeflinger/mips_disassem.c @@ -323,14 +323,14 @@ db_disasm_insn(int insn, db_addr_t loc, bool altfmt) db_printf("ext\t%s,%s,%d,%d", reg_name[i.RType.rt], reg_name[i.RType.rs], - i.RType.rd+1, - i.RType.shamt); + i.RType.shamt, + i.RType.rd+1); else if (i.RType.func == OP_INS) db_printf("ins\t%s,%s,%d,%d", reg_name[i.RType.rt], reg_name[i.RType.rs], - i.RType.rd+1, - i.RType.shamt); + i.RType.shamt, + i.RType.rd-i.RType.shamt+1); else if (i.RType.func == OP_BSHFL && i.RType.shamt == OP_WSBH) db_printf("wsbh\t%s,%s", reg_name[i.RType.rd], diff --git a/libpixelflinger/codeflinger/mips_opcode.h b/libpixelflinger/codeflinger/mips_opcode.h index 7ed5ef579..45bb19ea1 100644 --- a/libpixelflinger/codeflinger/mips_opcode.h +++ b/libpixelflinger/codeflinger/mips_opcode.h @@ -125,69 +125,118 @@ typedef union { #define OP_BLEZ 006 #define OP_BGTZ 007 +#if __mips_isa_rev < 6 #define OP_ADDI 010 +#else +#define OP_POP10 010 +#endif + #define OP_ADDIU 011 #define OP_SLTI 012 #define OP_SLTIU 013 #define OP_ANDI 014 #define OP_ORI 015 #define OP_XORI 016 + +#if __mips_isa_rev < 6 #define OP_LUI 017 +#else +#define OP_AUI 017 +#endif #define OP_COP0 020 #define OP_COP1 021 #define OP_COP2 022 + +#if __mips_isa_rev < 6 #define OP_COP3 023 -#define OP_BEQL 024 /* MIPS-II, for r4000 port */ -#define OP_BNEL 025 /* MIPS-II, for r4000 port */ -#define OP_BLEZL 026 /* MIPS-II, for r4000 port */ -#define OP_BGTZL 027 /* MIPS-II, for r4000 port */ +#define OP_BEQL 024 +#define OP_BNEL 025 +#define OP_BLEZL 026 +#define OP_BGTZL 027 +#define OP_DADDI 030 +#else +#define OP_POP26 026 +#define OP_POP27 027 +#define OP_POP30 030 +#endif -#define OP_DADDI 030 /* MIPS-II, for r4000 port */ -#define OP_DADDIU 031 /* MIPS-II, for r4000 port */ -#define OP_LDL 032 /* MIPS-II, for r4000 port */ -#define OP_LDR 033 /* MIPS-II, for r4000 port */ +#define OP_DADDIU 031 -#define OP_SPECIAL2 034 /* QED opcodes */ -#define OP_SPECIAL3 037 /* mips32r2 opcodes */ +#if __mips_isa_rev < 6 +#define OP_LDL 032 +#define OP_LDR 033 +#define OP_SPECIAL2 034 +#else +#define OP_DAUI 035 +#endif + +#define OP_SPECIAL3 037 #define OP_LB 040 #define OP_LH 041 + +#if __mips_isa_rev < 6 #define OP_LWL 042 +#endif + #define OP_LW 043 #define OP_LBU 044 #define OP_LHU 045 #define OP_LWR 046 #define OP_LHU 045 + +#if __mips_isa_rev < 6 #define OP_LWR 046 -#define OP_LWU 047 /* MIPS-II, for r4000 port */ +#endif + +#define OP_LWU 047 #define OP_SB 050 #define OP_SH 051 -#define OP_SWL 052 -#define OP_SW 053 -#define OP_SDL 054 /* MIPS-II, for r4000 port */ -#define OP_SDR 055 /* MIPS-II, for r4000 port */ -#define OP_SWR 056 -#define OP_CACHE 057 /* MIPS-II, for r4000 port */ +#if __mips_isa_rev < 6 +#define OP_SWL 052 +#endif + +#define OP_SW 053 + +#if __mips_isa_rev < 6 +#define OP_SDL 054 +#define OP_SDR 055 +#define OP_SWR 056 +#define OP_CACHE 057 #define OP_LL 060 -#define OP_LWC0 OP_LL /* backwards source compatibility */ +#define OP_LWC0 OP_LL #define OP_LWC1 061 #define OP_LWC2 062 #define OP_LWC3 063 -#define OP_LLD 064 /* MIPS-II, for r4000 port */ -#define OP_LDC1 065 -#define OP_LD 067 /* MIPS-II, for r4000 port */ +#define OP_LLD 064 +#else +#define OP_LWC1 061 +#define OP_BC 062 +#endif +#define OP_LDC1 065 +#define OP_LD 067 + +#if __mips_isa_rev < 6 #define OP_SC 070 -#define OP_SWC0 OP_SC /* backwards source compatibility */ +#define OP_SWC0 OP_SC +#endif + #define OP_SWC1 071 + +#if __mips_isa_rev < 6 #define OP_SWC2 072 #define OP_SWC3 073 -#define OP_SCD 074 /* MIPS-II, for r4000 port */ +#define OP_SCD 074 +#else +#define OP_BALC 072 +#endif + #define OP_SDC1 075 -#define OP_SD 077 /* MIPS-II, for r4000 port */ +#define OP_SD 077 /* * Values for the 'func' field when 'op' == OP_SPECIAL. @@ -199,28 +248,50 @@ typedef union { #define OP_SRLV 006 #define OP_SRAV 007 +#if __mips_isa_rev < 6 #define OP_JR 010 +#endif + #define OP_JALR 011 #define OP_SYSCALL 014 #define OP_BREAK 015 -#define OP_SYNC 017 /* MIPS-II, for r4000 port */ +#define OP_SYNC 017 +#if __mips_isa_rev < 6 #define OP_MFHI 020 #define OP_MTHI 021 #define OP_MFLO 022 #define OP_MTLO 023 -#define OP_DSLLV 024 /* MIPS-II, for r4000 port */ -#define OP_DSRLV 026 /* MIPS-II, for r4000 port */ -#define OP_DSRAV 027 /* MIPS-II, for r4000 port */ +#else +#define OP_CLZ 020 +#define OP_CLO 021 +#define OP_DCLZ 022 +#define OP_DCLO 023 +#endif +#define OP_DSLLV 024 +#define OP_DSRLV 026 +#define OP_DSRAV 027 + +#if __mips_isa_rev < 6 #define OP_MULT 030 #define OP_MULTU 031 #define OP_DIV 032 #define OP_DIVU 033 -#define OP_DMULT 034 /* MIPS-II, for r4000 port */ -#define OP_DMULTU 035 /* MIPS-II, for r4000 port */ -#define OP_DDIV 036 /* MIPS-II, for r4000 port */ -#define OP_DDIVU 037 /* MIPS-II, for r4000 port */ +#define OP_DMULT 034 +#define OP_DMULTU 035 +#define OP_DDIV 036 +#define OP_DDIVU 037 +#else +#define OP_SOP30 030 +#define OP_SOP31 031 +#define OP_SOP32 032 +#define OP_SOP33 033 +#define OP_SOP34 034 +#define OP_SOP35 035 +#define OP_SOP36 036 +#define OP_SOP37 037 +#endif #define OP_ADD 040 #define OP_ADDU 041 @@ -233,73 +304,96 @@ typedef union { #define OP_SLT 052 #define OP_SLTU 053 -#define OP_DADD 054 /* MIPS-II, for r4000 port */ -#define OP_DADDU 055 /* MIPS-II, for r4000 port */ -#define OP_DSUB 056 /* MIPS-II, for r4000 port */ -#define OP_DSUBU 057 /* MIPS-II, for r4000 port */ +#define OP_DADD 054 +#define OP_DADDU 055 +#define OP_DSUB 056 +#define OP_DSUBU 057 -#define OP_TGE 060 /* MIPS-II, for r4000 port */ -#define OP_TGEU 061 /* MIPS-II, for r4000 port */ -#define OP_TLT 062 /* MIPS-II, for r4000 port */ -#define OP_TLTU 063 /* MIPS-II, for r4000 port */ -#define OP_TEQ 064 /* MIPS-II, for r4000 port */ -#define OP_TNE 066 /* MIPS-II, for r4000 port */ +#define OP_TGE 060 +#define OP_TGEU 061 +#define OP_TLT 062 +#define OP_TLTU 063 +#define OP_TEQ 064 +#define OP_TNE 066 -#define OP_DSLL 070 /* MIPS-II, for r4000 port */ -#define OP_DSRL 072 /* MIPS-II, for r4000 port */ -#define OP_DSRA 073 /* MIPS-II, for r4000 port */ -#define OP_DSLL32 074 /* MIPS-II, for r4000 port */ -#define OP_DSRL32 076 /* MIPS-II, for r4000 port */ -#define OP_DSRA32 077 /* MIPS-II, for r4000 port */ +#define OP_DSLL 070 +#define OP_DSRL 072 +#define OP_DSRA 073 +#define OP_DSLL32 074 +#define OP_DSRL32 076 +#define OP_DSRA32 077 +#if __mips_isa_rev < 6 /* * Values for the 'func' field when 'op' == OP_SPECIAL2. + * OP_SPECIAL2 opcodes are removed in mips32r6 */ #define OP_MAD 000 /* QED */ #define OP_MADU 001 /* QED */ #define OP_MUL 002 /* QED */ +#endif /* * Values for the 'func' field when 'op' == OP_SPECIAL3. */ #define OP_EXT 000 +#define OP_DEXTM 001 +#define OP_DEXTU 002 +#define OP_DEXT 003 #define OP_INS 004 +#define OP_DINSM 005 +#define OP_DINSU 006 +#define OP_DINS 007 #define OP_BSHFL 040 +#define OP_RDHWR 073 /* * Values for the 'shamt' field when OP_SPECIAL3 && func OP_BSHFL. */ + #define OP_WSBH 002 #define OP_SEB 020 #define OP_SEH 030 +#if __mips_isa_rev == 6 +/* + * Values for the 'shamt' field when OP_SOP30. + */ +#define OP_MUL 002 +#define OP_MUH 003 +#endif + /* * Values for the 'func' field when 'op' == OP_BCOND. */ #define OP_BLTZ 000 #define OP_BGEZ 001 -#define OP_BLTZL 002 /* MIPS-II, for r4000 port */ -#define OP_BGEZL 003 /* MIPS-II, for r4000 port */ -#define OP_TGEI 010 /* MIPS-II, for r4000 port */ -#define OP_TGEIU 011 /* MIPS-II, for r4000 port */ -#define OP_TLTI 012 /* MIPS-II, for r4000 port */ -#define OP_TLTIU 013 /* MIPS-II, for r4000 port */ -#define OP_TEQI 014 /* MIPS-II, for r4000 port */ -#define OP_TNEI 016 /* MIPS-II, for r4000 port */ - -#define OP_BLTZAL 020 /* MIPS-II, for r4000 port */ +#if __mips_isa_rev < 6 +#define OP_BLTZL 002 +#define OP_BGEZL 003 +#define OP_TGEI 010 +#define OP_TGEIU 011 +#define OP_TLTI 012 +#define OP_TLTIU 013 +#define OP_TEQI 014 +#define OP_TNEI 016 +#define OP_BLTZAL 020 #define OP_BGEZAL 021 #define OP_BLTZALL 022 #define OP_BGEZALL 023 +#else +#define OP_NAL 020 +#define OP_BAL 021 +#endif /* * Values for the 'rs' field when 'op' == OP_COPz. */ #define OP_MF 000 -#define OP_DMF 001 /* MIPS-II, for r4000 port */ +#define OP_DMF 001 #define OP_MT 004 -#define OP_DMT 005 /* MIPS-II, for r4000 port */ +#define OP_DMT 005 #define OP_BCx 010 #define OP_BCy 014 #define OP_CF 002 @@ -311,6 +405,6 @@ typedef union { #define COPz_BC_TF_MASK 0x01 #define COPz_BC_TRUE 0x01 #define COPz_BC_FALSE 0x00 -#define COPz_BCL_TF_MASK 0x02 /* MIPS-II, for r4000 port */ -#define COPz_BCL_TRUE 0x02 /* MIPS-II, for r4000 port */ -#define COPz_BCL_FALSE 0x00 /* MIPS-II, for r4000 port */ +#define COPz_BCL_TF_MASK 0x02 +#define COPz_BCL_TRUE 0x02 +#define COPz_BCL_FALSE 0x00 diff --git a/libpixelflinger/include/private/pixelflinger/ggl_context.h b/libpixelflinger/include/private/pixelflinger/ggl_context.h index a18b2f769..d45dabcd0 100644 --- a/libpixelflinger/include/private/pixelflinger/ggl_context.h +++ b/libpixelflinger/include/private/pixelflinger/ggl_context.h @@ -42,7 +42,7 @@ inline uint32_t GGL_HOST_TO_RGBA(uint32_t v) { #else inline uint32_t GGL_RGBA_TO_HOST(uint32_t v) { -#if defined(__mips__) && __mips==32 && __mips_isa_rev>=2 +#if defined(__mips__) && __mips_isa_rev>=2 uint32_t r; __asm__("wsbh %0, %1;" "rotr %0, %0, 16" @@ -55,7 +55,7 @@ inline uint32_t GGL_RGBA_TO_HOST(uint32_t v) { #endif } inline uint32_t GGL_HOST_TO_RGBA(uint32_t v) { -#if defined(__mips__) && __mips==32 && __mips_isa_rev>=2 +#if defined(__mips__) && __mips_isa_rev>=2 uint32_t r; __asm__("wsbh %0, %1;" "rotr %0, %0, 16" diff --git a/libpixelflinger/include/private/pixelflinger/ggl_fixed.h b/libpixelflinger/include/private/pixelflinger/ggl_fixed.h index 787f6202b..17b85dd58 100644 --- a/libpixelflinger/include/private/pixelflinger/ggl_fixed.h +++ b/libpixelflinger/include/private/pixelflinger/ggl_fixed.h @@ -520,6 +520,252 @@ inline int64_t gglMulii(int32_t x, int32_t y) return res; } +#elif defined(__mips__) && __mips_isa_rev == 6 + +/*inline MIPS implementations*/ +inline GGLfixed gglMulx(GGLfixed a, GGLfixed b, int shift) CONST; +inline GGLfixed gglMulx(GGLfixed a, GGLfixed b, int shift) { + GGLfixed result,tmp,tmp1,tmp2; + + if (__builtin_constant_p(shift)) { + if (shift == 0) { + asm ("mul %[res], %[a], %[b] \t\n" + : [res]"=&r"(result) + : [a]"r"(a),[b]"r"(b) + ); + } else if (shift == 32) + { + asm ("mul %[res], %[a], %[b] \t\n" + "li %[tmp],1\t\n" + "sll %[tmp],%[tmp],0x1f\t\n" + "addu %[tmp1],%[tmp],%[res] \t\n" + "muh %[res], %[a], %[b] \t\n" + "sltu %[tmp1],%[tmp1],%[tmp]\t\n" /*obit*/ + "sra %[tmp],%[tmp],0x1f \t\n" + "addu %[res],%[res],%[tmp]\t\n" + "addu %[res],%[res],%[tmp1]\t\n" + : [res]"=&r"(result),[tmp]"=&r"(tmp),[tmp1]"=&r"(tmp1) + : [a]"r"(a),[b]"r"(b),[shift]"I"(shift) + ); + } else if ((shift >0) && (shift < 32)) + { + asm ("mul %[res], %[a], %[b] \t\n" + "li %[tmp],1 \t\n" + "sll %[tmp],%[tmp],%[shiftm1] \t\n" + "addu %[tmp1],%[tmp],%[res] \t\n" + "sltu %[tmp1],%[tmp1],%[tmp] \t\n" /*obit?*/ + "addu %[res],%[res],%[tmp] \t\n" + "muh %[tmp], %[a], %[b] \t\n" + "addu %[tmp],%[tmp],%[tmp1] \t\n" + "sll %[tmp],%[tmp],%[lshift] \t\n" + "srl %[res],%[res],%[rshift] \t\n" + "or %[res],%[res],%[tmp] \t\n" + : [res]"=&r"(result),[tmp]"=&r"(tmp),[tmp1]"=&r"(tmp1),[tmp2]"=&r"(tmp2) + : [a]"r"(a),[b]"r"(b),[lshift]"I"(32-shift),[rshift]"I"(shift),[shiftm1]"I"(shift-1) + ); + } else { + asm ("mul %[res], %[a], %[b] \t\n" + "li %[tmp],1 \t\n" + "sll %[tmp],%[tmp],%[shiftm1] \t\n" + "addu %[tmp1],%[tmp],%[res] \t\n" + "sltu %[tmp1],%[tmp1],%[tmp] \t\n" /*obit?*/ + "sra %[tmp2],%[tmp],0x1f \t\n" + "addu %[res],%[res],%[tmp] \t\n" + "muh %[tmp], %[a], %[b] \t\n" + "addu %[tmp],%[tmp],%[tmp2] \t\n" + "addu %[tmp],%[tmp],%[tmp1] \t\n" /*tmp=hi*/ + "srl %[tmp2],%[res],%[rshift] \t\n" + "srav %[res], %[tmp],%[rshift]\t\n" + "sll %[tmp],%[tmp],1 \t\n" + "sll %[tmp],%[tmp],%[norbits] \t\n" + "or %[tmp],%[tmp],%[tmp2] \t\n" + "seleqz %[tmp],%[tmp],%[bit5] \t\n" + "selnez %[res],%[res],%[bit5] \t\n" + "or %[res],%[res],%[tmp] \t\n" + : [res]"=&r"(result),[tmp]"=&r"(tmp),[tmp1]"=&r"(tmp1),[tmp2]"=&r"(tmp2) + : [a]"r"(a),[b]"r"(b),[norbits]"I"(~(shift)),[rshift]"I"(shift),[shiftm1] "I"(shift-1),[bit5]"I"(shift & 0x20) + ); + } + } else { + asm ("mul %[res], %[a], %[b] \t\n" + "li %[tmp],1 \t\n" + "sll %[tmp],%[tmp],%[shiftm1] \t\n" + "addu %[tmp1],%[tmp],%[res] \t\n" + "sltu %[tmp1],%[tmp1],%[tmp] \t\n" /*obit?*/ + "sra %[tmp2],%[tmp],0x1f \t\n" + "addu %[res],%[res],%[tmp] \t\n" + "muh %[tmp], %[a], %[b] \t\n" + "addu %[tmp],%[tmp],%[tmp2] \t\n" + "addu %[tmp],%[tmp],%[tmp1] \t\n" /*tmp=hi*/ + "srl %[tmp2],%[res],%[rshift] \t\n" + "srav %[res], %[tmp],%[rshift]\t\n" + "sll %[tmp],%[tmp],1 \t\n" + "sll %[tmp],%[tmp],%[norbits] \t\n" + "or %[tmp],%[tmp],%[tmp2] \t\n" + "seleqz %[tmp],%[tmp],%[bit5] \t\n" + "selnez %[res],%[res],%[bit5] \t\n" + "or %[res],%[res],%[tmp] \t\n" + : [res]"=&r"(result),[tmp]"=&r"(tmp),[tmp1]"=&r"(tmp1),[tmp2]"=&r"(tmp2) + : [a]"r"(a),[b]"r"(b),[norbits]"r"(~(shift)),[rshift] "r"(shift),[shiftm1]"r"(shift-1),[bit5] "r"(shift & 0x20) + ); + } + return result; +} + +inline GGLfixed gglMulAddx(GGLfixed a, GGLfixed b, GGLfixed c, int shift) CONST; +inline GGLfixed gglMulAddx(GGLfixed a, GGLfixed b, GGLfixed c, int shift) { + GGLfixed result,t,tmp1,tmp2; + + if (__builtin_constant_p(shift)) { + if (shift == 0) { + asm ("mul %[lo], %[a], %[b] \t\n" + "addu %[lo],%[lo],%[c] \t\n" + : [lo]"=&r"(result) + : [a]"r"(a),[b]"r"(b),[c]"r"(c) + ); + } else if (shift == 32) { + asm ("muh %[lo], %[a], %[b] \t\n" + "addu %[lo],%[lo],%[c] \t\n" + : [lo]"=&r"(result) + : [a]"r"(a),[b]"r"(b),[c]"r"(c) + ); + } else if ((shift>0) && (shift<32)) { + asm ("mul %[res], %[a], %[b] \t\n" + "muh %[t], %[a], %[b] \t\n" + "srl %[res],%[res],%[rshift] \t\n" + "sll %[t],%[t],%[lshift] \t\n" + "or %[res],%[res],%[t] \t\n" + "addu %[res],%[res],%[c] \t\n" + : [res]"=&r"(result),[t]"=&r"(t) + : [a]"r"(a),[b]"r"(b),[c]"r"(c),[lshift]"I"(32-shift),[rshift]"I"(shift) + ); + } else { + asm ("mul %[res], %[a], %[b] \t\n" + "muh %[t], %[a], %[b] \t\n" + "nor %[tmp1],$zero,%[shift]\t\n" + "srl %[res],%[res],%[shift] \t\n" + "sll %[tmp2],%[t],1 \t\n" + "sllv %[tmp2],%[tmp2],%[tmp1] \t\n" + "or %[tmp1],%[tmp2],%[res] \t\n" + "srav %[res],%[t],%[shift] \t\n" + "andi %[tmp2],%[shift],0x20\t\n" + "seleqz %[tmp1],%[tmp1],%[tmp2]\t\n" + "selnez %[res],%[res],%[tmp2]\t\n" + "or %[res],%[res],%[tmp1]\t\n" + "addu %[res],%[res],%[c] \t\n" + : [res]"=&r"(result),[t]"=&r"(t),[tmp1]"=&r"(tmp1),[tmp2]"=&r"(tmp2) + : [a]"r"(a),[b]"r"(b),[c]"r"(c),[shift]"I"(shift) + ); + } + } else { + asm ("mul %[res], %[a], %[b] \t\n" + "muh %[t], %[a], %[b] \t\n" + "nor %[tmp1],$zero,%[shift]\t\n" + "srl %[res],%[res],%[shift] \t\n" + "sll %[tmp2],%[t],1 \t\n" + "sllv %[tmp2],%[tmp2],%[tmp1] \t\n" + "or %[tmp1],%[tmp2],%[res] \t\n" + "srav %[res],%[t],%[shift] \t\n" + "andi %[tmp2],%[shift],0x20\t\n" + "seleqz %[tmp1],%[tmp1],%[tmp2]\t\n" + "selnez %[res],%[res],%[tmp2]\t\n" + "or %[res],%[res],%[tmp1]\t\n" + "addu %[res],%[res],%[c] \t\n" + : [res]"=&r"(result),[t]"=&r"(t),[tmp1]"=&r"(tmp1),[tmp2]"=&r"(tmp2) + : [a]"r"(a),[b]"r"(b),[c]"r"(c),[shift]"r"(shift) + ); + } + return result; +} + +inline GGLfixed gglMulSubx(GGLfixed a, GGLfixed b, GGLfixed c, int shift) CONST; +inline GGLfixed gglMulSubx(GGLfixed a, GGLfixed b, GGLfixed c, int shift) { + GGLfixed result,t,tmp1,tmp2; + + if (__builtin_constant_p(shift)) { + if (shift == 0) { + asm ("mul %[lo], %[a], %[b] \t\n" + "subu %[lo],%[lo],%[c] \t\n" + : [lo]"=&r"(result) + : [a]"r"(a),[b]"r"(b),[c]"r"(c) + ); + } else if (shift == 32) { + asm ("muh %[lo], %[a], %[b] \t\n" + "subu %[lo],%[lo],%[c] \t\n" + : [lo]"=&r"(result) + : [a]"r"(a),[b]"r"(b),[c]"r"(c) + ); + } else if ((shift>0) && (shift<32)) { + asm ("mul %[res], %[a], %[b] \t\n" + "muh %[t], %[a], %[b] \t\n" + "srl %[res],%[res],%[rshift] \t\n" + "sll %[t],%[t],%[lshift] \t\n" + "or %[res],%[res],%[t] \t\n" + "subu %[res],%[res],%[c] \t\n" + : [res]"=&r"(result),[t]"=&r"(t) + : [a]"r"(a),[b]"r"(b),[c]"r"(c),[lshift]"I"(32-shift),[rshift]"I"(shift) + ); + } else { + asm ("mul %[res], %[a], %[b] \t\n" + "muh %[t], %[a], %[b] \t\n" + "nor %[tmp1],$zero,%[shift]\t\n" + "srl %[res],%[res],%[shift] \t\n" + "sll %[tmp2],%[t],1 \t\n" + "sllv %[tmp2],%[tmp2],%[tmp1] \t\n" + "or %[tmp1],%[tmp2],%[res] \t\n" + "srav %[res],%[t],%[shift] \t\n" + "andi %[tmp2],%[shift],0x20\t\n" + "seleqz %[tmp1],%[tmp1],%[tmp2]\t\n" + "selnez %[res],%[res],%[tmp2]\t\n" + "or %[res],%[res],%[tmp1]\t\n" + "subu %[res],%[res],%[c] \t\n" + : [res]"=&r"(result),[t]"=&r"(t),[tmp1]"=&r"(tmp1),[tmp2]"=&r"(tmp2) + : [a]"r"(a),[b]"r"(b),[c]"r"(c),[shift]"I"(shift) + ); + } + } else { + asm ("mul %[res], %[a], %[b] \t\n" + "muh %[t], %[a], %[b] \t\n" + "nor %[tmp1],$zero,%[shift]\t\n" + "srl %[res],%[res],%[shift] \t\n" + "sll %[tmp2],%[t],1 \t\n" + "sllv %[tmp2],%[tmp2],%[tmp1] \t\n" + "or %[tmp1],%[tmp2],%[res] \t\n" + "srav %[res],%[t],%[shift] \t\n" + "andi %[tmp2],%[shift],0x20\t\n" + "seleqz %[tmp1],%[tmp1],%[tmp2]\t\n" + "selnez %[res],%[res],%[tmp2]\t\n" + "or %[res],%[res],%[tmp1]\t\n" + "subu %[res],%[res],%[c] \t\n" + : [res]"=&r"(result),[t]"=&r"(t),[tmp1]"=&r"(tmp1),[tmp2]"=&r"(tmp2) + : [a]"r"(a),[b]"r"(b),[c]"r"(c),[shift]"r"(shift) + ); + } + return result; +} + +inline int64_t gglMulii(int32_t x, int32_t y) CONST; +inline int64_t gglMulii(int32_t x, int32_t y) { + union { + struct { +#if defined(__MIPSEL__) + int32_t lo; + int32_t hi; +#elif defined(__MIPSEB__) + int32_t hi; + int32_t lo; +#endif + } s; + int64_t res; + }u; + asm("mul %0, %2, %3 \t\n" + "muh %1, %2, %3 \t\n" + : "=r"(u.s.lo), "=&r"(u.s.hi) + : "%r"(x), "r"(y) + ); + return u.res; +} + #else // ---------------------------------------------------------------------- inline GGLfixed gglMulx(GGLfixed a, GGLfixed b, int shift) CONST; diff --git a/libpixelflinger/scanline.cpp b/libpixelflinger/scanline.cpp index 3d145319a..a718b02c6 100644 --- a/libpixelflinger/scanline.cpp +++ b/libpixelflinger/scanline.cpp @@ -41,6 +41,8 @@ #include "codeflinger/Arm64Assembler.h" #elif defined(__mips__) && !defined(__LP64__) && __mips_isa_rev < 6 #include "codeflinger/MIPSAssembler.h" +#elif defined(__mips__) && defined(__LP64__) +#include "codeflinger/MIPS64Assembler.h" #endif //#include "codeflinger/ARMAssemblerOptimizer.h" @@ -59,7 +61,7 @@ # define ANDROID_CODEGEN ANDROID_CODEGEN_GENERATED #endif -#if defined(__arm__) || (defined(__mips__) && !defined(__LP64__) && __mips_isa_rev < 6) || defined(__aarch64__) +#if defined(__arm__) || (defined(__mips__) && ((!defined(__LP64__) && __mips_isa_rev < 6) || defined(__LP64__))) || defined(__aarch64__) # define ANDROID_ARM_CODEGEN 1 #else # define ANDROID_ARM_CODEGEN 0 @@ -73,7 +75,7 @@ */ #define DEBUG_NEEDS 0 -#if defined( __mips__) && !defined(__LP64__) && __mips_isa_rev < 6 +#if defined( __mips__) && ((!defined(__LP64__) && __mips_isa_rev < 6) || defined(__LP64__)) #define ASSEMBLY_SCRATCH_SIZE 4096 #elif defined(__aarch64__) #define ASSEMBLY_SCRATCH_SIZE 8192 @@ -136,6 +138,9 @@ extern "C" void scanline_t32cb16blend_arm64(uint16_t*, uint32_t*, size_t); extern "C" void scanline_col32cb16blend_arm64(uint16_t *dst, uint32_t col, size_t ct); #elif defined(__mips__) && !defined(__LP64__) && __mips_isa_rev < 6 extern "C" void scanline_t32cb16blend_mips(uint16_t*, uint32_t*, size_t); +#elif defined(__mips__) && defined(__LP64__) +extern "C" void scanline_t32cb16blend_mips64(uint16_t*, uint32_t*, size_t); +extern "C" void scanline_col32cb16blend_mips64(uint16_t *dst, uint32_t col, size_t ct); #endif // ---------------------------------------------------------------------------- @@ -286,7 +291,7 @@ static const needs_filter_t fill16noblend = { #if ANDROID_ARM_CODEGEN -#if defined(__mips__) && !defined(__LP64__) && __mips_isa_rev < 6 +#if defined(__mips__) && ((!defined(__LP64__) && __mips_isa_rev < 6) || defined(__LP64__)) static CodeCache gCodeCache(32 * 1024); #elif defined(__aarch64__) static CodeCache gCodeCache(48 * 1024); @@ -406,8 +411,10 @@ static void pick_scanline(context_t* c) //GGLAssembler assembler( // new ARMAssemblerOptimizer(new ARMAssembler(a)) ); #endif -#if defined(__mips__) +#if defined(__mips__) && !defined(__LP64__) && __mips_isa_rev < 6 GGLAssembler assembler( new ArmToMipsAssembler(a) ); +#elif defined(__mips__) && defined(__LP64__) + GGLAssembler assembler( new ArmToMips64Assembler(a) ); #elif defined(__aarch64__) GGLAssembler assembler( new ArmToArm64Assembler(a) ); #endif @@ -2103,6 +2110,8 @@ void scanline_col32cb16blend(context_t* c) #endif // defined(__ARM_HAVE_NEON) && BYTE_ORDER == LITTLE_ENDIAN #elif ((ANDROID_CODEGEN >= ANDROID_CODEGEN_ASM) && defined(__aarch64__)) scanline_col32cb16blend_arm64(dst, GGL_RGBA_TO_HOST(c->packed8888), ct); +#elif ((ANDROID_CODEGEN >= ANDROID_CODEGEN_ASM) && (defined(__mips__) && defined(__LP64__))) + scanline_col32cb16blend_mips64(dst, GGL_RGBA_TO_HOST(c->packed8888), ct); #else uint32_t s = GGL_RGBA_TO_HOST(c->packed8888); int sA = (s>>24); @@ -2175,7 +2184,8 @@ last_one: void scanline_t32cb16blend(context_t* c) { -#if ((ANDROID_CODEGEN >= ANDROID_CODEGEN_ASM) && (defined(__arm__) || (defined(__mips__) && !defined(__LP64__) && __mips_isa_rev < 6) || defined(__aarch64__))) +#if ((ANDROID_CODEGEN >= ANDROID_CODEGEN_ASM) && (defined(__arm__) || defined(__aarch64__) || \ + (defined(__mips__) && ((!defined(__LP64__) && __mips_isa_rev < 6) || defined(__LP64__))))) int32_t x = c->iterators.xl; size_t ct = c->iterators.xr - x; int32_t y = c->iterators.y; @@ -2191,8 +2201,10 @@ void scanline_t32cb16blend(context_t* c) scanline_t32cb16blend_arm(dst, src, ct); #elif defined(__aarch64__) scanline_t32cb16blend_arm64(dst, src, ct); -#elif defined(__mips__) +#elif defined(__mips__) && !defined(__LP64__) && __mips_isa_rev < 6 scanline_t32cb16blend_mips(dst, src, ct); +#elif defined(__mips__) && defined(__LP64__) + scanline_t32cb16blend_mips64(dst, src, ct); #endif #else dst_iterator16 di(c); diff --git a/libpixelflinger/tests/arch-mips/Android.mk b/libpixelflinger/tests/arch-mips/Android.mk new file mode 100644 index 000000000..fe6979ef6 --- /dev/null +++ b/libpixelflinger/tests/arch-mips/Android.mk @@ -0,0 +1,6 @@ +ifeq ($(TARGET_ARCH),mips) +include $(all-subdir-makefiles) +endif +ifeq ($(TARGET_ARCH),mipsel) +include $(all-subdir-makefiles) +endif diff --git a/libpixelflinger/tests/arch-mips/col32cb16blend/Android.mk b/libpixelflinger/tests/arch-mips/col32cb16blend/Android.mk new file mode 100644 index 000000000..40f197f3b --- /dev/null +++ b/libpixelflinger/tests/arch-mips/col32cb16blend/Android.mk @@ -0,0 +1,18 @@ +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_SRC_FILES:= \ + col32cb16blend_test.c \ + ../../../arch-mips/col32cb16blend.S + +LOCAL_SHARED_LIBRARIES := + +LOCAL_C_INCLUDES := + +LOCAL_MODULE:= test-pixelflinger-mips-col32cb16blend + +LOCAL_MODULE_TAGS := tests + +LOCAL_MULTILIB := 32 + +include $(BUILD_NATIVE_TEST) diff --git a/libpixelflinger/tests/arch-mips/col32cb16blend/col32cb16blend_test.c b/libpixelflinger/tests/arch-mips/col32cb16blend/col32cb16blend_test.c new file mode 100644 index 000000000..dd0e60fef --- /dev/null +++ b/libpixelflinger/tests/arch-mips/col32cb16blend/col32cb16blend_test.c @@ -0,0 +1,125 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include + + +#define ARGB_8888_MAX 0xFFFFFFFF +#define ARGB_8888_MIN 0x00000000 +#define RGB_565_MAX 0xFFFF +#define RGB_565_MIN 0x0000 + +struct test_t +{ + char name[256]; + uint32_t src_color; + uint16_t dst_color; + size_t count; +}; + +struct test_t tests[] = +{ + {"Count 1, Src=Max, Dst=Min", ARGB_8888_MAX, RGB_565_MIN, 1}, + {"Count 2, Src=Min, Dst=Max", ARGB_8888_MIN, RGB_565_MAX, 2}, + {"Count 3, Src=Max, Dst=Max", ARGB_8888_MAX, RGB_565_MAX, 3}, + {"Count 4, Src=Min, Dst=Min", ARGB_8888_MAX, RGB_565_MAX, 4}, + {"Count 1, Src=Rand, Dst=Rand", 0x12345678, 0x9ABC, 1}, + {"Count 2, Src=Rand, Dst=Rand", 0xABCDEF12, 0x2345, 2}, + {"Count 3, Src=Rand, Dst=Rand", 0x11111111, 0xEDFE, 3}, + {"Count 4, Src=Rand, Dst=Rand", 0x12345678, 0x9ABC, 4}, + {"Count 5, Src=Rand, Dst=Rand", 0xEFEFFEFE, 0xFACC, 5}, + {"Count 10, Src=Rand, Dst=Rand", 0x12345678, 0x9ABC, 10} +}; + +void scanline_col32cb16blend_mips(uint16_t *dst, uint32_t src, size_t count); +void scanline_col32cb16blend_c(uint16_t * dst, uint32_t src, size_t count) +{ + uint32_t srcAlpha = (src>>24); + uint32_t f = 0x100 - (srcAlpha + (srcAlpha>>7)); + + while (count--) + { + uint16_t d = *dst; + int dstR = (d>>11)&0x1f; + int dstG = (d>>5)&0x3f; + int dstB = (d)&0x1f; + int srcR = (src >> ( 3))&0x1F; + int srcG = (src >> ( 8+2))&0x3F; + int srcB = (src >> (16+3))&0x1F; + srcR += (f*dstR)>>8; + srcG += (f*dstG)>>8; + srcB += (f*dstB)>>8; + *dst++ = (uint16_t)((srcR<<11)|(srcG<<5)|srcB); + } +} + +void scanline_col32cb16blend_test() +{ + uint16_t dst_c[16], dst_asm[16]; + uint32_t i, j; + + for(i = 0; i < sizeof(tests)/sizeof(struct test_t); ++i) + { + struct test_t test = tests[i]; + + printf("Testing - %s:",test.name); + + memset(dst_c, 0, sizeof(dst_c)); + memset(dst_asm, 0, sizeof(dst_asm)); + + for(j = 0; j < test.count; ++j) + { + dst_c[j] = test.dst_color; + dst_asm[j] = test.dst_color; + } + + + scanline_col32cb16blend_c(dst_c, test.src_color, test.count); + scanline_col32cb16blend_mips(dst_asm, test.src_color, test.count); + + if(memcmp(dst_c, dst_asm, sizeof(dst_c)) == 0) + printf("Passed\n"); + else + printf("Failed\n"); + + for(j = 0; j < test.count; ++j) + { + printf("dst_c[%d] = %x, dst_asm[%d] = %x \n", j, dst_c[j], j, dst_asm[j]); + } + } +} + +int main() +{ + scanline_col32cb16blend_test(); + return 0; +} diff --git a/libpixelflinger/tests/arch-mips/t32cb16blend/Android.mk b/libpixelflinger/tests/arch-mips/t32cb16blend/Android.mk new file mode 100644 index 000000000..d0c0ae4dc --- /dev/null +++ b/libpixelflinger/tests/arch-mips/t32cb16blend/Android.mk @@ -0,0 +1,18 @@ +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_SRC_FILES:= \ + t32cb16blend_test.c \ + ../../../arch-mips/t32cb16blend.S + +LOCAL_SHARED_LIBRARIES := + +LOCAL_C_INCLUDES := + +LOCAL_MODULE:= test-pixelflinger-mips-t32cb16blend + +LOCAL_MODULE_TAGS := tests + +LOCAL_MULTILIB := 32 + +include $(BUILD_NATIVE_TEST) diff --git a/libpixelflinger/tests/arch-mips/t32cb16blend/t32cb16blend_test.c b/libpixelflinger/tests/arch-mips/t32cb16blend/t32cb16blend_test.c new file mode 100644 index 000000000..c6d6937c6 --- /dev/null +++ b/libpixelflinger/tests/arch-mips/t32cb16blend/t32cb16blend_test.c @@ -0,0 +1,134 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include + +#define ARGB_8888_MAX 0xFFFFFFFF +#define ARGB_8888_MIN 0x00000000 +#define RGB_565_MAX 0xFFFF +#define RGB_565_MIN 0x0000 + +struct test_t +{ + char name[256]; + uint32_t src_color; + uint16_t dst_color; + size_t count; +}; + +struct test_t tests[] = +{ + {"Count 0", 0, 0, 0}, + {"Count 1, Src=Max, Dst=Min", ARGB_8888_MAX, RGB_565_MIN, 1}, + {"Count 2, Src=Min, Dst=Max", ARGB_8888_MIN, RGB_565_MAX, 2}, + {"Count 3, Src=Max, Dst=Max", ARGB_8888_MAX, RGB_565_MAX, 3}, + {"Count 4, Src=Min, Dst=Min", ARGB_8888_MAX, RGB_565_MAX, 4}, + {"Count 1, Src=Rand, Dst=Rand", 0x12345678, 0x9ABC, 1}, + {"Count 2, Src=Rand, Dst=Rand", 0xABCDEF12, 0x2345, 2}, + {"Count 3, Src=Rand, Dst=Rand", 0x11111111, 0xEDFE, 3}, + {"Count 4, Src=Rand, Dst=Rand", 0x12345678, 0x9ABC, 4}, + {"Count 5, Src=Rand, Dst=Rand", 0xEFEFFEFE, 0xFACC, 5}, + {"Count 10, Src=Rand, Dst=Rand", 0x12345678, 0x9ABC, 10} + +}; + +void scanline_t32cb16blend_mips(uint16_t*, uint32_t*, size_t); +void scanline_t32cb16blend_c(uint16_t * dst, uint32_t* src, size_t count) +{ + while (count--) + { + uint16_t d = *dst; + uint32_t s = *src++; + int dstR = (d>>11)&0x1f; + int dstG = (d>>5)&0x3f; + int dstB = (d)&0x1f; + int srcR = (s >> ( 3))&0x1F; + int srcG = (s >> ( 8+2))&0x3F; + int srcB = (s >> (16+3))&0x1F; + int srcAlpha = (s>>24) & 0xFF; + + + int f = 0x100 - (srcAlpha + ((srcAlpha>>7) & 0x1)); + srcR += (f*dstR)>>8; + srcG += (f*dstG)>>8; + srcB += (f*dstB)>>8; + // srcR = srcR > 0x1F? 0x1F: srcR; + // srcG = srcG > 0x3F? 0x3F: srcG; + // srcB = srcB > 0x1F? 0x1F: srcB; + *dst++ = (uint16_t)((srcR<<11)|(srcG<<5)|srcB); + } +} + +void scanline_t32cb16blend_test() +{ + uint16_t dst_c[16], dst_asm[16]; + uint32_t src[16]; + uint32_t i; + uint32_t j; + + for(i = 0; i < sizeof(tests)/sizeof(struct test_t); ++i) + { + struct test_t test = tests[i]; + + printf("Testing - %s:",test.name); + + memset(dst_c, 0, sizeof(dst_c)); + memset(dst_asm, 0, sizeof(dst_asm)); + + for(j = 0; j < test.count; ++j) + { + dst_c[j] = test.dst_color; + dst_asm[j] = test.dst_color; + src[j] = test.src_color; + } + + scanline_t32cb16blend_c(dst_c,src,test.count); + scanline_t32cb16blend_mips(dst_asm,src,test.count); + + + if(memcmp(dst_c, dst_asm, sizeof(dst_c)) == 0) + printf("Passed\n"); + else + printf("Failed\n"); + + for(j = 0; j < test.count; ++j) + { + printf("dst_c[%d] = %x, dst_asm[%d] = %x \n", j, dst_c[j], j, dst_asm[j]); + } + } +} + +int main() +{ + scanline_t32cb16blend_test(); + return 0; +} diff --git a/libpixelflinger/tests/arch-mips64/Android.mk b/libpixelflinger/tests/arch-mips64/Android.mk new file mode 100644 index 000000000..3b1c64ec2 --- /dev/null +++ b/libpixelflinger/tests/arch-mips64/Android.mk @@ -0,0 +1,3 @@ +ifeq ($(TARGET_ARCH),mips64) +include $(all-subdir-makefiles) +endif diff --git a/libpixelflinger/tests/arch-mips64/assembler/Android.mk b/libpixelflinger/tests/arch-mips64/assembler/Android.mk new file mode 100644 index 000000000..469996126 --- /dev/null +++ b/libpixelflinger/tests/arch-mips64/assembler/Android.mk @@ -0,0 +1,21 @@ +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_SRC_FILES:= \ + mips64_assembler_test.cpp\ + asm_mips_test_jacket.S + +LOCAL_SHARED_LIBRARIES := \ + libcutils \ + libpixelflinger + +LOCAL_C_INCLUDES := \ + $(LOCAL_PATH)/../../.. + +LOCAL_MODULE:= test-pixelflinger-mips64-assembler-test + +LOCAL_MODULE_TAGS := tests + +LOCAL_MULTILIB := 64 + +include $(BUILD_NATIVE_TEST) diff --git a/libpixelflinger/tests/arch-mips64/assembler/asm_mips_test_jacket.S b/libpixelflinger/tests/arch-mips64/assembler/asm_mips_test_jacket.S new file mode 100644 index 000000000..8a7f74202 --- /dev/null +++ b/libpixelflinger/tests/arch-mips64/assembler/asm_mips_test_jacket.S @@ -0,0 +1,93 @@ +# /* +# * Copyright (C) 2015 The Android Open Source Project +# * All rights reserved. +# * +# * Redistribution and use in source and binary forms, with or without +# * modification, are permitted provided that the following conditions +# * are met: +# * * Redistributions of source code must retain the above copyright +# * notice, this list of conditions and the following disclaimer. +# * * Redistributions in binary form must reproduce the above copyright +# * notice, this list of conditions and the following disclaimer in +# * the documentation and/or other materials provided with the +# * distribution. +# * +# * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +# * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +# * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT +# * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# * SUCH DAMAGE. +# */ + + .text + .align 8 + + .global asm_mips_test_jacket + + # // Set the register + # // Calls the asm function + # // Reads the register values to output register + + # // Parameters + # // a0 - Function to jump + # // a1 - register values array + # // a2 - flag values array +asm_mips_test_jacket: + # // Save registers to stack + daddiu $sp, $sp, -96 + sd $s0, 64($sp) + sd $s1, 72($sp) + sd $s2, 80($sp) + sd $ra, 88($sp) + + move $s0, $a0 + move $s1, $a1 + move $s2, $a2 + + ld $v0, 16($s1) + ld $v1, 24($s1) + ld $a0, 32($s1) + ld $a1, 40($s1) + ld $a2, 48($s1) + ld $a3, 56($s1) + ld $a4, 64($s1) + ld $a5, 72($s1) + ld $a6, 80($s1) + ld $a7, 88($s1) + ld $t0, 96($s1) + ld $t1, 104($s1) + ld $t2, 112($s1) + ld $t3, 120($s1) + + jal $s0 + + sd $v0, 16($s1) + sd $v1, 24($s1) + sd $a0, 32($s1) + sd $a1, 40($s1) + sd $a2, 48($s1) + sd $a3, 56($s1) + sd $a4, 64($s1) + sd $a5, 72($s1) + sd $a6, 80($s1) + sd $a7, 88($s1) + sd $t0, 96($s1) + sd $t1, 104($s1) + sd $t2, 112($s1) + sd $t3, 120($s1) + + ld $s0, 64($sp) + ld $s1, 72($sp) + ld $s2, 80($sp) + ld $ra, 88($sp) + + daddiu $sp, $sp, 96 + + j $ra diff --git a/libpixelflinger/tests/arch-mips64/assembler/mips64_assembler_test.cpp b/libpixelflinger/tests/arch-mips64/assembler/mips64_assembler_test.cpp new file mode 100644 index 000000000..2b25223de --- /dev/null +++ b/libpixelflinger/tests/arch-mips64/assembler/mips64_assembler_test.cpp @@ -0,0 +1,644 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#define __STDC_FORMAT_MACROS +#include + +#include "codeflinger/ARMAssemblerInterface.h" +#include "codeflinger/MIPS64Assembler.h" +using namespace android; + +#define TESTS_DATAOP_ENABLE 1 +#define TESTS_DATATRANSFER_ENABLE 1 +#define ASSEMBLY_SCRATCH_SIZE 4096 + +void *instrMem; +uint32_t instrMemSize = 128 * 1024; +char dataMem[8192]; + +typedef void (*asm_function_t)(); +extern "C" void asm_mips_test_jacket(asm_function_t function, + int64_t regs[], int32_t flags[]); + +#define MAX_32BIT (uint32_t)(((uint64_t)1 << 32) - 1) +#define MAX_64BIT ((uint64_t)0xFFFFFFFFFFFFFFFF) +const uint32_t NA = 0; +const uint32_t NUM_REGS = 32; +const uint32_t NUM_FLAGS = 16; + +enum instr_t +{ + INSTR_ADD, + INSTR_SUB, + INSTR_AND, + INSTR_ORR, + INSTR_RSB, + INSTR_BIC, + INSTR_CMP, + INSTR_MOV, + INSTR_MVN, + INSTR_MUL, + INSTR_MLA, + INSTR_SMULBB, + INSTR_SMULBT, + INSTR_SMULTB, + INSTR_SMULTT, + INSTR_SMULWB, + INSTR_SMULWT, + INSTR_SMLABB, + INSTR_UXTB16, + INSTR_UBFX, + INSTR_ADDR_ADD, + INSTR_ADDR_SUB, + INSTR_LDR, + INSTR_LDRB, + INSTR_LDRH, + INSTR_ADDR_LDR, + INSTR_LDM, + INSTR_STR, + INSTR_STRB, + INSTR_STRH, + INSTR_ADDR_STR, + INSTR_STM +}; + +enum shift_t +{ + SHIFT_LSL, + SHIFT_LSR, + SHIFT_ASR, + SHIFT_ROR, + SHIFT_NONE +}; + +enum offset_t +{ + REG_SCALE_OFFSET, + REG_OFFSET, + IMM8_OFFSET, + IMM12_OFFSET, + NO_OFFSET +}; + +enum cond_t +{ + EQ, NE, CS, CC, MI, PL, VS, VC, HI, LS, GE, LT, GT, LE, AL, NV, + HS = CS, + LO = CC +}; + +const char * cc_code[] = +{ + "EQ", "NE", "CS", "CC", "MI", "PL", "VS", "VC", + "HI", "LS","GE","LT", "GT", "LE", "AL", "NV" +}; + +struct condTest_t +{ + int mode; + int32_t Rcond1; + int32_t Rcond2; + uint64_t Rcond1Value; + uint64_t Rcond2Value; +}; + + +struct dataOpTest_t +{ + uint32_t id; + instr_t op; + condTest_t preCond; + cond_t cond; + bool setFlags; + uint64_t RnValue; + uint64_t RsValue; + bool immediate; + uint32_t immValue; + uint64_t RmValue; + uint32_t shiftMode; + uint32_t shiftAmount; + uint64_t RdValue; + bool checkRd; + uint64_t postRdValue; +}; + +struct dataTransferTest_t +{ + uint32_t id; + instr_t op; + uint32_t preFlag; + cond_t cond; + bool setMem; + uint64_t memOffset; + uint64_t memValue; + uint64_t RnValue; + offset_t offsetType; + uint64_t RmValue; + uint32_t immValue; + bool writeBack; + bool preIndex; + bool postIndex; + uint64_t RdValue; + uint64_t postRdValue; + uint64_t postRnValue; + bool checkMem; + uint64_t postMemOffset; + uint32_t postMemLength; + uint64_t postMemValue; +}; + + +dataOpTest_t dataOpTests [] = +{ + {0xA000,INSTR_ADD,{0,0,0,0,0},AL,0,1,NA,1,MAX_32BIT,NA,NA,NA,NA,1,0}, + {0xA001,INSTR_ADD,{0,0,0,0,0},AL,0,1,NA,1,MAX_32BIT-1,NA,NA,NA,NA,1,MAX_64BIT}, + {0xA002,INSTR_ADD,{0,0,0,0,0},AL,0,1,NA,0,NA,MAX_32BIT,NA,NA,NA,1,0}, + {0xA003,INSTR_ADD,{0,0,0,0,0},AL,0,1,NA,0,NA,MAX_32BIT-1,NA,NA,NA,1,MAX_64BIT}, + {0xA004,INSTR_ADD,{0,0,0,0,0},AL,0,1,NA,0,0,MAX_32BIT,SHIFT_LSL, 0,NA,1,0}, + {0xA005,INSTR_ADD,{0,0,0,0,0},AL,0,1,NA,0,0,MAX_32BIT,SHIFT_LSL,31,NA,1,0xFFFFFFFF80000001}, + {0xA006,INSTR_ADD,{0,0,0,0,0},AL,0,1,NA,0,0,3,SHIFT_LSR,1,NA,1,2}, + {0xA007,INSTR_ADD,{0,0,0,0,0},AL,0,1,NA,0,0,MAX_32BIT,SHIFT_LSR,31,NA,1,2}, + {0xA008,INSTR_ADD,{0,0,0,0,0},AL,0,0,NA,0,0,3,SHIFT_ASR,1,NA,1,1}, + {0xA009,INSTR_ADD,{0,0,0,0,0},AL,0,1,NA,0,0,MAX_64BIT,SHIFT_ASR,31,NA,1,0}, + {0xA010,INSTR_AND,{0,0,0,0,0},AL,0,1,NA,1,MAX_32BIT,0,0,0,NA,1,1}, + {0xA011,INSTR_AND,{0,0,0,0,0},AL,0,1,NA,1,MAX_32BIT-1,0,0,0,NA,1,0}, + {0xA012,INSTR_AND,{0,0,0,0,0},AL,0,1,NA,0,0,MAX_32BIT,0,0,NA,1,1}, + {0xA013,INSTR_AND,{0,0,0,0,0},AL,0,1,NA,0,0,MAX_32BIT-1,0,0,NA,1,0}, + {0xA014,INSTR_AND,{0,0,0,0,0},AL,0,1,NA,0,0,MAX_32BIT,SHIFT_LSL,0,NA,1,1}, + {0xA015,INSTR_AND,{0,0,0,0,0},AL,0,1,NA,0,0,MAX_32BIT,SHIFT_LSL,31,NA,1,0}, + {0xA016,INSTR_AND,{0,0,0,0,0},AL,0,1,NA,0,0,3,SHIFT_LSR,1,NA,1,1}, + {0xA017,INSTR_AND,{0,0,0,0,0},AL,0,1,NA,0,0,MAX_32BIT,SHIFT_LSR,31,NA,1,1}, + {0xA018,INSTR_AND,{0,0,0,0,0},AL,0,0,NA,0,0,3,SHIFT_ASR,1,NA,1,0}, + {0xA019,INSTR_AND,{0,0,0,0,0},AL,0,1,NA,0,0,MAX_32BIT,SHIFT_ASR,31,NA,1,1}, + {0xA020,INSTR_ORR,{0,0,0,0,0},AL,0,3,NA,1,MAX_32BIT,0,0,0,NA,1,MAX_64BIT}, + {0xA021,INSTR_ORR,{0,0,0,0,0},AL,0,2,NA,1,MAX_32BIT-1,0,0,0,NA,1,MAX_64BIT-1}, + {0xA022,INSTR_ORR,{0,0,0,0,0},AL,0,3,NA,0,0,MAX_32BIT,0,0,NA,1,MAX_64BIT}, + {0xA023,INSTR_ORR,{0,0,0,0,0},AL,0,2,NA,0,0,MAX_32BIT-1,0,0,NA,1,MAX_64BIT-1}, + {0xA024,INSTR_ORR,{0,0,0,0,0},AL,0,1,NA,0,0,MAX_32BIT,SHIFT_LSL,0,NA,1,MAX_64BIT}, + {0xA025,INSTR_ORR,{0,0,0,0,0},AL,0,1,NA,0,0,MAX_32BIT,SHIFT_LSL,31,NA,1,0xFFFFFFFF80000001}, + {0xA026,INSTR_ORR,{0,0,0,0,0},AL,0,1,NA,0,0,3,SHIFT_LSR,1,NA,1,1}, + {0xA027,INSTR_ORR,{0,0,0,0,0},AL,0,0,NA,0,0,MAX_32BIT,SHIFT_LSR,31,NA,1,1}, + {0xA028,INSTR_ORR,{0,0,0,0,0},AL,0,0,NA,0,0,3,SHIFT_ASR,1,NA,1,1}, + {0xA029,INSTR_ORR,{0,0,0,0,0},AL,0,1,NA,0,0,MAX_64BIT,SHIFT_ASR,31,NA,1,MAX_64BIT}, + {0xA030,INSTR_CMP,{0,0,0,0,0},AL,1,0x10000,NA,1,0x10000,0,0,0,NA,0,0}, + {0xA031,INSTR_MUL,{0,0,0,0,0},AL,0,0,0x10000,0,0,0x10000,0,0,NA,1,0}, + {0xA032,INSTR_MUL,{0,0,0,0,0},AL,0,0,0x1000,0,0,0x10000,0,0,NA,1,0x10000000}, + {0xA033,INSTR_MUL,{0,0,0,0,0},AL,0,0,MAX_32BIT,0,0,1,0,0,NA,1,MAX_64BIT}, + {0xA034,INSTR_MLA,{0,0,0,0,0},AL,0,0x10000,0x10000,0,0,0x10000,0,0,NA,1,0x10000}, + {0xA035,INSTR_MLA,{0,0,0,0,0},AL,0,0x10000,0x1000,0,0,0x10000,0,0,NA,1,0x10010000}, + {0xA036,INSTR_SUB,{1,R_v1,R_a6,2,4},MI,0,2,NA,0,NA,1,NA,NA,2,1,1}, + {0xA037,INSTR_SUB,{2,R_v1,R_a6,2,0},MI,0,2,NA,0,NA,1,NA,NA,2,1,2}, + {0xA038,INSTR_SUB,{1,R_v1,R_a6,4,2},GE,0,2,NA,1,1,NA,NA,NA,2,1,1}, + {0xA039,INSTR_SUB,{1,R_a5,R_a6,2,7},GE,0,2,NA,1,1,NA,NA,NA,2,1,2}, + {0xA040,INSTR_SUB,{1,R_a5,R_a6,1,1},HS,0,2,NA,1,1,NA,NA,NA,2,1,1}, + {0xA041,INSTR_SUB,{1,R_a5,R_a6,0,1},HS,0,2,NA,1,1,NA,NA,NA,2,1,2}, + {0xA042,INSTR_SUB,{0,0,0,0,0},AL,0,1,NA,1,1<< 16,0,0,0,NA,1,(uint64_t)(1 -(1<<16))}, + {0xA043,INSTR_SUB,{0,0,0,0,0},AL,0,MAX_32BIT,NA,1,1,0,0,0,NA,1,MAX_64BIT-1}, + {0xA044,INSTR_SUB,{0,0,0,0,0},AL,0,1,NA,1,1,0,0,0,NA,1,0}, + {0xA045,INSTR_SUB,{0,0,0,0,0},AL,0,1,NA,0,NA,1<<16,0,0,NA,1,(uint64_t)(1 -(1<<16))}, + {0xA046,INSTR_SUB,{0,0,0,0,0},AL,0,MAX_32BIT,NA,0,NA,1,0,0,NA,1,MAX_64BIT-1}, + {0xA047,INSTR_SUB,{0,0,0,0,0},AL,0,1,NA,0,NA,1,0,0,NA,1,0}, + {0xA048,INSTR_SUB,{0,0,0,0,0},AL,0,1,NA,0,NA,1,SHIFT_LSL,16,NA,1,(uint64_t)(1 -(1<<16))}, + {0xA049,INSTR_SUB,{0,0,0,0,0},AL,0,0x80000001,NA,0,NA,MAX_32BIT,SHIFT_LSL,31,NA,1,1}, + {0xA050,INSTR_SUB,{0,0,0,0,0},AL,0,1,NA,0,NA,3,SHIFT_LSR,1,NA,1,0}, + {0xA051,INSTR_SUB,{0,0,0,0,0},AL,0,1,NA,0,NA,MAX_32BIT,SHIFT_LSR,31,NA,1,0}, + {0xA052,INSTR_RSB,{1,R_a5,R_a6,4,1},GE,0,2,NA,1,0,NA,NA,NA,2,1,(uint64_t)-2}, + {0xA053,INSTR_RSB,{1,R_a5,R_a6,-1,1},GE,0,2,NA,1,0,NA,NA,NA,2,1,2}, + {0xA054,INSTR_RSB,{0,0,0,0,0},AL,0,1,NA,1,1<<16,NA,NA,NA,NA,1,(1<<16)-1}, + {0xA055,INSTR_RSB,{0,0,0,0,0},AL,0,MAX_32BIT,NA,1,1,NA,NA,NA,NA,1,(uint64_t)(1-MAX_64BIT)}, + {0xA056,INSTR_RSB,{0,0,0,0,0},AL,0,1,NA,1,1,NA,NA,NA,NA,1,0}, + {0xA057,INSTR_RSB,{0,0,0,0,0},AL,0,1,NA,0,NA,1<<16,0,0,NA,1,(1<<16)-1}, + {0xA058,INSTR_RSB,{0,0,0,0,0},AL,0,MAX_32BIT,NA,0,NA,1,0,0,NA,1,(uint64_t)(1-MAX_64BIT)}, + {0xA059,INSTR_RSB,{0,0,0,0,0},AL,0,1,NA,0,NA,1,0,0,NA,1,0}, + {0xA060,INSTR_RSB,{0,0,0,0,0},AL,0,1,NA,0,NA,1,SHIFT_LSL,16,NA,1,(1<<16)-1}, + {0xA061,INSTR_RSB,{0,0,0,0,0},AL,0,0x80000001,NA,0,NA,MAX_32BIT ,SHIFT_LSL,31,NA,1,(uint64_t)(-1)}, + {0xA062,INSTR_RSB,{0,0,0,0,0},AL,0,1,NA,0,NA,3,SHIFT_LSR,1,NA,1,0}, + {0xA063,INSTR_RSB,{0,0,0,0,0},AL,0,1,NA,0,NA,MAX_32BIT,SHIFT_LSR,31,NA,1,0}, + {0xA064,INSTR_MOV,{0,0,0,0,0},AL,0,NA,NA,1,0x80000001,NA,NA,NA,NA,1,0xFFFFFFFF80000001}, + {0xA065,INSTR_MOV,{0,0,0,0,0},AL,0,NA,NA,0,0,0x80000001,0,0,NA,1,0xFFFFFFFF80000001}, + {0xA066,INSTR_MOV,{0,0,0,0,0},AL,0,NA,NA,0,0,MAX_32BIT,SHIFT_LSL,1,NA,1,MAX_64BIT-1}, + {0xA067,INSTR_MOV,{0,0,0,0,0},AL,0,NA,NA,0,0,MAX_32BIT,SHIFT_LSL,31,NA,1,0xFFFFFFFF80000000}, + {0xA068,INSTR_MOV,{0,0,0,0,0},AL,0,NA,NA,0,0,3,SHIFT_LSR,1,NA,1,1}, + {0xA069,INSTR_MOV,{0,0,0,0,0},AL,0,NA,NA,0,0,MAX_32BIT,SHIFT_LSR,31,NA,1,1}, + {0xA070,INSTR_MOV,{0,0,0,0,0},AL,0,NA,NA,0,0,3,SHIFT_ASR,1,NA,1,1}, + {0xA071,INSTR_MOV,{0,0,0,0,0},AL,0,NA,NA,0,0,MAX_64BIT ,SHIFT_ASR,31,NA,1,MAX_64BIT}, + {0xA072,INSTR_MOV,{0,0,0,0,0},AL,0,NA,NA,0,0,3,SHIFT_ROR,1,NA,1,0xFFFFFFFF80000001}, + {0xA073,INSTR_MOV,{0,0,0,0,0},AL,0,NA,NA,0,0,0x80000001,SHIFT_ROR,31,NA,1,3}, + {0xA074,INSTR_MOV,{0,0,0,0,0},AL,1,NA,NA,0,0,MAX_64BIT -1,SHIFT_ASR,1,NA,1,MAX_64BIT}, + {0xA075,INSTR_MOV,{0,0,0,0,0},AL,1,NA,NA,0,0,3,SHIFT_ASR,1,NA,1,1}, + {0xA076,INSTR_MOV,{2,R_a5,R_a6,6,8},MI,0,NA,NA,1,0x80000001,NA,NA,NA,2,1,2}, + {0xA077,INSTR_MOV,{2,R_a5,R_a6,-4,-8},MI,0,NA,NA,0,0,0x80000001,0,0,2,1,0xFFFFFFFF80000001}, + {0xA078,INSTR_MOV,{1,R_a5,R_a6,-1,-1},LT,0,NA,NA,1,0x80000001,NA,NA,NA,2,1,2}, + {0xA079,INSTR_MOV,{1,R_a5,R_a6,-1,1},LT,0,NA,NA,1,0x80000001,NA,NA,NA,2,1,0xFFFFFFFF80000001}, + {0xA080,INSTR_MOV,{1,R_a5,R_a6,-1,-5},GE,0,NA,NA,0,0,MAX_32BIT,SHIFT_LSL,1,2,1,MAX_64BIT-1}, + {0xA081,INSTR_MOV,{1,R_a5,R_a6,5,5},GE,0,NA,NA,0,0,MAX_32BIT,SHIFT_LSL,31,2,1,0xFFFFFFFF80000000}, + {0xA082,INSTR_MOV,{1,R_a5,R_a6,-1,1},GE,0,NA,NA,0,0,MAX_32BIT,SHIFT_LSL,31,2,1,2}, + {0xA083,INSTR_MOV,{1,R_a5,R_a6,4,1},LE,0,NA,NA,0,0,MAX_32BIT,SHIFT_LSL,1,2,1,2}, + {0xA084,INSTR_MOV,{1,R_a5,R_a6,-1,-1},LE,0,NA,NA,1,0x80000001,NA,NA,NA,2,1,0xFFFFFFFF80000001}, + {0xA085,INSTR_MOV,{1,R_a5,R_a6,-1,1},LE,0,NA,NA,0,0,MAX_32BIT,SHIFT_LSL,31,2,1,0xFFFFFFFF80000000}, + {0xA086,INSTR_MOV,{1,R_a5,R_a6,1,1},GT,0,NA,NA,1,0x80000001,NA,NA,NA,2,1,2}, + {0xA087,INSTR_MOV,{1,R_a5,R_a6,-1,-3},GT,0,NA,NA,1,0x80000001,NA,NA,NA,2,1,0xFFFFFFFF80000001}, + {0xA088,INSTR_MOV,{1,R_a5,R_a6,-1,0},GT,0,NA,NA,1,0x80000001,NA,NA,NA,2,1,2}, + {0xA089,INSTR_MOV,{1,R_a5,R_a6,-1,-1},GT,0,NA,NA,0,0,0x80000001,0,0,2,1,2}, + {0xA090,INSTR_MOV,{1,R_a5,R_a6,6,1},GT,0,NA,NA,0,0,0x80000001,0,0,2,1,0xFFFFFFFF80000001}, + {0xA091,INSTR_MOV,{1,R_a5,R_a6,-1,1},GT,0,NA,NA,0,0,0x80000001,0,0,2,1,2}, + {0xA092,INSTR_MOV,{1,R_a5,R_a6,1,1},GT,0,NA,NA,0,0,MAX_32BIT,SHIFT_LSL,1,2,1,2}, + {0xA093,INSTR_MOV,{1,R_a5,R_a6,4,1},GT,0,NA,NA,0,0,MAX_32BIT,SHIFT_LSL,1,2,1,MAX_64BIT-1}, + {0xA094,INSTR_MOV,{1,R_a5,R_a6,-1,1},GT,0,NA,NA,0,0,MAX_32BIT ,SHIFT_LSL,1,2,1,2}, + {0xA095,INSTR_MOV,{1,R_a5,R_a6,1,-1},HS,0,NA,NA,1,0x80000001,NA,NA,NA,2,1,2}, + {0xA096,INSTR_MOV,{1,R_a5,R_a6,-1,1},HS,0,NA,NA,1,0x80000001,NA,NA,NA,2,1,0xFFFFFFFF80000001}, + {0xA097,INSTR_MVN,{1,R_a5,R_a6,1,4},HS,0,NA,NA,1,MAX_32BIT-1,NA,NA,NA,2,1,2}, + {0xA098,INSTR_MVN,{1,R_a5,R_a6,-1,1},HS,0,NA,NA,1,MAX_32BIT-1,NA,NA,NA,2,1,1}, + {0xA099,INSTR_MVN,{0,0,0,0,0},AL,0,NA,NA,1,0,NA,NA,NA,2,1,MAX_64BIT}, + {0xA100,INSTR_MVN,{0,0,0,0,0},AL,0,NA,NA,0,NA,MAX_32BIT-1,NA,0,2,1,1}, + {0xA101,INSTR_MVN,{0,0,0,0,0},AL,0,NA,NA,0,NA,0x80000001,NA,0,2,1,0x7FFFFFFE}, + {0xA102,INSTR_BIC,{0,0,0,0,0},AL,0,1,NA,1,MAX_32BIT,NA,NA,NA,NA,1,0}, + {0xA103,INSTR_BIC,{0,0,0,0,0},AL,0,1,NA,1,MAX_32BIT-1,NA,NA,NA,NA,1,1}, + {0xA104,INSTR_BIC,{0,0,0,0,0},AL,0,1,NA,0,0,MAX_32BIT,0,0,NA,1,0}, + {0xA105,INSTR_BIC,{0,0,0,0,0},AL,0,1,NA,0,0,MAX_32BIT-1,0,0,NA,1,1}, + {0xA106,INSTR_BIC,{0,0,0,0,0},AL,0,0xF0,NA,0,0,3,SHIFT_ASR,1,NA,1,0xF0}, + {0xA107,INSTR_BIC,{0,0,0,0,0},AL,0,0xF0,NA,0,0,MAX_64BIT,SHIFT_ASR,31,NA,1,0}, + {0xA108,INSTR_SMULBB,{0,0,0,0,0},AL,0,NA,0xFFFFFFFFABCDFFFF,0,NA,0xFFFFFFFFABCD0001,NA,NA,NA,1,0xFFFFFFFFFFFFFFFF}, + {0xA109,INSTR_SMULBB,{0,0,0,0,0},AL,0,NA,0xFFFFFFFFABCD0001,0,NA,0xFFFFFFFFABCD0FFF,NA,NA,NA,1,0x00000FFF}, + {0xA110,INSTR_SMULBB,{0,0,0,0,0},AL,0,NA,0xFFFFFFFFABCD0001,0,NA,0xFFFFFFFFABCDFFFF,NA,NA,NA,1,0xFFFFFFFFFFFFFFFF}, + {0xA111,INSTR_SMULBB,{0,0,0,0,0},AL,0,NA,0xFFFFFFFFABCDFFFF,0,NA,0xFFFFFFFFABCDFFFF,NA,NA,NA,1,1}, + {0xA112,INSTR_SMULBT,{0,0,0,0,0},AL,0,NA,0xFFFFFFFFFFFFABCD,0,NA,0xFFFFFFFFABCD0001,NA,NA,NA,1,0xFFFFFFFFFFFFFFFF}, + {0xA113,INSTR_SMULBT,{0,0,0,0,0},AL,0,NA,0x000000000001ABCD,0,NA,0xFFFFFFFFABCD0FFF,NA,NA,NA,1,0x00000FFF}, + {0xA114,INSTR_SMULBT,{0,0,0,0,0},AL,0,NA,0x000000000001ABCD,0,NA,0xFFFFFFFFABCDFFFF,NA,NA,NA,1,0xFFFFFFFFFFFFFFFF}, + {0xA115,INSTR_SMULBT,{0,0,0,0,0},AL,0,NA,0xFFFFFFFFFFFFABCD,0,NA,0xFFFFFFFFABCDFFFF,NA,NA,NA,1,1}, + {0xA116,INSTR_SMULTB,{0,0,0,0,0},AL,0,NA,0xFFFFFFFFABCDFFFF,0,NA,0x000000000001ABCD,NA,NA,NA,1,0xFFFFFFFFFFFFFFFF}, + {0xA117,INSTR_SMULTB,{0,0,0,0,0},AL,0,NA,0xFFFFFFFFABCD0001,0,NA,0x000000000FFFABCD,NA,NA,NA,1,0x00000FFF}, + {0xA118,INSTR_SMULTB,{0,0,0,0,0},AL,0,NA,0xFFFFFFFFABCD0001,0,NA,0xFFFFFFFFFFFFABCD,NA,NA,NA,1,0xFFFFFFFFFFFFFFFF}, + {0xA119,INSTR_SMULTB,{0,0,0,0,0},AL,0,NA,0xFFFFFFFFABCDFFFF,0,NA,0xFFFFFFFFFFFFABCD,NA,NA,NA,1,1}, + {0xA120,INSTR_SMULTT,{0,0,0,0,0},AL,0,NA,0xFFFFFFFFFFFFABCD,0,NA,0x000000000001ABCD,NA,NA,NA,1,0xFFFFFFFFFFFFFFFF}, + {0xA121,INSTR_SMULTT,{0,0,0,0,0},AL,0,NA,0x000000000001ABCD,0,NA,0x000000000FFFABCD,NA,NA,NA,1,0x00000FFF}, + {0xA122,INSTR_SMULTT,{0,0,0,0,0},AL,0,NA,0x000000000001ABCD,0,NA,0xFFFFFFFFFFFFABCD,NA,NA,NA,1,0xFFFFFFFFFFFFFFFF}, + {0xA123,INSTR_SMULTT,{0,0,0,0,0},AL,0,NA,0xFFFFFFFFFFFFABCD,0,NA,0xFFFFFFFFFFFFABCD,NA,NA,NA,1,1}, + {0xA124,INSTR_SMULWB,{0,0,0,0,0},AL,0,NA,0xFFFFFFFFABCDFFFF,0,NA,0x000000000001ABCD,NA,NA,NA,1,0xFFFFFFFFFFFFFFFE}, + {0xA125,INSTR_SMULWB,{0,0,0,0,0},AL,0,NA,0xFFFFFFFFABCD0001,0,NA,0x000000000FFFABCD,NA,NA,NA,1,0x00000FFF}, + {0xA126,INSTR_SMULWB,{0,0,0,0,0},AL,0,NA,0xFFFFFFFFABCD0001,0,NA,0xFFFFFFFFFFFFABCD,NA,NA,NA,1,0xFFFFFFFFFFFFFFFF}, + {0xA127,INSTR_SMULWB,{0,0,0,0,0},AL,0,NA,0xFFFFFFFFABCDFFFF,0,NA,0xFFFFFFFFFFFFABCD,NA,NA,NA,1,0}, + {0xA128,INSTR_SMULWT,{0,0,0,0,0},AL,0,NA,0xFFFFFFFFFFFFABCD,0,NA,0x000000000001ABCD,NA,NA,NA,1,0xFFFFFFFFFFFFFFFE}, + {0xA129,INSTR_SMULWT,{0,0,0,0,0},AL,0,NA,0x000000000001ABCD,0,NA,0x000000000FFFABCD,NA,NA,NA,1,0x00000FFF}, + {0xA130,INSTR_SMULWT,{0,0,0,0,0},AL,0,NA,0x000000000001ABCD,0,NA,0xFFFFFFFFFFFFABCD,NA,NA,NA,1,0xFFFFFFFFFFFFFFFF}, + {0xA131,INSTR_SMULWT,{0,0,0,0,0},AL,0,NA,0xFFFFFFFFFFFFABCD,0,NA,0xFFFFFFFFFFFFABCD,NA,NA,NA,1,0}, + {0xA132,INSTR_SMLABB,{0,0,0,0,0},AL,0,1,0xFFFFFFFFABCDFFFF,0,NA,0xFFFFFFFFABCD0001,NA,NA,NA,1,0}, + {0xA133,INSTR_SMLABB,{0,0,0,0,0},AL,0,1,0xFFFFFFFFABCD0001,0,NA,0xFFFFFFFFABCD0FFF,NA,NA,NA,1,0x00001000}, + {0xA134,INSTR_SMLABB,{0,0,0,0,0},AL,0,0xFFFFFFFFFFFFFFFF,0xFFFFFFFFABCD0001,0,NA,0xABCDFFFF,NA,NA,NA,1,0xFFFFFFFFFFFFFFFE}, + {0xA135,INSTR_SMLABB,{0,0,0,0,0},AL,0,0xFFFFFFFFFFFFFFFF,0xFFFFFFFFABCDFFFF,0,NA,0xABCDFFFF,NA,NA,NA,1,0}, + {0xA136,INSTR_UXTB16,{0,0,0,0,0},AL,0,NA,NA,0,NA,0xABCDEF01,SHIFT_ROR,0,NA,1,0x00CD0001}, + {0xA137,INSTR_UXTB16,{0,0,0,0,0},AL,0,NA,NA,0,NA,0xABCDEF01,SHIFT_ROR,1,NA,1,0x00AB00EF}, + {0xA138,INSTR_UXTB16,{0,0,0,0,0},AL,0,NA,NA,0,NA,0xABCDEF01,SHIFT_ROR,2,NA,1,0x000100CD}, + {0xA139,INSTR_UXTB16,{0,0,0,0,0},AL,0,NA,NA,0,NA,0xABCDEF01,SHIFT_ROR,3,NA,1,0x00EF00AB}, + {0xA140,INSTR_ADDR_ADD,{0,0,0,0,0},AL,0,0xCFFFFFFFF,NA,0,NA,0x1,SHIFT_LSL,1,NA,1,0xD00000001}, + {0xA141,INSTR_ADDR_ADD,{0,0,0,0,0},AL,0,0x01,NA,0,NA,0x1,SHIFT_LSL,2,NA,1,0x5}, + {0xA142,INSTR_ADDR_ADD,{0,0,0,0,0},AL,0,0xCFFFFFFFF,NA,0,NA,0x1,NA,0,NA,1,0xD00000000}, + {0xA143,INSTR_ADDR_SUB,{0,0,0,0,0},AL,0,0xD00000001,NA,0,NA,0x010000,SHIFT_LSR,15,NA,1,0xCFFFFFFFF}, + {0xA144,INSTR_ADDR_SUB,{0,0,0,0,0},AL,0,0xCFFFFFFFF,NA,0,NA,0x020000,SHIFT_LSR,15,NA,1,0xCFFFFFFFB}, + {0xA145,INSTR_ADDR_SUB,{0,0,0,0,0},AL,0,3,NA,0,NA,0x010000,SHIFT_LSR,15,NA,1,1}, +}; + +dataTransferTest_t dataTransferTests [] = +{ + {0xB000,INSTR_LDR,AL,AL,1,24,0xABCDEF0123456789,0,REG_SCALE_OFFSET,24,NA,NA,NA,NA,NA,0x23456789,0,0,NA,NA,NA}, + {0xB001,INSTR_LDR,AL,AL,1,0,0xABCDEF0123456789,0,IMM12_OFFSET,NA,4,1,0,1,NA,0x23456789,4,0,NA,NA,NA}, + {0xB002,INSTR_LDR,AL,AL,1,0,0xABCDEF0123456789,0,NO_OFFSET,NA,NA,0,0,0,NA,0x23456789,0,0,NA,NA,NA}, + {0xB003,INSTR_LDRB,AL,AL,1,4064,0xABCDEF0123456789,0,REG_SCALE_OFFSET,4064,NA,NA,NA,NA,NA,0x89,0,0,NA,NA,NA}, + {0xB004,INSTR_LDRB,AL,AL,1,4064,0xABCDEF0123456789,4065,IMM12_OFFSET,NA,0,0,1,0,NA,0x67,4065,0,NA,NA,NA}, + {0xB005,INSTR_LDRB,AL,AL,1,4064,0xABCDEF0123456789,4065,IMM12_OFFSET,NA,1,0,1,0,NA,0x45,4065,0,NA,NA,NA}, + {0xB006,INSTR_LDRB,AL,AL,1,4064,0xABCDEF0123456789,4065,IMM12_OFFSET,NA,2,0,1,0,NA,0x23,4065,0,NA,NA,NA}, + {0xB007,INSTR_LDRB,AL,AL,1,4064,0xABCDEF0123456789,4065,IMM12_OFFSET,NA,1,1,0,1,NA,0x67,4066,0,NA,NA,NA}, + {0xB008,INSTR_LDRB,AL,AL,1,4064,0xABCDEF0123456789,0,NO_OFFSET,NA,NA,0,0,0,NA,0x89,0,0,NA,NA,NA}, + {0xB009,INSTR_LDRH,AL,AL,1,0,0xABCDEF0123456789,0,IMM8_OFFSET,NA,2,1,0,1,NA,0x6789,2,0,NA,NA,NA}, + {0xB010,INSTR_LDRH,AL,AL,1,4064,0xABCDEF0123456789,0,REG_OFFSET,4064,0,0,1,0,NA,0x6789,0,0,NA,NA,NA}, + {0xB011,INSTR_LDRH,AL,AL,1,4064,0xABCDEF0123456789,0,REG_OFFSET,4066,0,0,1,0,NA,0x2345,0,0,NA,NA,NA}, + {0xB012,INSTR_LDRH,AL,AL,1,0,0xABCDEF0123456789,0,NO_OFFSET,NA,0,0,0,0,NA,0x6789,0,0,NA,NA,NA}, + {0xB013,INSTR_LDRH,AL,AL,1,0,0xABCDEF0123456789,2,NO_OFFSET,NA,0,0,0,0,NA,0x2345,2,0,NA,NA,NA}, + {0xB014,INSTR_STR,AL,AL,1,2,0xDEADBEEFDEADBEEF,4,IMM12_OFFSET,NA,4,1,0,1,0xABCDEF0123456789,0xABCDEF0123456789,8,1,2,8,0xDEAD23456789BEEF}, + {0xB015,INSTR_STR,AL,AL,1,2,0xDEADBEEFDEADBEEF,4,NO_OFFSET,NA,NA,0,0,0,0xABCDEF0123456789,0xABCDEF0123456789,4,1,2,8,0xDEAD23456789BEEF}, + {0xB016,INSTR_STRB,AL,AL,1,0,0xDEADBEEFDEADBEEF,1,IMM12_OFFSET,NA,0,0,1,0,0xABCDEF0123456789,0xABCDEF0123456789,1,1,0,8,0xDEADBEEFDEAD89EF}, + {0xB017,INSTR_STRB,AL,AL,1,0,0xDEADBEEFDEADBEEF,1,IMM12_OFFSET,NA,1,0,1,0,0xABCDEF0123456789,0xABCDEF0123456789,1,1,0,8,0xDEADBEEFDE89BEEF}, + {0xB018,INSTR_STRB,AL,AL,1,0,0xDEADBEEFDEADBEEF,1,IMM12_OFFSET,NA,2,0,1,0,0xABCDEF0123456789,0xABCDEF0123456789,1,1,0,8,0xDEADBEEF89ADBEEF}, + {0xB019,INSTR_STRB,AL,AL,1,0,0xDEADBEEFDEADBEEF,1,IMM12_OFFSET,NA,4,1,0,1,0xABCDEF0123456789,0xABCDEF0123456789,5,1,0,8,0xDEADBEEFDEAD89EF}, + {0xB020,INSTR_STRB,AL,AL,1,0,0xDEADBEEFDEADBEEF,1,NO_OFFSET,NA,NA,0,0,0,0xABCDEF0123456789,0xABCDEF0123456789,1,1,0,8,0xDEADBEEFDEAD89EF}, + {0xB021,INSTR_STRH,AL,AL,1,4066,0xDEADBEEFDEADBEEF,4070,IMM8_OFFSET,NA,2,1,0,1,0xABCDEF0123456789,0xABCDEF0123456789,4072,1,4066,8,0xDEAD6789DEADBEEF}, + {0xB022,INSTR_STRH,AL,AL,1,4066,0xDEADBEEFDEADBEEF,4070,NO_OFFSET,NA,NA,0,0,0,0xABCDEF0123456789,0xABCDEF0123456789,4070,1,4066,8,0xDEAD6789DEADBEEF}, +}; + + +void flushcache() +{ + const long base = long(instrMem); + const long curr = base + long(instrMemSize); + __builtin___clear_cache((char*)base, (char*)curr); +} + +void dataOpTest(dataOpTest_t test, ArmToMips64Assembler *a64asm, uint32_t Rd = R_v1, + uint32_t Rn = R_t0, uint32_t Rm = R_t1, uint32_t Rs = R_t2) +{ + int64_t regs[NUM_REGS] = {0}; + int32_t flags[NUM_FLAGS] = {0}; + int64_t savedRegs[NUM_REGS] = {0}; + uint32_t i; + uint32_t op2; + + for(i = 0; i < NUM_REGS; ++i) + { + regs[i] = i; + } + + regs[Rd] = test.RdValue; + regs[Rn] = test.RnValue; + regs[Rs] = test.RsValue; + a64asm->reset(); + if (test.preCond.mode) { + a64asm->set_condition(test.preCond.mode, test.preCond.Rcond1, test.preCond.Rcond2); + regs[test.preCond.Rcond1] = test.preCond.Rcond1Value; + regs[test.preCond.Rcond2] = test.preCond.Rcond2Value; + } + a64asm->prolog(); + if(test.immediate == true) + { + op2 = a64asm->imm(test.immValue); + } + else if(test.immediate == false && test.shiftAmount == 0) + { + op2 = Rm; + regs[Rm] = (int64_t)((int32_t)(test.RmValue)); + } + else + { + op2 = a64asm->reg_imm(Rm, test.shiftMode, test.shiftAmount); + regs[Rm] = (int64_t)((int32_t)(test.RmValue)); + } + switch(test.op) + { + case INSTR_ADD: a64asm->ADD(test.cond, test.setFlags, Rd,Rn,op2); break; + case INSTR_SUB: a64asm->SUB(test.cond, test.setFlags, Rd,Rn,op2); break; + case INSTR_RSB: a64asm->RSB(test.cond, test.setFlags, Rd,Rn,op2); break; + case INSTR_AND: a64asm->AND(test.cond, test.setFlags, Rd,Rn,op2); break; + case INSTR_ORR: a64asm->ORR(test.cond, test.setFlags, Rd,Rn,op2); break; + case INSTR_BIC: a64asm->BIC(test.cond, test.setFlags, Rd,Rn,op2); break; + case INSTR_MUL: a64asm->MUL(test.cond, test.setFlags, Rd,Rm,Rs); break; + case INSTR_MLA: a64asm->MLA(test.cond, test.setFlags, Rd,Rm,Rs,Rn); break; + case INSTR_CMP: a64asm->CMP(test.cond, Rn,op2); break; + case INSTR_MOV: a64asm->MOV(test.cond, test.setFlags,Rd,op2); break; + case INSTR_MVN: a64asm->MVN(test.cond, test.setFlags,Rd,op2); break; + case INSTR_SMULBB:a64asm->SMULBB(test.cond, Rd,Rm,Rs); break; + case INSTR_SMULBT:a64asm->SMULBT(test.cond, Rd,Rm,Rs); break; + case INSTR_SMULTB:a64asm->SMULTB(test.cond, Rd,Rm,Rs); break; + case INSTR_SMULTT:a64asm->SMULTT(test.cond, Rd,Rm,Rs); break; + case INSTR_SMULWB:a64asm->SMULWB(test.cond, Rd,Rm,Rs); break; + case INSTR_SMULWT:a64asm->SMULWT(test.cond, Rd,Rm,Rs); break; + case INSTR_SMLABB:a64asm->SMLABB(test.cond, Rd,Rm,Rs,Rn); break; + case INSTR_UXTB16:a64asm->UXTB16(test.cond, Rd,Rm,test.shiftAmount); break; + case INSTR_ADDR_ADD: a64asm->ADDR_ADD(test.cond, test.setFlags, Rd,Rn,op2); break; + case INSTR_ADDR_SUB: a64asm->ADDR_SUB(test.cond, test.setFlags, Rd,Rn,op2); break; + default: printf("Error"); return; + } + a64asm->epilog(0); + a64asm->fix_branches(); + flushcache(); + + asm_function_t asm_function = (asm_function_t)(instrMem); + + for(i = 0; i < NUM_REGS; ++i) + savedRegs[i] = regs[i]; + + asm_mips_test_jacket(asm_function, regs, flags); + + /* Check if all regs except Rd is same */ + for(i = 0; i < NUM_REGS; ++i) + { + if((i == Rd) || i == 2) continue; + if(regs[i] != savedRegs[i]) + { + printf("Test %x failed Reg(%d) tampered Expected(0x%" PRIx64 ")," + "Actual(0x%" PRIx64 ") t\n", test.id, i, savedRegs[i], + regs[i]); + exit(0); + return; + } + } + + if(test.checkRd == 1 && regs[Rd] != test.postRdValue) + { + printf("Test %x failed, Expected(%" PRIx64 "), Actual(%" PRIx64 ")\n", + test.id, test.postRdValue, regs[Rd]); + exit(0); + } + else + { + printf("Test %x passed\n", test.id); + } +} + + +void dataTransferTest(dataTransferTest_t test, ARMAssemblerInterface *a64asm, + uint32_t Rd = R_v1, uint32_t Rn = R_t0,uint32_t Rm = R_t1) +{ + int64_t regs[NUM_REGS] = {0}; + int64_t savedRegs[NUM_REGS] = {0}; + int32_t flags[NUM_FLAGS] = {0}; + uint32_t i; + for(i = 0; i < NUM_REGS; ++i) + { + regs[i] = i; + } + + uint32_t op2; + + regs[Rd] = test.RdValue; + regs[Rn] = (uint64_t)(&dataMem[test.RnValue]); + regs[Rm] = test.RmValue; + flags[test.preFlag] = 1; + + if(test.setMem == true) + { + unsigned char *mem = (unsigned char *)&dataMem[test.memOffset]; + uint64_t value = test.memValue; + for(int j = 0; j < 8; ++j) + { + mem[j] = value & 0x00FF; + value >>= 8; + } + } + a64asm->reset(); + a64asm->prolog(); + if(test.offsetType == REG_SCALE_OFFSET) + { + op2 = a64asm->reg_scale_pre(Rm); + } + else if(test.offsetType == REG_OFFSET) + { + op2 = a64asm->reg_pre(Rm); + } + else if(test.offsetType == IMM12_OFFSET && test.preIndex == true) + { + op2 = a64asm->immed12_pre(test.immValue, test.writeBack); + } + else if(test.offsetType == IMM12_OFFSET && test.postIndex == true) + { + op2 = a64asm->immed12_post(test.immValue); + } + else if(test.offsetType == IMM8_OFFSET && test.preIndex == true) + { + op2 = a64asm->immed8_pre(test.immValue, test.writeBack); + } + else if(test.offsetType == IMM8_OFFSET && test.postIndex == true) + { + op2 = a64asm->immed8_post(test.immValue); + } + else if(test.offsetType == NO_OFFSET) + { + op2 = a64asm->__immed12_pre(0); + } + else + { + printf("Error - Unknown offset\n"); return; + } + + switch(test.op) + { + case INSTR_LDR: a64asm->LDR(test.cond, Rd,Rn,op2); break; + case INSTR_LDRB: a64asm->LDRB(test.cond, Rd,Rn,op2); break; + case INSTR_LDRH: a64asm->LDRH(test.cond, Rd,Rn,op2); break; + case INSTR_ADDR_LDR: a64asm->ADDR_LDR(test.cond, Rd,Rn,op2); break; + case INSTR_STR: a64asm->STR(test.cond, Rd,Rn,op2); break; + case INSTR_STRB: a64asm->STRB(test.cond, Rd,Rn,op2); break; + case INSTR_STRH: a64asm->STRH(test.cond, Rd,Rn,op2); break; + case INSTR_ADDR_STR: a64asm->ADDR_STR(test.cond, Rd,Rn,op2); break; + default: printf("Error"); return; + } + a64asm->epilog(0); + flushcache(); + + asm_function_t asm_function = (asm_function_t)(instrMem); + + for(i = 0; i < NUM_REGS; ++i) + savedRegs[i] = regs[i]; + + asm_mips_test_jacket(asm_function, regs, flags); + + /* Check if all regs except Rd/Rn are same */ + for(i = 0; i < NUM_REGS; ++i) + { + if(i == Rd || i == Rn || i == R_v0) continue; + + if(regs[i] != savedRegs[i]) + { + printf("Test %x failed Reg(%d) tampered" + " Expected(0x%" PRIx64 "), Actual(0x%" PRIx64 ") t\n", + test.id, i, savedRegs[i], regs[i]); + return; + } + } + + if((uint64_t)regs[Rd] != test.postRdValue) + { + printf("Test %x failed, " + "Expected in Rd(0x%" PRIx64 "), Actual(0x%" PRIx64 ")\n", + test.id, test.postRdValue, regs[Rd]); + } + else if((uint64_t)regs[Rn] != (uint64_t)(&dataMem[test.postRnValue])) + { + printf("Test %x failed, " + "Expected in Rn(0x%" PRIx64 "), Actual(0x%" PRIx64 ")\n", + test.id, test.postRnValue, regs[Rn] - (uint64_t)dataMem); + } + else if(test.checkMem == true) + { + unsigned char *addr = (unsigned char *)&dataMem[test.postMemOffset]; + uint64_t value; + value = 0; + for(uint32_t j = 0; j < test.postMemLength; ++j) + value = (value << 8) | addr[test.postMemLength-j-1]; + if(value != test.postMemValue) + { + printf("Test %x failed, " + "Expected in Mem(0x%" PRIx64 "), Actual(0x%" PRIx64 ")\n", + test.id, test.postMemValue, value); + } + else + { + printf("Test %x passed\n", test.id); + } + } + else + { + printf("Test %x passed\n", test.id); + } +} + +int main(void) +{ + uint32_t i; + + /* Allocate memory to store instructions generated by ArmToArm64Assembler */ + { + int fd = ashmem_create_region("code cache", instrMemSize); + if(fd < 0) { + printf("IF < 0\n"); + printf("Creating code cache, ashmem_create_region " + "failed with error '%s'", strerror(errno)); + } + instrMem = mmap(NULL, instrMemSize, + PROT_READ | PROT_WRITE | PROT_EXEC, + MAP_PRIVATE, fd, 0); + } + + ArmToMips64Assembler a64asm(instrMem); + + if(TESTS_DATAOP_ENABLE) + { + printf("Running data processing tests\n"); + for(i = 0; i < sizeof(dataOpTests)/sizeof(dataOpTest_t); ++i) { + dataOpTest(dataOpTests[i], &a64asm); + } + } + + if(TESTS_DATATRANSFER_ENABLE) + { + printf("Running data transfer tests\n"); + for(i = 0; i < sizeof(dataTransferTests)/sizeof(dataTransferTest_t); ++i) + dataTransferTest(dataTransferTests[i], &a64asm); + } + + return 0; +} diff --git a/libpixelflinger/tests/arch-mips64/col32cb16blend/Android.mk b/libpixelflinger/tests/arch-mips64/col32cb16blend/Android.mk new file mode 100644 index 000000000..7d4177ecb --- /dev/null +++ b/libpixelflinger/tests/arch-mips64/col32cb16blend/Android.mk @@ -0,0 +1,18 @@ +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_SRC_FILES:= \ + col32cb16blend_test.c \ + ../../../arch-mips64/col32cb16blend.S + +LOCAL_SHARED_LIBRARIES := + +LOCAL_C_INCLUDES := + +LOCAL_MODULE:= test-pixelflinger-mips64-col32cb16blend + +LOCAL_MODULE_TAGS := tests + +LOCAL_MULTILIB := 64 + +include $(BUILD_NATIVE_TEST) diff --git a/libpixelflinger/tests/arch-mips64/col32cb16blend/col32cb16blend_test.c b/libpixelflinger/tests/arch-mips64/col32cb16blend/col32cb16blend_test.c new file mode 100644 index 000000000..066eab679 --- /dev/null +++ b/libpixelflinger/tests/arch-mips64/col32cb16blend/col32cb16blend_test.c @@ -0,0 +1,125 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include + + +#define ARGB_8888_MAX 0xFFFFFFFF +#define ARGB_8888_MIN 0x00000000 +#define RGB_565_MAX 0xFFFF +#define RGB_565_MIN 0x0000 + +struct test_t +{ + char name[256]; + uint32_t src_color; + uint16_t dst_color; + size_t count; +}; + +struct test_t tests[] = +{ + {"Count 1, Src=Max, Dst=Min", ARGB_8888_MAX, RGB_565_MIN, 1}, + {"Count 2, Src=Min, Dst=Max", ARGB_8888_MIN, RGB_565_MAX, 2}, + {"Count 3, Src=Max, Dst=Max", ARGB_8888_MAX, RGB_565_MAX, 3}, + {"Count 4, Src=Min, Dst=Min", ARGB_8888_MAX, RGB_565_MAX, 4}, + {"Count 1, Src=Rand, Dst=Rand", 0x12345678, 0x9ABC, 1}, + {"Count 2, Src=Rand, Dst=Rand", 0xABCDEF12, 0x2345, 2}, + {"Count 3, Src=Rand, Dst=Rand", 0x11111111, 0xEDFE, 3}, + {"Count 4, Src=Rand, Dst=Rand", 0x12345678, 0x9ABC, 4}, + {"Count 5, Src=Rand, Dst=Rand", 0xEFEFFEFE, 0xFACC, 5}, + {"Count 10, Src=Rand, Dst=Rand", 0x12345678, 0x9ABC, 10} +}; + +void scanline_col32cb16blend_mips64(uint16_t *dst, uint32_t src, size_t count); +void scanline_col32cb16blend_c(uint16_t * dst, uint32_t src, size_t count) +{ + uint32_t srcAlpha = (src>>24); + uint32_t f = 0x100 - (srcAlpha + (srcAlpha>>7)); + + while (count--) + { + uint16_t d = *dst; + int dstR = (d>>11)&0x1f; + int dstG = (d>>5)&0x3f; + int dstB = (d)&0x1f; + int srcR = (src >> ( 3))&0x1F; + int srcG = (src >> ( 8+2))&0x3F; + int srcB = (src >> (16+3))&0x1F; + srcR += (f*dstR)>>8; + srcG += (f*dstG)>>8; + srcB += (f*dstB)>>8; + *dst++ = (uint16_t)((srcR<<11)|(srcG<<5)|srcB); + } +} + +void scanline_col32cb16blend_test() +{ + uint16_t dst_c[16], dst_asm[16]; + uint32_t i, j; + + for(i = 0; i < sizeof(tests)/sizeof(struct test_t); ++i) + { + struct test_t test = tests[i]; + + printf("Testing - %s:",test.name); + + memset(dst_c, 0, sizeof(dst_c)); + memset(dst_asm, 0, sizeof(dst_asm)); + + for(j = 0; j < test.count; ++j) + { + dst_c[j] = test.dst_color; + dst_asm[j] = test.dst_color; + } + + + scanline_col32cb16blend_c(dst_c, test.src_color, test.count); + scanline_col32cb16blend_mips64(dst_asm, test.src_color, test.count); + + if(memcmp(dst_c, dst_asm, sizeof(dst_c)) == 0) + printf("Passed\n"); + else + printf("Failed\n"); + + for(j = 0; j < test.count; ++j) + { + printf("dst_c[%d] = %x, dst_asm[%d] = %x \n", j, dst_c[j], j, dst_asm[j]); + } + } +} + +int main() +{ + scanline_col32cb16blend_test(); + return 0; +} diff --git a/libpixelflinger/tests/arch-mips64/disassembler/Android.mk b/libpixelflinger/tests/arch-mips64/disassembler/Android.mk new file mode 100644 index 000000000..4e72b5784 --- /dev/null +++ b/libpixelflinger/tests/arch-mips64/disassembler/Android.mk @@ -0,0 +1,16 @@ +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_SRC_FILES:= \ + mips64_disassembler_test.cpp \ + ../../../codeflinger/mips64_disassem.c + +LOCAL_SHARED_LIBRARIES := + +LOCAL_MODULE:= test-pixelflinger-mips64-disassembler-test + +LOCAL_MODULE_TAGS := tests + +LOCAL_MULTILIB := 64 + +include $(BUILD_NATIVE_TEST) diff --git a/libpixelflinger/tests/arch-mips64/disassembler/mips64_disassembler_test.cpp b/libpixelflinger/tests/arch-mips64/disassembler/mips64_disassembler_test.cpp new file mode 100644 index 000000000..41f6f3ef9 --- /dev/null +++ b/libpixelflinger/tests/arch-mips64/disassembler/mips64_disassembler_test.cpp @@ -0,0 +1,218 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +#include +#include +#include +#include "../../../codeflinger/mips64_disassem.h" + +//typedef uint64_t db_addr_t; +//db_addr_t mips_disassem(db_addr_t loc, char *di_buffer, int alt_format); + +struct test_table_entry_t +{ + uint32_t code; + const char *instr; +}; + +static test_table_entry_t test_table [] = +{ + { 0x00011020, "add\tv0,zero,at" }, + { 0x00832820, "add\ta1,a0,v1" }, + { 0x00c74020, "add\ta4,a2,a3" }, + { 0x012a5820, "add\ta7,a5,a6" }, + { 0x258dffff, "addiu\tt1,t0,-1" }, + { 0x25cf0004, "addiu\tt3,t2,4" }, + { 0x02119021, "addu\ts2,s0,s1" }, + { 0x0274a821, "addu\ts5,s3,s4" }, + { 0x02d7c024, "and\tt8,s6,s7" }, + { 0x333aff00, "andi\tk0,t9,0xff00" }, + { 0x3f7cffff, "aui\tgp,k1,-1" }, + { 0x3c1dffff, "lui\tsp,0xffff" }, + { 0x00e04051, "clo\ta4,a3" }, + { 0x01205050, "clz\ta6,a5" }, + { 0x016c682c, "dadd\tt1,a7,t0" }, + { 0x65cf0008, "daddiu\tt3,t2,8" }, + { 0x0211902d, "daddu\ts2,s0,s1" }, + { 0x7e741403, "dext\ts4,s3,16,3" }, + { 0x7eb6f801, "dextm\ts6,s5,0,64" }, + { 0x7ef87c02, "dextu\tt8,s7,48,16" }, + { 0x7f3a8207, "dins\tk0,t9,8,9" }, + { 0x7f7c0005, "dinsm\tgp,k1,0,33" }, + { 0x7fbe0806, "dinsu\ts8,sp,32,2" }, + { 0x03e1102e, "dsub\tv0,ra,at" }, + { 0x0064282f, "dsubu\ta1,v1,a0" }, + { 0x7cc77a00, "ext\ta3,a2,8,16" }, + { 0x7d09fc04, "ins\ta5,a4,16,16" }, + { 0x00200009, "jr\tat" }, + { 0x00201009, "jalr\tv0,at" }, + { 0x0020f809, "jalr\tat" }, + { 0x8082fff0, "lb\tv0,-16(a0)" }, + { 0x916c0008, "lbu\tt0,8(a7)" }, + { 0xdfa3ffe8, "ld\tv1,-24(sp)" }, + { 0x84850080, "lh\ta1,128(a0)" }, + { 0x94c7ff80, "lhu\ta3,-128(a2)" }, + { 0x8d09000c, "lw\ta5,12(a4)" }, + { 0x9d4bfff4, "lwu\ta7,-12(a6)" }, + { 0x00620898, "mul\tat,v1,v0" }, + { 0x006208d8, "muh\tat,v1,v0" }, + { 0x00620899, "mulu\tat,v1,v0" }, + { 0x006208d9, "muhu\tat,v1,v0" }, + { 0x00000000, "nop" }, + { 0x02329827, "nor\ts3,s1,s2" }, + { 0x0295b025, "or\ts6,s4,s5" }, + { 0x36f0ff00, "ori\ts0,s7,0xff00" }, + { 0x7c03103b, "rdhwr\tv0,v1" }, + { 0x00242a02, "rotr\ta1,a0,8" }, + { 0x00c74046, "rotrv\ta4,a3,a2" }, + { 0xa12afff0, "sb\ta6,-16(a5)" }, + { 0xfd6c0100, "sd\tt0,256(a7)" }, + { 0x7c0d7420, "seb\tt2,t1" }, + { 0x7c0f8620, "seh\ts0,t3" }, + { 0x02329835, "seleqz\ts3,s1,s2" }, + { 0x0295b037, "selnez\ts6,s4,s5" }, + { 0xa6f84000, "sh\tt8,16384(s7)" }, + { 0x0019d100, "sll\tk0,t9,4" }, + { 0x037ce804, "sllv\tsp,gp,k1" }, + { 0x03df082a, "slt\tat,s8,ra" }, + { 0x28430007, "slti\tv1,v0,7" }, + { 0x2c850020, "sltiu\ta1,a0,32" }, + { 0x00c7402b, "sltu\ta4,a2,a3" }, + { 0x00095103, "sra\ta6,a5,4" }, + { 0x016c6807, "srav\tt1,t0,a7" }, + { 0x000e7a02, "srl\tt3,t2,8" }, + { 0x02119006, "srlv\ts2,s1,s0" }, + { 0x0274a822, "sub\ts5,s3,s4" }, + { 0x02d7c023, "subu\tt8,s6,s7" }, + { 0xaf3afffc, "sw\tk0,-4(t9)" }, + { 0x7c1be0a0, "wsbh\tgp,k1" }, + { 0x03bef826, "xor\tra,sp,s8" }, + { 0x3801ffff, "li\tat,0xffff" }, + { 0x3843ffff, "xori\tv1,v0,0xffff" }, +}; + +struct test_branches_table_entry_t +{ + uint32_t code; + const char *instr; + int16_t offset; +}; + +static test_branches_table_entry_t test_branches_table [] = { + { 0x1000ffff, "b\t", 0xffff }, + { 0x13df0008, "beq\ts8,ra,", 0x8 }, + { 0x042100ff, "bgez\tat,", 0xff }, + { 0x1c40ff00, "bgtz\tv0,", 0xff00 }, + { 0x18605555, "blez\tv1,", 0x5555 }, + { 0x0480aaaa, "bltz\ta0,", 0xaaaa }, + { 0x14a68888, "bne\ta1,a2,", 0x8888 }, +}; + +struct test_jump_table_entry_t +{ + uint32_t code; + const char *instr; + int32_t offset; +}; + +static test_jump_table_entry_t test_jump_table [] = { + { 0x0956ae66, "j\t", 0x156ae66 }, + { 0x0d56ae66, "jal\t", 0x156ae66 }, +}; + +int main() +{ + char instr[256]; + uint32_t failed = 0; + + for(uint32_t i = 0; i < sizeof(test_table)/sizeof(test_table_entry_t); ++i) + { + test_table_entry_t *test; + test = &test_table[i]; + mips_disassem(&test->code, instr, 0); + if(strcmp(instr, test->instr) != 0) + { + printf("Test Failed \n" + "Code : 0x%0x\n" + "Expected : %s\n" + "Actual : %s\n", test->code, test->instr, instr); + failed++; + } + } + for(uint32_t i = 0; i < sizeof(test_branches_table)/sizeof(test_branches_table_entry_t); ++i) + { + test_branches_table_entry_t *test; + test = &test_branches_table[i]; + mips_disassem(&test->code, instr, 0); + //printf("DBG code address: %lx\n", (uint64_t)(&test->code)); + uint64_t loc = (uint64_t)test + 4 + (test->offset << 2); + //printf("DBG loc: %lx\n", loc); + char temp[256], address[16]; + strcpy(temp, test->instr); + sprintf(address, "0x%lx", loc); + strcat(temp, address); + if(strcmp(instr, temp) != 0) + { + printf("Test Failed \n" + "Code : 0x%0x\n" + "Expected : %s\n" + "Actual : %s\n", test->code, temp, instr); + failed++; + } + } + for(uint32_t i = 0; i < sizeof(test_jump_table)/sizeof(test_jump_table_entry_t); ++i) + { + test_jump_table_entry_t *test; + test = &test_jump_table[i]; + mips_disassem(&test->code, instr, 0); + //printf("DBG code address: %lx\n", (uint64_t)(&test->code)); + uint64_t loc = ((uint64_t)test & 0xfffffffff0000000) | (test->offset << 2); + //printf("DBG loc: %lx\n", loc); + char temp[256], address[16]; + strcpy(temp, test->instr); + sprintf(address, "0x%08lx", loc); + strcat(temp, address); + if(strcmp(instr, temp) != 0) + { + printf("Test Failed \n" + "Code : 0x%0x\n" + "Expected : '%s'\n" + "Actual : '%s'\n", test->code, temp, instr); + failed++; + } + } + if(failed == 0) + { + printf("All tests PASSED\n"); + return 0; + } + else + { + printf("%d tests FAILED\n", failed); + return -1; + } +} diff --git a/libpixelflinger/tests/codegen/codegen.cpp b/libpixelflinger/tests/codegen/codegen.cpp index 148b6f44d..efa6d87bf 100644 --- a/libpixelflinger/tests/codegen/codegen.cpp +++ b/libpixelflinger/tests/codegen/codegen.cpp @@ -11,16 +11,18 @@ #include "codeflinger/ARMAssembler.h" #if defined(__mips__) && !defined(__LP64__) && __mips_isa_rev < 6 #include "codeflinger/MIPSAssembler.h" +#elif defined(__mips__) && defined(__LP64__) && __mips_isa_rev == 6 +#include "codeflinger/MIPS64Assembler.h" #endif #include "codeflinger/Arm64Assembler.h" -#if defined(__arm__) || (defined(__mips__) && !defined(__LP64__) && __mips_isa_rev < 6) || defined(__aarch64__) +#if defined(__arm__) || (defined(__mips__) && ((!defined(__LP64__) && __mips_isa_rev < 6) || (defined(__LP64__) && __mips_isa_rev == 6))) || defined(__aarch64__) # define ANDROID_ARM_CODEGEN 1 #else # define ANDROID_ARM_CODEGEN 0 #endif -#if defined(__mips__) && !defined(__LP64__) && __mips_isa_rev < 6 +#if defined(__mips__) && ((!defined(__LP64__) && __mips_isa_rev < 6) || (defined(__LP64__) && __mips_isa_rev == 6)) #define ASSEMBLY_SCRATCH_SIZE 4096 #elif defined(__aarch64__) #define ASSEMBLY_SCRATCH_SIZE 8192 @@ -58,6 +60,10 @@ static void ggl_test_codegen(uint32_t n, uint32_t p, uint32_t t0, uint32_t t1) GGLAssembler assembler( new ArmToMipsAssembler(a) ); #endif +#if defined(__mips__) && defined(__LP64__) && __mips_isa_rev == 6 + GGLAssembler assembler( new ArmToMips64Assembler(a) ); +#endif + #if defined(__aarch64__) GGLAssembler assembler( new ArmToArm64Assembler(a) ); #endif