298 lines
8.2 KiB
C
298 lines
8.2 KiB
C
/* $Id$ */
|
|
/* Copyright (c) 2011-2012 Pierre Pronchery <khorben@defora.org> */
|
|
/* This file is part of DeforaOS Devel as */
|
|
/* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, version 3 of the License.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
|
|
|
|
|
|
|
#include <stddef.h>
|
|
|
|
|
|
/* sparc */
|
|
/* private */
|
|
/* prototypes */
|
|
/* plug-in */
|
|
static int _sparc_decode(AsmArchPlugin * plugin, AsmArchInstructionCall * call);
|
|
static int _sparc_encode(AsmArchPlugin * plugin,
|
|
AsmArchInstruction * instruction,
|
|
AsmArchInstructionCall * call);
|
|
|
|
|
|
/* functions */
|
|
/* plug-in */
|
|
/* sparc_decode */
|
|
static int _sparc_decode(AsmArchPlugin * plugin, AsmArchInstructionCall * call)
|
|
{
|
|
AsmArchPluginHelper * helper = plugin->helper;
|
|
uint32_t u32;
|
|
uint32_t opcode;
|
|
AsmArchInstruction * ai;
|
|
size_t i;
|
|
|
|
if(helper->read(helper->arch, &u32, sizeof(u32)) != sizeof(u32))
|
|
return -1;
|
|
u32 = _htob32(u32);
|
|
if((u32 & 0xc0000000) == 0xc0000000) /* load store */
|
|
opcode = u32 & (0xc0000000 | (0xf << 19) | (0x1 << 13));
|
|
else if((u32 & 0xc1c00000) == 0x01000000) /* nop, sethi */
|
|
opcode = u32 & (0x7 << 22);
|
|
else if((u32 & 0xc0000000) == 0x80000000) /* integer arithmetic */
|
|
opcode = u32 & (0x80000000 | (0x1f << 19) | (0x1 << 13));
|
|
else if((u32 & 0xc1c00000) == 0x00800000) /* branch */
|
|
#if 0 /* FIXME figure what's wrong */
|
|
opcode = u32 & (0x00800000 | (0xf << 25) | (0x3 << 2));
|
|
#else
|
|
opcode = u32 & (0x00800000 | (0xf << 25));
|
|
#endif
|
|
else
|
|
{
|
|
call->name = "dw";
|
|
return 0;
|
|
}
|
|
if((ai = helper->get_instruction_by_opcode(helper->arch, 32, opcode))
|
|
== NULL)
|
|
return -1;
|
|
call->name = ai->name;
|
|
call->operands[0].definition = ai->op1;
|
|
call->operands[1].definition = ai->op2;
|
|
call->operands[2].definition = ai->op3;
|
|
for(i = 0; i < 3 && call->operands[i].definition != AOT_NONE; i++);
|
|
call->operands_cnt = i;
|
|
return 0;
|
|
}
|
|
|
|
|
|
/* sparc_encode */
|
|
static int _encode_branch(AsmArchInstruction * instruction,
|
|
AsmArchInstructionCall * call, uint32_t * opcode);
|
|
static int _encode_integer(AsmArchPlugin * plugin, AsmArchInstruction * instruction,
|
|
AsmArchInstructionCall * call, uint32_t * opcode);
|
|
static int _encode_loadstore(AsmArchPlugin * plugin, AsmArchInstruction * instruction,
|
|
AsmArchInstructionCall * call, uint32_t * opcode);
|
|
static int _encode_sethi(AsmArchPlugin * plugin, AsmArchInstruction * instruction,
|
|
AsmArchInstructionCall * call, uint32_t * opcode);
|
|
|
|
static int _sparc_encode(AsmArchPlugin * plugin,
|
|
AsmArchInstruction * instruction,
|
|
AsmArchInstructionCall * call)
|
|
{
|
|
AsmArchPluginHelper * helper = plugin->helper;
|
|
uint32_t opcode = instruction->opcode;
|
|
|
|
if((opcode & 0xc0000000) == 0xc0000000)
|
|
{
|
|
if(_encode_loadstore(plugin, instruction, call, &opcode) != 0)
|
|
return -1;
|
|
}
|
|
else if((opcode & 0xc1c00000) == 0x01000000)
|
|
{
|
|
if(_encode_sethi(plugin, instruction, call, &opcode) != 0)
|
|
return -1;
|
|
}
|
|
else if((opcode & 0xc0000000) == 0x80000000)
|
|
{
|
|
if(_encode_integer(plugin, instruction, call, &opcode) != 0)
|
|
return -1;
|
|
}
|
|
else if((opcode & 0xc1c00000) == 0x00800000)
|
|
{
|
|
if(_encode_branch(instruction, call, &opcode) != 0)
|
|
return -1;
|
|
}
|
|
else
|
|
return -1;
|
|
opcode = _htob32(opcode);
|
|
if(helper->write(helper->arch, &opcode, sizeof(opcode))
|
|
!= sizeof(opcode))
|
|
return -1;
|
|
return 0;
|
|
}
|
|
|
|
static int _encode_branch(AsmArchInstruction * instruction,
|
|
AsmArchInstructionCall * call, uint32_t * opcode)
|
|
{
|
|
uint32_t disp;
|
|
|
|
if(AO_GET_TYPE(instruction->op1) != AOT_IMMEDIATE)
|
|
return -1;
|
|
disp = call->operands[0].value.immediate.value;
|
|
if(call->operands[0].value.immediate.negative)
|
|
disp = -disp;
|
|
disp &= (0x003fffff);
|
|
*opcode |= disp;
|
|
return 0;
|
|
}
|
|
|
|
static int _encode_integer(AsmArchPlugin * plugin, AsmArchInstruction * instruction,
|
|
AsmArchInstructionCall * call, uint32_t * opcode)
|
|
{
|
|
AsmArchPluginHelper * helper = plugin->helper;
|
|
uint32_t rd;
|
|
uint32_t rs1;
|
|
uint32_t rs2;
|
|
char const * name;
|
|
AsmArchRegister * ar;
|
|
|
|
/* rs1 */
|
|
if(AO_GET_TYPE(instruction->op1) != AOT_REGISTER)
|
|
return -1;
|
|
name = call->operands[0].value._register.name;
|
|
if((ar = helper->get_register_by_name_size(helper->arch,
|
|
name, 32)) == NULL)
|
|
return -1;
|
|
rs1 = (ar->id << 14);
|
|
/* rs2 */
|
|
if(AO_GET_TYPE(instruction->op2) == AOT_REGISTER)
|
|
{
|
|
name = call->operands[1].value._register.name;
|
|
if((ar = helper->get_register_by_name_size(helper->arch,
|
|
name, 32)) == NULL)
|
|
return -1;
|
|
rs2 = ar->id;
|
|
}
|
|
else if(AO_GET_TYPE(instruction->op2) == AOT_IMMEDIATE)
|
|
{
|
|
rs2 = call->operands[1].value.immediate.value;
|
|
if(call->operands[1].value.immediate.negative)
|
|
rs2 = -rs2;
|
|
rs2 &= 0x00001fff;
|
|
rs2 |= (1 << 13);
|
|
}
|
|
else
|
|
return -1;
|
|
/* rd */
|
|
if(AO_GET_TYPE(instruction->op3) != AOT_REGISTER)
|
|
return -1;
|
|
name = call->operands[2].value._register.name;
|
|
if((ar = helper->get_register_by_name_size(helper->arch,
|
|
name, 32)) == NULL)
|
|
return -1;
|
|
rd = (ar->id << 25);
|
|
*opcode |= (rd | rs1 | rs2);
|
|
return 0;
|
|
}
|
|
|
|
static int _encode_loadstore(AsmArchPlugin * plugin, AsmArchInstruction * instruction,
|
|
AsmArchInstructionCall * call, uint32_t * opcode)
|
|
{
|
|
AsmArchPluginHelper * helper = plugin->helper;
|
|
uint32_t rd;
|
|
uint32_t rs1;
|
|
uint32_t rs2;
|
|
char const * name;
|
|
AsmArchRegister * ar;
|
|
|
|
if(instruction->opcode & (1 << 21)) /* store instruction */
|
|
{
|
|
/* rd */
|
|
if(AO_GET_TYPE(instruction->op1) != AOT_REGISTER)
|
|
return -1;
|
|
name = call->operands[0].value._register.name;
|
|
if((ar = helper->get_register_by_name_size(helper->arch,
|
|
name, 32)) == NULL)
|
|
return -1;
|
|
rd = (ar->id << 25);
|
|
/* [rs1 + rs2] */
|
|
if(AO_GET_TYPE(instruction->op2) == AOT_DREGISTER2)
|
|
{
|
|
name = call->operands[1].value.dregister2.name;
|
|
if((ar = helper->get_register_by_name_size(helper->arch,
|
|
name, 32)) == NULL)
|
|
return -1;
|
|
rs1 = (ar->id << 14);
|
|
name = call->operands[1].value.dregister2.name2;
|
|
if((ar = helper->get_register_by_name_size(helper->arch,
|
|
name, 32)) == NULL)
|
|
return -1;
|
|
rs2 = ar->id;
|
|
}
|
|
else if(AO_GET_TYPE(instruction->op2) == AOT_DREGISTER)
|
|
{
|
|
name = call->operands[1].value.dregister.name;
|
|
if((ar = helper->get_register_by_name_size(helper->arch,
|
|
name, 32)) == NULL)
|
|
return -1;
|
|
rs1 = (ar->id << 14);
|
|
rs2 = 0; /* FIXME implement */
|
|
}
|
|
else
|
|
return -1;
|
|
}
|
|
else
|
|
{
|
|
/* [rs1 + rs2] */
|
|
if(AO_GET_TYPE(instruction->op1) == AOT_DREGISTER2)
|
|
{
|
|
name = call->operands[0].value.dregister2.name;
|
|
if((ar = helper->get_register_by_name_size(helper->arch,
|
|
name, 32)) == NULL)
|
|
return -1;
|
|
rs1 = (ar->id << 14);
|
|
name = call->operands[0].value.dregister2.name2;
|
|
if((ar = helper->get_register_by_name_size(helper->arch,
|
|
name, 32)) == NULL)
|
|
return -1;
|
|
rs2 = ar->id;
|
|
}
|
|
else if(AO_GET_TYPE(instruction->op1) == AOT_DREGISTER)
|
|
{
|
|
name = call->operands[0].value.dregister.name;
|
|
if((ar = helper->get_register_by_name_size(helper->arch,
|
|
name, 32)) == NULL)
|
|
return -1;
|
|
rs1 = (ar->id << 14);
|
|
rs2 = 0; /* FIXME implement */
|
|
}
|
|
else
|
|
return -1;
|
|
/* rd */
|
|
if(AO_GET_TYPE(instruction->op2) != AOT_REGISTER)
|
|
return -1;
|
|
name = call->operands[1].value._register.name;
|
|
if((ar = helper->get_register_by_name_size(helper->arch,
|
|
name, 32)) == NULL)
|
|
return -1;
|
|
rd = (ar->id << 25);
|
|
}
|
|
*opcode |= (rd | rs1 | rs2);
|
|
return 0;
|
|
}
|
|
|
|
static int _encode_sethi(AsmArchPlugin * plugin, AsmArchInstruction * instruction,
|
|
AsmArchInstructionCall * call, uint32_t * opcode)
|
|
{
|
|
AsmArchPluginHelper * helper = plugin->helper;
|
|
uint32_t rd;
|
|
uint32_t value;
|
|
char const * name;
|
|
AsmArchRegister * ar;
|
|
|
|
/* nop */
|
|
if(AO_GET_TYPE(instruction->op1) == AOT_NONE)
|
|
return 0;
|
|
/* value */
|
|
if(AO_GET_TYPE(instruction->op1) != AOT_IMMEDIATE)
|
|
return -1;
|
|
value = (call->operands[0].value.immediate.value >> 10);
|
|
/* rd */
|
|
if(AO_GET_TYPE(instruction->op2) != AOT_REGISTER)
|
|
return -1;
|
|
name = call->operands[1].value._register.name;
|
|
if((ar = helper->get_register_by_name_size(helper->arch,
|
|
name, 32)) == NULL)
|
|
return -1;
|
|
rd = (ar->id << 25);
|
|
*opcode |= (rd | value);
|
|
return 0;
|
|
}
|