* patch by Jeppe Johansen to add support for handling different flags for xPSR regs,

and add usermode parsing of LDM/STM ops
  This patch basically extends the ARM assembly reader a bit to properly parse CPSR and 
  SPSR flags for the MSR opcode, and allows the reader to understand 
  the ^ modifer for register lists for STMxx and LDMxx.

  Previously the following combinations weren't possible in straight assembler:
     MRS R0, CPSR
     MRS R0, SPSR
     MSR CPSR_CX, R0
     LDMIA SP, {R0-R15}^
     etc.. 

git-svn-id: trunk@22502 -
This commit is contained in:
florian 2012-09-29 08:23:40 +00:00
parent 0a755be6fe
commit 54d3d736f5
18 changed files with 160 additions and 18 deletions

1
.gitattributes vendored
View File

@ -12888,6 +12888,7 @@ tests/webtbs/tw2289.pp svneol=native#text/plain
tests/webtbs/tw2291.pp svneol=native#text/plain tests/webtbs/tw2291.pp svneol=native#text/plain
tests/webtbs/tw2294.pp svneol=native#text/plain tests/webtbs/tw2294.pp svneol=native#text/plain
tests/webtbs/tw2296.pp svneol=native#text/plain tests/webtbs/tw2296.pp svneol=native#text/plain
tests/webtbs/tw22992.pp svneol=native#text/pascal
tests/webtbs/tw2300.pp svneol=native#text/plain tests/webtbs/tw2300.pp svneol=native#text/plain
tests/webtbs/tw2305.pp svneol=native#text/plain tests/webtbs/tw2305.pp svneol=native#text/plain
tests/webtbs/tw2306.pp svneol=native#text/plain tests/webtbs/tw2306.pp svneol=native#text/plain

View File

@ -201,6 +201,7 @@ interface
,top_shifterop ,top_shifterop
,top_conditioncode ,top_conditioncode
,top_modeflags ,top_modeflags
,top_specialreg
{$endif arm} {$endif arm}
{$ifdef m68k} {$ifdef m68k}
{ m68k only } { m68k only }
@ -241,10 +242,11 @@ interface
{ local varsym that will be inserted in pass_generate_code } { local varsym that will be inserted in pass_generate_code }
top_local : (localoper:plocaloper); top_local : (localoper:plocaloper);
{$ifdef arm} {$ifdef arm}
top_regset : (regset:^tcpuregisterset; regtyp: tregistertype; subreg: tsubregister); top_regset : (regset:^tcpuregisterset; regtyp: tregistertype; subreg: tsubregister; usermode: boolean);
top_shifterop : (shifterop : pshifterop); top_shifterop : (shifterop : pshifterop);
top_conditioncode : (cc : TAsmCond); top_conditioncode : (cc : TAsmCond);
top_modeflags : (modeflags : tcpumodeflags); top_modeflags : (modeflags : tcpumodeflags);
top_specialreg : (specialreg:tregister; specialflags:tspecialregflags);
{$endif arm} {$endif arm}
{$ifdef m68k} {$ifdef m68k}
top_regset : (regset:^tcpuregisterset); top_regset : (regset:^tcpuregisterset);

View File

@ -161,9 +161,10 @@ uses
wideformat : boolean; wideformat : boolean;
roundingmode : troundingmode; roundingmode : troundingmode;
procedure loadshifterop(opidx:longint;const so:tshifterop); procedure loadshifterop(opidx:longint;const so:tshifterop);
procedure loadregset(opidx:longint; regsetregtype: tregistertype; regsetsubregtype: tsubregister; const s:tcpuregisterset); procedure loadregset(opidx:longint; regsetregtype: tregistertype; regsetsubregtype: tsubregister; const s:tcpuregisterset; ausermode: boolean=false);
procedure loadconditioncode(opidx:longint;const cond:tasmcond); procedure loadconditioncode(opidx:longint;const cond:tasmcond);
procedure loadmodeflags(opidx:longint;const flags:tcpumodeflags); procedure loadmodeflags(opidx:longint;const flags:tcpumodeflags);
procedure loadspecialreg(opidx:longint;const areg:tregister; const aflags:tspecialregflags);
constructor op_none(op : tasmop); constructor op_none(op : tasmop);
constructor op_reg(op : tasmop;_op1 : tregister); constructor op_reg(op : tasmop;_op1 : tregister);
@ -192,6 +193,9 @@ uses
constructor op_modeflags(op: tasmop; flags: tcpumodeflags); constructor op_modeflags(op: tasmop; flags: tcpumodeflags);
constructor op_modeflags_const(op: tasmop; flags: tcpumodeflags; a: aint); constructor op_modeflags_const(op: tasmop; flags: tcpumodeflags; a: aint);
{ MSR }
constructor op_specialreg_reg(op: tasmop; specialreg: tregister; specialregflags: tspecialregflags; _op2: tregister);
{ *M*LL } { *M*LL }
constructor op_reg_reg_reg_reg(op : tasmop;_op1,_op2,_op3,_op4 : tregister); constructor op_reg_reg_reg_reg(op : tasmop;_op1,_op2,_op3,_op4 : tregister);
@ -286,7 +290,7 @@ implementation
end; end;
procedure taicpu.loadregset(opidx:longint; regsetregtype: tregistertype; regsetsubregtype: tsubregister; const s:tcpuregisterset); procedure taicpu.loadregset(opidx:longint; regsetregtype: tregistertype; regsetsubregtype: tsubregister; const s:tcpuregisterset; ausermode: boolean);
var var
i : byte; i : byte;
begin begin
@ -301,6 +305,7 @@ implementation
regset^:=s; regset^:=s;
regtyp:=regsetregtype; regtyp:=regsetregtype;
subreg:=regsetsubregtype; subreg:=regsetsubregtype;
usermode:=ausermode;
typ:=top_regset; typ:=top_regset;
case regsetregtype of case regsetregtype of
R_INTREGISTER: R_INTREGISTER:
@ -345,6 +350,19 @@ implementation
end; end;
end; end;
procedure taicpu.loadspecialreg(opidx: longint; const areg: tregister; const aflags: tspecialregflags);
begin
allocate_oper(opidx+1);
with oper[opidx]^ do
begin
if typ<>top_specialreg then
clearop(opidx);
specialreg:=areg;
specialflags:=aflags;
typ:=top_specialreg;
end;
end;
{***************************************************************************** {*****************************************************************************
taicpu Constructors taicpu Constructors
*****************************************************************************} *****************************************************************************}
@ -479,6 +497,13 @@ implementation
loadconst(1,a); loadconst(1,a);
end; end;
constructor taicpu.op_specialreg_reg(op: tasmop; specialreg: tregister; specialregflags: tspecialregflags; _op2: tregister);
begin
inherited create(op);
ops:=2;
loadspecialreg(0,specialreg,specialregflags);
loadreg(1,_op2);
end;
constructor taicpu.op_reg_reg_sym_ofs(op : tasmop;_op1,_op2 : tregister; _op3: tasmsymbol;_op3ofs: longint); constructor taicpu.op_reg_reg_sym_ofs(op : tasmop;_op1,_op2 : tregister; _op3: tasmsymbol;_op3ofs: longint);
begin begin

View File

@ -215,6 +215,8 @@ unit agarmgas;
first:=false; first:=false;
end; end;
getopstr:=getopstr+'}'; getopstr:=getopstr+'}';
if o.usermode then
getopstr:=getopstr+'^';
end; end;
top_conditioncode: top_conditioncode:
getopstr:=cond2str[o.cc]; getopstr:=cond2str[o.cc];
@ -238,6 +240,18 @@ unit agarmgas;
end end
else else
getopstr:=getreferencestring(o.ref^); getopstr:=getreferencestring(o.ref^);
top_specialreg:
begin
getopstr:=gas_regname(o.specialreg);
if o.specialflags<>[] then
begin
getopstr:=getopstr+'_';
if srC in o.specialflags then getopstr:=getopstr+'c';
if srX in o.specialflags then getopstr:=getopstr+'x';
if srF in o.specialflags then getopstr:=getopstr+'f';
if srS in o.specialflags then getopstr:=getopstr+'s';
end;
end
else else
internalerror(2002070604); internalerror(2002070604);
end; end;

View File

@ -107,5 +107,6 @@ D30,$04,$07,$1E,d30,0,0
D31,$04,$07,$1F,d31,0,0 D31,$04,$07,$1F,d31,0,0
; special registers ; special registers
CPSR_C,$05,$00,$00,cpsr_c,0,0 CPSR,$05,$00,$00,cpsr,0,0
FPSCR,$05,$00,$01,fpscr,0,0 FPSCR,$05,$00,$01,fpscr,0,0
SPSR,$05,$00,$02,spsr,0,0

View File

