Commit 6eee6524 authored by Jeffrey Lee's avatar Jeffrey Lee

VFP/NEON disassembly improvements

Detail:
  actions/ARMv8FP_AArch32, Makefile - Add disasembly for the ARMv8 VFP/NEON instructions
  actions/ARMv7_ASIMD, actions/ARMv7_VFP - Fix incorrect disassembly of VCLS, VMOVN, VRSUBHN, VFNMA, VFNMS
  c/util - Add disassembly for MVFR2 register
  s/ARM - Tweak coprocessor instruction decoding logic; ARMv8 uses some of the CDP2 instructions for VFP/NEON
  cache/vfp - Updated decgen cache file
  Test/c/testbed - Improve fopen/system error checking. Add some more rules to deal with (expected) differences between Debugger/dis2 and decaof.
Admin:
  Tested on Raspberry Pi 3
  Disassembly for new instructions (+ some nearby values) checked against BASIC 1.74 + decaof 5.18
  Requires Library-1_92


Version 2.02. Tagged as 'Debugger-2_02'
parent adb4bab6
......@@ -82,16 +82,17 @@ ACTIONS_ARM = actions/common \
actions/ARMv7_ASIMD \
actions/ARMv7_VFP \
actions/ARMv8_AArch32 \
actions/ARMv8FP_AArch32 \
actions/FPA \
actions/XScale_DSP
ACTIONS_VFP = actions/common \
actions/ARMv7_ASIMD \
actions/ARMv7_VFP
actions/ARMv7_VFP \
actions/ARMv8FP_AArch32
ENCODINGS = Build:decgen.encodings.ARMv7 \
Build:decgen.encodings.ARMv7_ASIMD \
Build:decgen.encodings.ARMv7_VFP \
Build:decgen.encodings.ARMv8FP_AArch32 \
Build:decgen.encodings.ARMv8_AArch32 \
Build:decgen.encodings.FPA \
Build:decgen.encodings.XScale_DSP
......
......@@ -23,8 +23,29 @@
/* Standalone testbed app for comparing standalone dis2 builds against the
Debugger module and decaof */
void xsystem(const char *cmd)
{
// printf("*%s\n",cmd);
if (system(cmd))
{
fprintf(stderr,"'%s' failed!\n",cmd);
exit(257);
}
}
FILE *xfopen(const char *file,const char *mode)
{
FILE *f = fopen(file,mode);
if(!f)
{
fprintf(stderr,"Couldn't open '%s'\n",file);
exit(257);
}
return f;
}
#define DEBUGGER
//#define DECAOF
#define DECAOF
#define MYDIFF
......@@ -33,9 +54,9 @@ void postprocess(char *folder,char *in,char *out)
{
char buf[4096];
sprintf(buf,"%s.%s",folder,in);
FILE *fin = fopen(buf,"r");
FILE *fin = xfopen(buf,"r");
sprintf(buf,"%s.%s",folder,out);
FILE *fout = fopen(buf,"w");
FILE *fout = xfopen(buf,"w");
setvbuf(fin,NULL,_IOFBF,65536);
setvbuf(fout,NULL,_IOFBF,65536);
while(!feof(fin) && fgets(buf,4096,fin))
......@@ -86,11 +107,11 @@ int diff_decaof(char *folder,char *one,char *two,char *out)
FILE *fin1,*fin2;
FILE *fout;
sprintf(buf1,"%s.%s",folder,one);
fin1 = fopen(buf1,"r");
fin1 = xfopen(buf1,"r");
sprintf(buf1,"%s.%s",folder,two);
fin2 = fopen(buf1,"r");
fin2 = xfopen(buf1,"r");
sprintf(buf1,"%s.%s",folder,out);
fout = fopen(buf1,"w");
fout = xfopen(buf1,"w");
setvbuf(fin1,NULL,_IOFBF,65536);
setvbuf(fin2,NULL,_IOFBF,65536);
setvbuf(fout,NULL,_IOFBF,65536);
......@@ -139,6 +160,18 @@ int diff_decaof(char *folder,char *one,char *two,char *out)
/* Skip any that decgen thinks are nonstandard */
if(strstr(c2,"Nonstandard encoding"))
continue;
/* Skip any that decgen thinks are undefined */
if(strstr(c2,"Undefined instruction"))
continue;
/* decaof & dis2 agree on how unknown VMRS/VMSR registers should be shown */
if(strstr(c2,"Bad VFP/NEON special register"))
continue;
/* decaof doesn't recognise MVFR2 */
if(strstr(c2,"MVFR2"))
continue;
/* decaof & dis2 agree on how VTBL, VTBX ranges should be represented */
if(strstr(c2,"VTB"))
continue;
/* Compare RHS */
int s1 = -1;
int s2 = -1;
......@@ -189,11 +222,11 @@ int diff_decaof(char *folder,char *one,char *two,char *out)
else
{
s1 = S_ID;
if(isalnum(*c1))
if(isalnum(*c1) || (*c1 == '.'))
{
do {
n1++;
} while(isalnum(c1[n1]));
} while(isalnum(c1[n1]) || (c1[n1] == '.'));
}
else
n1 = 1;
......@@ -240,11 +273,11 @@ int diff_decaof(char *folder,char *one,char *two,char *out)
else
{
s2 = S_ID;
if(isalnum(*c2))
if(isalnum(*c2) || (*c2 == '.'))
{
do {
n2++;
} while(isalnum(c2[n2]));
} while(isalnum(c2[n2]) || (c2[n2] == '.'));
}
else
{
......@@ -270,10 +303,21 @@ int diff_decaof(char *folder,char *one,char *two,char *out)
{
if((n1 != n2) || xstrnicmp(c1,c2,(size_t) n1))
{
/* dis2 currently uses 'CP' for coprocessor numbers, even in objasm mode */
if ((n2 == n1+1) && (c2[0] == 'C') && !xstrnicmp(c1,c2+1,(size_t) n1))
{
goto ok;
}
/* for things like VRINTA.F32.F32, decaof only outputs one .F32, while dis2 outputs two */
if ((n2 == n1 + 4) && (n1 > 4) && !xstrnicmp(c1,c2,(size_t) n1) && !xstrnicmp(c2+n1-4,c2+n1,4))
{
goto ok;
}
fprintf(fout,"ID mismatch:\n%s\n%s\n",b1,b2);
ret = 1;
break;
}
ok:
c1 += n1;
c2 += n2;
}
......@@ -297,11 +341,11 @@ int diff_debugger(char *folder,char *one,char *two,char *out)
char buf1[4096],buf2[4096];
FILE *fin1,*fin2,*fout;
sprintf(buf1,"%s.%s",folder,one);
fin1 = fopen(buf1,"r");
fin1 = xfopen(buf1,"r");
sprintf(buf1,"%s.%s",folder,two);
fin2 = fopen(buf1,"r");
fin2 = xfopen(buf1,"r");
sprintf(buf1,"%s.%s",folder,out);
fout = fopen(buf1,"w");
fout = xfopen(buf1,"w");
setvbuf(fin1,NULL,_IOFBF,65536);
setvbuf(fin2,NULL,_IOFBF,65536);
setvbuf(fout,NULL,_IOFBF,65536);
......@@ -423,61 +467,33 @@ void process(char *rawfile,char *folder,unsigned int *raw,unsigned int count)
int ret = 0;
#ifdef DECAOF
sprintf(buf,"binaof %s %s.aof foo foo -C",rawfile,folder);
if(system(buf))
{
fprintf(stderr,"binaof failed!\n");
exit(EXIT_FAILURE);
}
xsystem(buf);
#endif
printf("Disassembling\n");
#ifdef DEBUGGER
sprintf(buf,"dis2 %s 0x%08x -debugger > %s.dis2_debugger",rawfile,(unsigned int) raw,folder);
if(system(buf))
{
fprintf(stderr,"dis2 failed!\n");
exit(EXIT_FAILURE);
}
xsystem(buf);
sprintf(buf,"memoryi %08x + %08x { > %s.debugger }",(unsigned int) raw,count*4,folder);
if(system(buf))
{
fprintf(stderr,"memoryi failed!\n");
exit(EXIT_FAILURE);
}
xsystem(buf);
sprintf(buf,"settype %s.debugger fff",folder);
system(buf);
xsystem(buf);
#endif
#ifdef DECAOF
sprintf(buf,"dis2 %s 0 -decaof > %s.dis2_decaof",rawfile,folder);
if(system(buf))
{
fprintf(stderr,"dis2 failed!\n");
exit(EXIT_FAILURE);
}
xsystem(buf);
sprintf(buf,"dis2 %s 0 -decaofual > %s.dis2_decaofual",rawfile,folder);
if(system(buf))
{
fprintf(stderr,"dis2 failed!\n");
exit(EXIT_FAILURE);
}
xsystem(buf);
sprintf(buf,"decaof -c %s.aof > %s.decaof",folder,folder);
if(system(buf))
{
fprintf(stderr,"decaof failed!\n");
exit(EXIT_FAILURE);
}
xsystem(buf);
sprintf(buf,"decaof -uc %s.aof > %s.decaofual",folder,folder);
if(system(buf))
{
fprintf(stderr,"decaof failed!\n");
exit(EXIT_FAILURE);
}
xsystem(buf);
#endif
printf("Postprocessing\n");
#ifdef DECAOF
sprintf(buf,"grep \" 0x\" %s/decaof > %s/decaof2",folder,folder);
system(buf);
sprintf(buf,"grep \" 0x\" %s/decaofual > %s/decaofual2",folder,folder);
system(buf);
sprintf(buf,"grep \" 0x\" %s.decaof > %s.decaof2",folder,folder);
xsystem(buf);
sprintf(buf,"grep \" 0x\" %s.decaofual > %s.decaofual2",folder,folder);
xsystem(buf);
#endif
#ifndef MYDIFF
#ifdef DEBUGGER
......@@ -497,7 +513,7 @@ void process(char *rawfile,char *folder,unsigned int *raw,unsigned int count)
ret |= diff_debugger(folder,"debugger","dis2_debugger","diff_debugger");
#else
sprintf(buf,"gnudiff -u %s/debugger2 %s/dis2_debugger2 > %s/diff_debugger",folder,folder,folder);
system(buf);
xsystem(buf);
#endif
#endif
#ifdef DECAOF
......@@ -506,9 +522,9 @@ void process(char *rawfile,char *folder,unsigned int *raw,unsigned int count)
ret |= diff_decaof(folder,"decaofual2","dis2_decaofual","diff_decaofual");
#else
sprintf(buf,"gnudiff -ui %s/decaof3 %s/dis2_decaof2 > %s/diff_decaof",folder,folder,folder);
system(buf);
xsystem(buf);
sprintf(buf,"gnudiff -ui %s/decaofual3 %s/dis2_decaofual2 > %s/diff_decaofual",folder,folder,folder);
system(buf);
xsystem(buf);
#endif
#endif
if(ret)
......@@ -525,19 +541,14 @@ int main(int argc,char **argv)
fprintf(stderr,"usage: testbed <folder> <start> <count>\n");
fprintf(stderr,"or: testbed <folder> <start> <count> <repeat>\n");
fprintf(stderr,"or: testbed <folder> <file>\n");
exit(EXIT_FAILURE);
exit(257);
}
char *folder = argv[1];
unsigned int count,*raw,repeat;
if(argc == 3)
{
char *rawfile = argv[2];
FILE *f = fopen(rawfile,"rb");
if(!f)
{
fprintf(stderr,"Couldn't open '%s'\n",rawfile);
exit(EXIT_FAILURE);
}
FILE *f = xfopen(rawfile,"rb");
printf("Loading file\n");
fseek(f,0,SEEK_END);
count = (unsigned int) (ftell(f)>>2);
......
......@@ -11,13 +11,13 @@
GBLS Module_HelpVersion
GBLS Module_ComponentName
GBLS Module_ComponentPath
Module_MajorVersion SETS "2.01"
Module_Version SETA 201
Module_MajorVersion SETS "2.02"
Module_Version SETA 202
Module_MinorVersion SETS ""
Module_Date SETS "21 Feb 2018"
Module_ApplicationDate SETS "21-Feb-18"
Module_Date SETS "25 Feb 2018"
Module_ApplicationDate SETS "25-Feb-18"
Module_ComponentName SETS "Debugger"
Module_ComponentPath SETS "castle/RiscOS/Sources/Programmer/Debugger"
Module_FullVersion SETS "2.01"
Module_HelpVersion SETS "2.01 (21 Feb 2018)"
Module_FullVersion SETS "2.02"
Module_HelpVersion SETS "2.02 (25 Feb 2018)"
END
/* (2.01)
/* (2.02)
*
* This file is automatically maintained by srccommit, do not edit manually.
* Last processed by srccommit version: 1.1.
*
*/
#define Module_MajorVersion_CMHG 2.01
#define Module_MajorVersion_CMHG 2.02
#define Module_MinorVersion_CMHG
#define Module_Date_CMHG 21 Feb 2018
#define Module_Date_CMHG 25 Feb 2018
#define Module_MajorVersion "2.01"
#define Module_Version 201
#define Module_MajorVersion "2.02"
#define Module_Version 202
#define Module_MinorVersion ""
#define Module_Date "21 Feb 2018"
#define Module_Date "25 Feb 2018"
#define Module_ApplicationDate "21-Feb-18"
#define Module_ApplicationDate "25-Feb-18"
#define Module_ComponentName "Debugger"
#define Module_ComponentPath "castle/RiscOS/Sources/Programmer/Debugger"
#define Module_FullVersion "2.01"
#define Module_HelpVersion "2.01 (21 Feb 2018)"
#define Module_LibraryVersionInfo "2:1"
#define Module_FullVersion "2.02"
#define Module_HelpVersion "2.02 (25 Feb 2018)"
#define Module_LibraryVersionInfo "2:2"
......@@ -264,7 +264,7 @@ VCLS_A1(D:Vd,size,Q,M:Vm,nonstandard)
{
COMMON
ONLY1(ASIMD);
ASIMD_D_M(JUSTPARAMS,"CLS",size,0,Q,D_Vd,M_Vm);
ASIMD_D_M(JUSTPARAMS,"VCLS",size,0,Q,D_Vd,M_Vm);
return;
}
......@@ -650,7 +650,7 @@ VMOVN_A1(D:Vd,size,M:Vm,nonstandard)
{
COMMON
ONLY1(ASIMD);
sprintf(params->buf,"VMOVN%s.I%d\tD%d,Q%d",ASIMDCOND,8<<size,D_Vd,M_Vm>>1);
sprintf(params->buf,"VMOVN%s.I%d\tD%d,Q%d",ASIMDCOND,16<<size,D_Vd,M_Vm>>1);
return;
}
......@@ -1171,7 +1171,7 @@ VRSUBHN_A1(D:Vd,size,N:Vn,M:Vm,nonstandard)
{
COMMON
ONLY1(ASIMD);
ASIMD_I_DD_QN_QM(JUSTPARAMS,"VRSUBHN",size,D_Vd,N_Vn,M_Vm);
ASIMD_I_DD_QN_QM(JUSTPARAMS,"VRSUBHN",size+1,D_Vd,N_Vn,M_Vm);
return;
}
......
......@@ -155,7 +155,7 @@ VFNMA_VFNMS_A1(cond,D,Vn,Vd,sz,N,op,M,Vm,nonstandard)
_UNDEFINED(sz && !VFPDP);
COMMON
ONLY1(VFPv4);
VFP_CC_VD_VN_VM(JUSTPARAMS,(op?"VFNMS":"VFNMA"),(op?"VFNMS":"VFNMA"),cond,sz,Vd,D,Vn,N,Vm,M);
VFP_CC_VD_VN_VM(JUSTPARAMS,(op?"VFNMA":"VFNMS"),(op?"VFNMA":"VFNMS"),cond,sz,Vd,D,Vn,N,Vm,M);
return;
}
......
# Copyright 2018 Castle Technology Ltd
#
# 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.
#
# Actions for ARMv8 FP disassembly (just the ARMv8 bits)
VMAXNM_VMINNM_A1(op,D:Vd,N:Vn,Q,M:Vm,nonstandard)
{
COMMON
ONLY1(ARMv8);
ASIMD_F32_D_N_M(JUSTPARAMS,(op?"VMINNM":"VMAXNM"),Q,D_Vd,N_Vn,M_Vm);
return;
}
VMAXNM_VMINNM_A2(D,Vn,Vd,sz,op,N,M,Vm,nonstandard)
{
COMMON
ONLY1(ARMv8);
VFP_CC_VD_VN_VM(JUSTPARAMS,(op?"VMINNM":"VMAXNM"),(op?"VMINNM":"VMAXNM"),14,sz,Vd,D,Vn,N,Vm,M);
return;
}
VCVTx_ASIMD_A1(D:Vd,RM,op,Q,M:Vm,nonstandard)
{
COMMON
ONLY1(ARMv8);
const char rms[4] = {'A','N','P','M'};
sprintf(params->buf,(Q?"VCVT%c.%c32.F32\tQ%d,Q%d":"VCVT%c.%c32.F32\tD%d,D%d"),rms[RM],(op?'U':'S'),D_Vd>>Q,M_Vm>>Q);
return;
}
VCVTx_fp_A1(D,RM,Vd,sz,op,M,Vm,nonstandard)
{
COMMON
ONLY1(ARMv8);
const char rms[4] = {'A','N','P','M'};
if (sz)
{
sprintf(params->buf,"VCVT%c.%c32.F64\tS%d,D%d",rms[RM],(op?'S':'U'),(Vd<<1)|D,(M<<4)|Vm);
}
else
{
sprintf(params->buf,"VCVT%c.%c32.F32\tS%d,S%d",rms[RM],(op?'S':'U'),(Vd<<1)|D,(Vm<<1)|M);
}
return;
}
VCVTB_VCVTT_A1(cond,D,Vd,op,T,M,Vm,nonstandard)
{
COMMON
ONLY1(ARMv8);
if (op)
{
sprintf(params->buf,"VCVT%c%s.F16.F64\tS%d,D%d",(T?'T':'B'),condition(JUSTPARAMS,cond),(Vd<<1)|D,(M<<4)|Vm);
}
else
{
sprintf(params->buf,"VCVT%c%s.F64.F16\tD%d,S%d",(T?'T':'B'),condition(JUSTPARAMS,cond),(D<<4)|Vd,(Vm<<1)|M);
}
return;
}
VRINTx_ASIMD_A1(D:Vd,op,Q,M:Vm,nonstandard)
{
COMMON
ONLY1(ARMv8);
const char rms[4] = {'N','A','M','P'};
sprintf(params->buf,(Q?"VRINT%c.F32.F32\tQ%d,Q%d":"VRINT%c.F32.F32\tD%d,D%d"),rms[op>>1],D_Vd>>Q,M_Vm>>Q);
return;
}
VRINTx_fp_A1(D,RM,Vd,sz,M,Vm,nonstandard)
{
COMMON
ONLY1(ARMv8);
const char rms[4] = {'A','N','P','M'};
char opstr[12];
sprintf(opstr,"VRINT%c.F%d",rms[RM],(sz?64:32));
VFP_CC_VD_VM(JUSTPARAMS,opstr,opstr,14,sz,Vd,D,Vm,M);
return;
}
VRINTR_VRINTZ_fp_A1(cond,D,Vd,sz,op,M,Vm,nonstandard)
{
COMMON
ONLY1(ARMv8);
char opstr[16];
sprintf(opstr,"VRINT%c%s.F%d",(op?'Z':'R'),condition(JUSTPARAMS,cond),(sz?64:32));
VFP_CC_VD_VM(JUSTPARAMS,opstr,opstr,14,sz,Vd,D,Vm,M);
return;
}
VRINTX_ASIMD_A1(D:Vd,Q,M:Vm,nonstandard)
{
COMMON
ONLY1(ARMv8);
sprintf(params->buf,(Q?"VRINTX.F32.F32\tQ%d,Q%d":"VRINTX.F32.F32\tD%d,D%d"),D_Vd>>Q,M_Vm>>Q);
return;
}
VRINTZ_ASIMD_A1(D:Vd,Q,M:Vm,nonstandard)
{
COMMON
ONLY1(ARMv8);
sprintf(params->buf,(Q?"VRINTZ.F32.F32\tQ%d,Q%d":"VRINTZ.F32.F32\tD%d,D%d"),D_Vd>>Q,M_Vm>>Q);
return;
}
VRINTX_fp_A1(cond,D,Vd,sz,M,Vm,nonstandard)
{
COMMON
ONLY1(ARMv8);
char opstr[16];
sprintf(opstr,"VRINTX%s.F%d",condition(JUSTPARAMS,cond),(sz?64:32));
VFP_CC_VD_VM(JUSTPARAMS,opstr,opstr,14,sz,Vd,D,Vm,M);
return;
}
VSELxx_A1(D,cc,Vn,Vd,sz,N,M,Vm,nonstandard)
{
COMMON
ONLY1(ARMv8);
const char conds[4] = {0,6,10,12};
VFP_CC_VD_VN_VM(JUSTPARAMS,"VSEL","VSEL",conds[cc],sz,Vd,D,Vn,N,Vm,M);
return;
}
......@@ -65,7 +65,7 @@ const optval vfp_mrs[16] =
{ "c2", false },
{ "c3", false },
{ "c4", false },
{ "c5", false },
{ "MVFR2", true },
{ "MVFR1", true },
{ "MVFR0", true },
{ "FPEXC", true },
......
No preview for this file type
......@@ -55,7 +55,7 @@ Instruction Entry "r0, r3-r9"
BEQ Swi ; [software interrupt = 0F]
CMP r3, #&0C
BHS Coprocessor ; [coproc 0C..0E]
BHS Coprocessor_Conditional ; [coproc 0C..0E]
CMP r3, #&0A
BHS Branch ; [branch = 0A..0B]
......@@ -72,11 +72,8 @@ Instruction Entry "r0, r3-r9"
TEQS r3, #&0F
BEQ Undefined ; [undefined = 0F]
CMP r3, #&0E
BEQ Co_Operations ; [coprocessor = 0E]
CMP r3, #&0C
BHS Co_Transfer ; [coprocessor = 0C,0D]
BHS Coprocessor_Unconditional ; [coproc 0C..0E]
CMP r3, #&0A
BHS BLX_offset ; [BLX = 0A,0B]
......@@ -1786,14 +1783,24 @@ Mrrc DCB "MRRC", 0
; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Coprocessor
Coprocessor_Unconditional
; Coprocessor operations
; arrive here with cccc 11nn xxxx xxxx xxxx xxxx xxxx xxxx
; arrive here with 1111 11nn xxxx xxxx xxxx xxxx xxxx xxxx
; with nn <> 11
MOV r2, r4, LSR #28 ; No currently known coprocessors use "2" opcodes
TEQ r2, #15
BEQ Coprocessor_NotFP
; So far, ARMv8 VFP are the only known instructions that fit here
[ UseCVFPNEON
AND r2, r4, #2_1111 :SHL: 8 ; r2 := CP# << 8
TEQ r2, #10 :SHL: 8
TEQNE r2, #11 :SHL: 8
BEQ VFP
]
B Coprocessor_NotFP
Coprocessor_Conditional
; Coprocessor operations
; arrive here with cccc 11nn xxxx xxxx xxxx xxxx xxxx xxxx
; with nn <> 11, cccc <> 1111
ANDS r2, r4, #2_1111 :SHL: 8 ; r2 := CP# << 8
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment