Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SPARC: Bugfixes and improvements #6346

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
228 changes: 129 additions & 99 deletions Ghidra/Processors/Sparc/data/languages/SparcV9.sinc
Expand Up @@ -486,8 +486,9 @@ macro unpackflags(ccr) {
:addcc RS1,regorimm,RD is op=2 & RD & op3=0x10 & RS1 & regorimm
{
addflags(RS1,regorimm);
RD = RS1 + regorimm;
zeroflags(RD);
local res:$(SIZE) = RS1 + regorimm;
zeroflags(res);
RD = res;
}

:addc RS1,regorimm,RD is op=2 & RD & op3=0x8 & RS1 & regorimm {RD = RS1 + regorimm + zext(i_cf);}
Expand All @@ -496,59 +497,66 @@ macro unpackflags(ccr) {
{
local original_i_cf:$(SIZE) = zext(i_cf);
addCarryFlags(RS1,regorimm);
RD = RS1 + regorimm + original_i_cf;
zeroflags(RD);
local res:$(SIZE) = RS1 + regorimm + original_i_cf;
zeroflags(res);
RD = res;
}
#-----------------------
:and RS1,regorimm,RD is op=2 & RD & op3=0x1 & RS1 & regorimm {RD = RS1 & regorimm;}

:andcc RS1,regorimm,RD is op=2 & RD & op3=0x11 & RS1 & regorimm
{
logicflags();
RD = RS1 & regorimm;
zeroflags(RD);
local res:$(SIZE) = RS1 & regorimm;
zeroflags(res);
RD = res;
}
:andn RS1,regorimm,RD is op=2 & RD & op3=0x5 & RS1 & regorimm {RD = RS1 & ~regorimm;}

:andncc RS1,regorimm,RD is op=2 & RD & op3=0x15 & RS1 & regorimm
{
logicflags();
RD = RS1 & ~regorimm;
zeroflags(RD);
local res:$(SIZE) = RS1 & ~regorimm;
zeroflags(res);
RD = res;
}

:or RS1,regorimm,RD is op=2 & RD & op3=0x2 & RS1 & regorimm {RD = RS1 | regorimm;}

:orcc RS1,regorimm,RD is op=2 & RD & op3=0x12 & RS1 & regorimm
{
logicflags();
RD = RS1 | regorimm;
zeroflags(RD);
local res:$(SIZE) = RS1 | regorimm;
zeroflags(res);
RD = res;
}
:orn RS1,regorimm,RD is op=2 & RD & op3=0x6 & RS1 & regorimm {RD = RS1 | ~regorimm;}

:orncc RS1,regorimm,RD is op=2 & RD & op3=0x16 & RS1 & regorimm
{
logicflags();
RD = RS1 | ~regorimm;
zeroflags(RD);
local res:$(SIZE) = RS1 | ~regorimm;
zeroflags(res);
RD = res;
}
:xor RS1,regorimm,RD is op=2 & RD & op3=0x3 & RS1 & regorimm {RD = RS1 ^ regorimm;}

:xorcc RS1,regorimm,RD is op=2 & RD & op3=0x13 & RS1 & regorimm
{
logicflags();
RD = RS1 ^ regorimm;
zeroflags(RD);
local res:$(SIZE) = RS1 ^ regorimm;
zeroflags(res);
RD = res;
}

:xnor RS1,regorimm,RD is op=2 & RD & op3=0x7 & RS1 & regorimm {RD = RS1 ^ ~regorimm;}

:xnorcc RS1,regorimm,RD is op=2 & RD & op3=0x17 & RS1 & regorimm
{
logicflags();
RD = RS1 ^ ~regorimm;
zeroflags(RD);
local res:$(SIZE) = RS1 ^ ~regorimm;
zeroflags(res);
RD = res;
}

# ---------------
Expand Down Expand Up @@ -609,8 +617,9 @@ macro unpackflags(ccr) {
:subcc RS1,regorimm,RD is op=2 & RD & op3=0x14 & RS1 & regorimm
{
subflags(RS1,regorimm);
RD = RS1 - regorimm;
zeroflags(RD);
local res:$(SIZE) = RS1 - regorimm;
zeroflags(res);
RD = res;
}

:subc RS1,regorimm,RD is op=2 & RD & op3=0xc & RS1 & regorimm
Expand All @@ -622,8 +631,9 @@ macro unpackflags(ccr) {
{
local original_cf:$(SIZE) = zext(i_cf);
subCarryFlags(RS1,regorimm);
RD = RS1 - regorimm - original_cf;
zeroflags(RD);
local res:$(SIZE) = RS1 - regorimm - original_cf;
zeroflags(res);
RD = res;
}

# ---------------
Expand All @@ -635,8 +645,8 @@ macro unpackflags(ccr) {
:cmp RS1,regorimm is op=0x2 & rd=0x0 & op3=0x14 & RS1 & regorimm
{
subflags(RS1,regorimm);
local tmp = RS1 - regorimm;
zeroflags(tmp);
local res:$(SIZE) = RS1 - regorimm;
zeroflags(res);
}


Expand Down Expand Up @@ -819,51 +829,49 @@ callreloff: reloc is disp30 [reloc=inst_start+4*disp30;] { export *:$(SIZE) rel

#----------------MULTIPLY 32 bit
@if SIZE=="8"
:umul RS1,regorimm,RD is op=2 & RD & op3=0x0a & RS1 & regorimm {RD = zext(RS1:4) * zext(regorimm:4); Y=RD>>32;}
:smul RS1,regorimm,RD is op=2 & RD & op3=0x0b & RS1 & regorimm {RD = sext(RS1:4) * sext(regorimm:4); Y=RD>>32;}
:umulcc RS1,regorimm,RD is op=2 & RD & op3=0x1a & RS1 & regorimm {RD = zext(RS1:4) * zext(regorimm:4); Y=RD>>32; zeroflags(RD); logicflags();}
:smulcc RS1,regorimm,RD is op=2 & RD & op3=0x1b & RS1 & regorimm {RD = sext(RS1:4) * sext(regorimm:4); Y=RD>>32; zeroflags(RD); logicflags();}
:umul RS1,regorimm,RD is op=2 & RD & op3=0x0a & RS1 & regorimm {local res:8 = zext(RS1:4) * zext(regorimm:4); Y=res >> 32; RD = res:4;}
:smul RS1,regorimm,RD is op=2 & RD & op3=0x0b & RS1 & regorimm {local res:8 = sext(RS1:4) * sext(regorimm:4); Y=res s>> 32; RD = res:4;}
:umulcc RS1,regorimm,RD is op=2 & RD & op3=0x1a & RS1 & regorimm {local res:8 = zext(RS1:4) * zext(regorimm:4); Y=res >> 32; zeroflags(res:4); RD = res:4; logicflags();}
:smulcc RS1,regorimm,RD is op=2 & RD & op3=0x1b & RS1 & regorimm {local res:8 = sext(RS1:4) * sext(regorimm:4); Y=res s>> 32; zeroflags(res:4); RD = res:4; logicflags();}

@else
# size = 4
:umul RS1,regorimm,RD is op=2 & RD & op3=0x0a & RS1 & regorimm
:umul RS1,regorimm,RD is op=2 & RD & op3=0x0a & RS1 & regorimm
{
tmp_RS1:8 = zext(RS1);
tmp_regorimm:8 = zext(regorimm);
tmp:8 = tmp_RS1 * tmp_regorimm;
RD = tmp:4; tmp2:8 = tmp >> 32;
Y = tmp2:4;
local res:8 = zext(RS1:4) * zext(regorimm:4);
Y = res[32,32];
RD = res:4;
}

:smul RS1,regorimm,RD is op=2 & RD & op3=0x0b & RS1 & regorimm
:smul RS1,regorimm,RD is op=2 & RD & op3=0x0b & RS1 & regorimm
{
tmp_RS1:8 = sext(RS1);
tmp_regorimm:8 = sext(regorimm);
tmp:8 = tmp_RS1 * tmp_regorimm;
RD = tmp:4; tmp2:8 = tmp >> 32;
Y = tmp2:4;
local res:8 = sext(RS1:4) * sext(regorimm:4);
Y = res[32,32];
RD = res:4;
}

:umulcc RS1,regorimm,RD is op=2 & RD & op3=0x1a & RS1 & regorimm
:umulcc RS1,regorimm,RD is op=2 & RD & op3=0x1a & RS1 & regorimm
{
RD = zext(RS1:4) * zext(regorimm:4);
Y=RD>>32;
zeroflags(RD);
local res:8 = zext(RS1:4) * zext(regorimm:4);
Y = res[32,32];
zeroflags(res:4);
RD = res:4;
logicflags();
}
:smulcc RS1,regorimm,RD is op=2 & RD & op3=0x1b & RS1 & regorimm
:smulcc RS1,regorimm,RD is op=2 & RD & op3=0x1b & RS1 & regorimm
{
RD = zext(RS1:4) * zext(regorimm:4);
Y=RD>>32;
zeroflags(RD);
local res:8 = sext(RS1:4) * sext(regorimm:4);
Y = res[32,32];
zeroflags(res:4);
RD = res:4;
logicflags();
}

@endif

#----------------MULTIPLY Step

:mulscc RS1,regorimm,RD is op=2 & RD & op3=0x24 & RS1 & regorimm
:mulscc RS1,regorimm,RD is op=2 & RD & op3=0x24 & RS1 & regorimm
{
local ccr:4 = zext(i_nf ^^ i_vf);
ccr = ccr << 31;
Expand All @@ -877,48 +885,53 @@ callreloff: reloc is disp30 [reloc=inst_start+4*disp30;] { export *:$(SIZE) rel
addflags32(addend,shifted);
#upper 32 bits of RD are undefined according to the manual
local tbit:4 = (RS1:4 & 0x1:4) << 31;
RD = zext(sum);
zeroflags(RD);
local res:$(SIZE) = zext(sum);
zeroflags(res);
RD = res;
#Y is 64 bits in Sparc 9 but the high 32 are fixed to 0
Y = zext((Y:4 >> 1:4) | tbit);
}

#----------------DIVIDE (64-bit / 32-bit)

# NB- Beware, the plus + operator has higher precedence than shift <<
# (These are Java rules. C rules have shift and + at the same level, so left to right)

:udiv RS1,regorimm,RD is op=2 & RD & op3=0x0e & RS1 & regorimm
:udiv RS1,regorimm,RD is op=2 & RD & op3=0x0e & RS1 & regorimm
{
numerator:$(SIZE)= (Y << 32) + (RS1 & 0xffffffff);
denom:$(SIZE) = regorimm & 0xffffffff;
RD = numerator / denom;
numerator:8 = (zext(Y) << 32) + zext(RS1);
denom:8 = zext(regorimm:4)
mumbel marked this conversation as resolved.
Show resolved Hide resolved
local res:8 = numerator / denom;
RD = zext(res:4);
}
:sdiv RS1,regorimm,RD is op=2 & RD & op3=0x0f & RS1 & regorimm
:sdiv RS1,regorimm,RD is op=2 & RD & op3=0x0f & RS1 & regorimm
{
numerator:$(SIZE)= (Y << 32) + (RS1 & 0xffffffff);
denom:$(SIZE) = regorimm & 0xffffffff;
RD = numerator s/ denom;
}
numerator:8 = (sext(Y) << 32) + zext(RS1:4);
denom:8 = sext(regorimm:4);
local res:8 = numerator s/ denom;
RD = sext(res:4);
}

:udivcc RS1,regorimm,RD is op=2 & RD & op3=0x1e & RS1 & regorimm
:udivcc RS1,regorimm,RD is op=2 & RD & op3=0x1e & RS1 & regorimm
{
numerator:$(SIZE)= ( Y << 32) + (RS1 & 0xffffffff);
denom:$(SIZE) = regorimm & 0xffffffff;
RD = numerator / denom;
zeroflags(RD);
i_vf = RD > 0xffffffff;
numerator:8 = (zext(Y) << 32) + zext(RS1:4);
denom:8 = zext(regorimm:4)
mumbel marked this conversation as resolved.
Show resolved Hide resolved
local res:8 = numerator / denom;
zeroflags(res:4);
RD = zext(res:4);
i_vf = res > 0xffffffff;
i_cf = 0;
x_vf = 0;
x_cf = 0;
}
:sdivcc RS1,regorimm,RD is op=2 & RD & op3=0x1f & RS1 & regorimm
:sdivcc RS1,regorimm,RD is op=2 & RD & op3=0x1f & RS1 & regorimm
{
numerator:$(SIZE)= (Y << 32) + (RS1 & 0xffffffff);
denom:$(SIZE) = regorimm & 0xffffffff;
RD = numerator s/ denom;
zeroflags(RD);
i_vf = (RD s>= 0x80000000) || (RD s<= -0x7ffffffff);
numerator:8 = (sext(Y) << 32) + (zext(RS1) & 0xffffffff);
denom:8 = sext(regorimm:4);
local res:8 = numerator s/ denom;
zeroflags(res:4);
RD = sext(res:4);
i_vf = (res s>= 0x80000000) || (res s<= -0x7ffffffff);
i_cf = 0;
x_vf = 0;
x_cf = 0;
Expand Down Expand Up @@ -984,69 +997,86 @@ sethidisp: "%hi("^hi^")" is udisp22 [hi=udisp22<<10;] { export *[const]:$(SIZE)
:restore RS1,regorimm,RD is op=0x2 & RD & op3=0x3d & RS1 & regorimm { local tmp = RS1 + regorimm; restore(); didrestore=1; RD = tmp; }
:restore is op=0x2 & rd=0 & op3=0x3d { restore(); didrestore=1; }

# FIXME 'jmpl' can have 'return' in the delayslot to return from a user trap handler
# - jmpl sets the trapped PC supplied to user trap handler
# - return sets the trapped nPC supplied to user trap handler
# Nothing in instruction encoding defines this, requiring a context register;
# or a fake 8-byte instruction, requiring logic for 64-bits of tokens

:return retea is op=0x2 & op3=0x39 & retea { build retea; restore(); delayslot(1); didrestore=1; return [retea]; }

:jmpl retea,RD is op=0x2 & RD & op3=0x38 & retea { build retea; RD = inst_start; delayslot(1); goto [retea]; }

# special case where link register is loaded with return address; functions as indirect call
:jmpl retea,RD is op=0x2 & RD & prd=15 & op3=0x38 & retea { build retea; RD = inst_start; delayslot(1); call [retea]; }

# This could be better to split out into three cases to use return instead of goto:
# - rs1=31 & simm13=8 to return, assume SAVE from CALL
# - rs1=15 & simm13=8 to return, assume no SAVE from CALL
:jmpl retea is op=0x2 & rd=0 & op3=0x38 & retea { build retea; delayslot(1); goto [retea]; }
:ret is op=0x2 & rd=0 & rs1=31 & op3=0x38 & i=1 & simm13=8 & retea { build retea; delayslot(1); return [retea]; }
:retl is op=0x2 & rd=0 & rs1=15 & op3=0x38 & i=1 & simm13=8 & retea { build retea; delayslot(1); return [retea]; }

casa_ea: [RS1]imm_asi is i=0 & RS1 & imm_asi { local tmp1:1 = imm_asi; local tmp = RS1+segment(tmp1); export tmp; }
casa_ea: [RS1]%ASI is i=1 & RS1 & ASI { local tmp = RS1+segment(ASI); export tmp; }

:casa casa_ea,RS2,RD is op=0x3 & RD & op3=0x3c & casa_ea & RS2
{
local tmp:4=RD:4;
RD=zext(*:4 casa_ea);
if ((RS2 & 0xFFFFFFFF)!=RD) goto <end>;
*:4 casa_ea=tmp;
:casa casa_ea,RS2,RD is op=0x3 & RD & op3=0x3c & casa_ea & RS2
{
local tmp:4=RD:4;
local tmp2:$(SIZE) = RS2;
local tmp_ea:$(SIZE) = casa_ea;
RD=zext(*:4 tmp_ea);
if ((tmp2 & 0xFFFFFFFF)!=RD) goto <end>;
*:4 tmp_ea=tmp;
<end>
}
:casxa casa_ea,RS2,RD is op=0x3 & RD & op3=0x3e & casa_ea & RS2
{
local tmp=RD;
RD=*:$(SIZE) casa_ea;
if (RS2!=RD) goto <end>;
*:$(SIZE) casa_ea=tmp;
:casxa casa_ea,RS2,RD is op=0x3 & RD & op3=0x3e & casa_ea & RS2
{
local tmp=RD;
local tmp2:$(SIZE) = RS2;
local tmp_ea:$(SIZE) = casa_ea;
RD=*:$(SIZE) tmp_ea;
if (tmp2!=RD) goto <end>;
*:$(SIZE) tmp_ea=tmp;
<end>
}

:impdef1 is op=0x2 & op3=0x36 unimpl
:impdef2 is op=0x2 & op3=0x37 unimpl

:ldstub ea,RD is op=0x3 & RD & op3=0xd & ea { RD = zext(*:1 ea); *:1 ea = 0xFF; }
:ldstuba ea_alt,RD is op=0x3 & RD & op3=0x1d & ea_alt { RD = zext(*:1 ea_alt); *:1 ea_alt = 0xFF; }
:ldstub ea,RD is op=0x3 & RD & op3=0xd & ea { local tmp_ea:$(SIZE) = ea; RD = zext(*:1 tmp_ea); *:1 tmp_ea = 0xFF; }
:ldstuba ea_alt,RD is op=0x3 & RD & op3=0x1d & ea_alt { local tmp_ea:$(SIZE) = ea_alt; RD = zext(*:1 tmp_ea); *:1 tmp_ea = 0xFF; }

:swap ea,RD is op=0x3 & RD & op3=0xF & ea { tmp:4=RD:4; RD = zext(*:4 ea); *:4 ea = tmp; }
:swapa ea_alt,RD is op=0x3 & RD & op3=0x1F & ea_alt { tmp:4=RD:4; RD = zext(*:4 ea_alt); *:4 ea_alt = tmp; }
:swap ea,RD is op=0x3 & RD & op3=0xF & ea { local tmp_ea:$(SIZE) = ea; tmp:4=RD:4; RD = zext(*:4 tmp_ea); *:4 tmp_ea = tmp; }
:swapa ea_alt,RD is op=0x3 & RD & op3=0x1F & ea_alt { local tmp_ea:$(SIZE) = ea_alt; tmp:4=RD:4; RD = zext(*:4 tmp_ea); *:4 tmp_ea = tmp; }

:taddcc RS1,regorimm,RD is op=2 & RD & op3=0x20 & RS1 & regorimm
:taddcc RS1,regorimm,RD is op=2 & RD & op3=0x20 & RS1 & regorimm
{
taddflags(RS1,regorimm);
RD = RS1 + regorimm;
zeroflags(RD);
local res:$(SIZE) = RS1 + regorimm;
zeroflags(res);
RD = res;
}
:taddcctv RS1,regorimm,RD is op=2 & RD & op3=0x22 & RS1 & regorimm
:taddcctv RS1,regorimm,RD is op=2 & RD & op3=0x22 & RS1 & regorimm
{
taddflags(RS1,regorimm);
RD = RS1 + regorimm;
zeroflags(RD);
local res:$(SIZE) = RS1 + regorimm;
zeroflags(res);
RD = res;
}
:tsubcc RS1,regorimm,RD is op=2 & RD & op3=0x21 & RS1 & regorimm
:tsubcc RS1,regorimm,RD is op=2 & RD & op3=0x21 & RS1 & regorimm
{
tsubflags(RS1,regorimm);
RD = RS1 - regorimm;
zeroflags(RD);
local res:$(SIZE) = RS1 - regorimm;
zeroflags(res);
RD = res;
}
:tsubcctv RS1,regorimm,RD is op=2 & RD & op3=0x23 & RS1 & regorimm
:tsubcctv RS1,regorimm,RD is op=2 & RD & op3=0x23 & RS1 & regorimm
{
tsubflags(RS1,regorimm);
RD = RS1 - regorimm;
zeroflags(RD);
local res:$(SIZE) = RS1 - regorimm;
zeroflags(res);
RD = res;
}

tcc: icc is cc1_4=0 & cc0_4=0 & icc { export icc; }
Expand Down