@ -215,6 +215,9 @@ unit cpubase;
tcpumodeflag = (mfA, mfI, mfF); tcpumodeflag = (mfA, mfI, mfF);
tcpumodeflags = set of tcpumodeflag; tcpumodeflags = set of tcpumodeflag;
tspecialregflag = (srC, srX, srS, srF);
tspecialregflags = set of tspecialregflag;
{***************************************************************************** {*****************************************************************************
Constants Constants
*****************************************************************************} *****************************************************************************}
@ -296,8 +299,8 @@ unit cpubase;
{ Offset where the parent framepointer is pushed } { Offset where the parent framepointer is pushed }
PARENT_FRAMEPOINTER_OFFSET = 0; PARENT_FRAMEPOINTER_OFFSET = 0;
NR_DEFAULTFLAGS = NR_CPSR_C; NR_DEFAULTFLAGS = NR_CPSR;
RS_DEFAULTFLAGS = RS_CPSR_C; RS_DEFAULTFLAGS = RS_CPSR;
{ Low part of 64bit return value } { Low part of 64bit return value }
function NR_FUNCTION_RESULT64_LOW_REG: tregister;{$ifdef USEINLINE}inline;{$endif USEINLINE} function NR_FUNCTION_RESULT64_LOW_REG: tregister;{$ifdef USEINLINE}inline;{$endif USEINLINE}

View File

@ -38,6 +38,7 @@ Unit raarmgas;
procedure handleopcode;override; procedure handleopcode;override;
procedure BuildReference(oper : tarmoperand); procedure BuildReference(oper : tarmoperand);
procedure BuildOperand(oper : tarmoperand); procedure BuildOperand(oper : tarmoperand);
procedure BuildSpecialreg(oper : tarmoperand);
function TryBuildShifterOp(oper : tarmoperand) : boolean; function TryBuildShifterOp(oper : tarmoperand) : boolean;
procedure BuildOpCode(instr : tarminstruction); procedure BuildOpCode(instr : tarminstruction);
procedure ReadSym(oper : tarmoperand); procedure ReadSym(oper : tarmoperand);
@ -925,6 +926,13 @@ Unit raarmgas;
oper.opr.regtype:=regtype; oper.opr.regtype:=regtype;
oper.opr.subreg:=subreg; oper.opr.subreg:=subreg;
oper.opr.regset:=registerset; oper.opr.regset:=registerset;
if actasmtoken=AS_XOR then
begin
consume(AS_XOR);
oper.opr.usermode:=true;
end
else
oper.opr.usermode:=false;
if (registerset=[]) then if (registerset=[]) then
Message(asmr_e_empty_regset); Message(asmr_e_empty_regset);
end; end;
@ -939,6 +947,68 @@ Unit raarmgas;
end; { end case } end; { end case }
end; end;
procedure tarmattreader.BuildSpecialreg(oper: tarmoperand);
var
hs, reg : String;
ch : char;
i, t : longint;
hreg : tregister;
flags : tspecialregflags;
begin
case actasmtoken of
AS_REGISTER:
begin
oper.opr.typ:=OPR_REGISTER;
oper.opr.reg:=actasmregister;
Consume(AS_REGISTER);
end;
AS_ID:
begin
t := pos('_', actasmpattern);
if t > 0 then
begin
hs:=lower(actasmpattern);
reg:=copy(hs, 1, t-1);
delete(hs, 1, t);
if length(hs) < 1 then
Message(asmr_e_invalid_operand_type);
if reg = 'cpsr' then
hreg:=NR_CPSR
else if reg='spsr' then
hreg:=NR_SPSR
else
Message(asmr_e_invalid_register);
flags:=[];
for i := 1 to length(hs) do
begin
ch:=hs[i];
if ch='c' then
include(flags, srC)
else if ch='x' then
include(flags, srX)
else if ch='f' then
include(flags, srF)
else if ch='s' then
include(flags, srS)
else
message(asmr_e_invalid_operand_type);
end;
oper.opr.typ:=OPR_SPECIALREG;
oper.opr.specialreg:=hreg;
oper.opr.specialregflags:=flags;
consume(AS_ID);
end
else
Message(asmr_e_invalid_operand_type); // Otherwise it would have been seen as a AS_REGISTER
end;
end;
end;
{***************************************************************************** {*****************************************************************************
tarmattreader tarmattreader
@ -1001,7 +1071,10 @@ Unit raarmgas;
break; break;
end; end;
else else
BuildOperand(instr.Operands[operandnum] as tarmoperand); if (instr.opcode = A_MSR) and (operandnum = 1) then
BuildSpecialreg(instr.Operands[operandnum] as tarmoperand)
else
BuildOperand(instr.Operands[operandnum] as tarmoperand);
end; { end case } end; { end case }
until false; until false;
instr.Ops:=operandnum; instr.Ops:=operandnum;

View File

@ -88,5 +88,6 @@ NR_D28 = tregister($0407001C);
NR_D29 = tregister($0407001D); NR_D29 = tregister($0407001D);
NR_D30 = tregister($0407001E); NR_D30 = tregister($0407001E);
NR_D31 = tregister($0407001F); NR_D31 = tregister($0407001F);
NR_CPSR_C = tregister($05000000); NR_CPSR = tregister($05000000);
NR_FPSCR = tregister($05000001); NR_FPSCR = tregister($05000001);
NR_SPSR = tregister($05000002);

View File

@ -89,4 +89,5 @@
0, 0,
0, 0,
0, 0,
0,
0 0

View File

@ -1,2 +1,2 @@
{ don't edit, this file is generated from armreg.dat } { don't edit, this file is generated from armreg.dat }
91 92

View File

@ -89,4 +89,5 @@ tregister($0407001D),
tregister($0407001E), tregister($0407001E),
tregister($0407001F), tregister($0407001F),
tregister($05000000), tregister($05000000),
tregister($05000001) tregister($05000001),
tregister($05000002)

View File

@ -89,4 +89,5 @@
87, 87,
88, 88,
89, 89,
90 90,
91

View File

@ -89,4 +89,5 @@
34, 34,
35, 35,
37, 37,
38 38,
91

View File

@ -89,4 +89,5 @@
0, 0,
0, 0,
0, 0,
0,
0 0

View File

@ -88,5 +88,6 @@
'd29', 'd29',
'd30', 'd30',
'd31', 'd31',
'cpsr_c', 'cpsr',
'fpscr' 'fpscr',
'spsr'

View File

@ -88,5 +88,6 @@ RS_D28 = $1C;
RS_D29 = $1D; RS_D29 = $1D;
RS_D30 = $1E; RS_D30 = $1E;
RS_D31 = $1F; RS_D31 = $1F;
RS_CPSR_C = $00; RS_CPSR = $00;
RS_FPSCR = $01; RS_FPSCR = $01;
RS_SPSR = $02;

View File

@ -72,7 +72,7 @@ Function SearchLabel(const s: string; var hl: tasmlabel;emit:boolean): boolean;
type type
TOprType=(OPR_NONE,OPR_CONSTANT,OPR_SYMBOL,OPR_LOCAL, TOprType=(OPR_NONE,OPR_CONSTANT,OPR_SYMBOL,OPR_LOCAL,
OPR_REFERENCE,OPR_REGISTER,OPR_REGLIST,OPR_COND,OPR_REGSET,OPR_SHIFTEROP,OPR_MODEFLAGS); OPR_REFERENCE,OPR_REGISTER,OPR_REGLIST,OPR_COND,OPR_REGSET,OPR_SHIFTEROP,OPR_MODEFLAGS,OPR_SPECIALREG);
TOprRec = record TOprRec = record
case typ:TOprType of case typ:TOprType of
@ -92,10 +92,11 @@ type
OPR_COND : (cond : tasmcond); OPR_COND : (cond : tasmcond);
{$endif POWERPC64} {$endif POWERPC64}
{$ifdef arm} {$ifdef arm}
OPR_REGSET : (regset : tcpuregisterset; regtype: tregistertype; subreg: tsubregister); OPR_REGSET : (regset : tcpuregisterset; regtype: tregistertype; subreg: tsubregister; usermode: boolean);
OPR_SHIFTEROP : (shifterop : tshifterop); OPR_SHIFTEROP : (shifterop : tshifterop);
OPR_COND : (cc : tasmcond); OPR_COND : (cc : tasmcond);
OPR_MODEFLAGS : (flags : tcpumodeflags); OPR_MODEFLAGS : (flags : tcpumodeflags);
OPR_SPECIALREG: (specialreg : tregister; specialregflags : tspecialregflags);
{$endif arm} {$endif arm}
end; end;
@ -1091,13 +1092,15 @@ end;
ai.loadref(i-1,ref); ai.loadref(i-1,ref);
{$ifdef ARM} {$ifdef ARM}
OPR_REGSET: OPR_REGSET:
ai.loadregset(i-1,regtype,subreg,regset); ai.loadregset(i-1,regtype,subreg,regset,usermode);
OPR_SHIFTEROP: OPR_SHIFTEROP:
ai.loadshifterop(i-1,shifterop); ai.loadshifterop(i-1,shifterop);
OPR_COND: OPR_COND:
ai.loadconditioncode(i-1,cc); ai.loadconditioncode(i-1,cc);
OPR_MODEFLAGS: OPR_MODEFLAGS:
ai.loadmodeflags(i-1,flags); ai.loadmodeflags(i-1,flags);
OPR_SPECIALREG:
ai.loadspecialreg(i-1,specialreg,specialregflags);
{$endif ARM} {$endif ARM}
{ ignore wrong operand } { ignore wrong operand }
OPR_NONE: OPR_NONE:

12
tests/webtbs/tw22992.pp Normal file
View File

@ -0,0 +1,12 @@
{ %norun }
{ %cpu=arm }
begin
asm
MRS R0, CPSR
MRS R0, SPSR
MSR CPSR_CX, R0
LDMIA SP, {R0-R15}^
end;
end.