Asm/src/arch/sparc.h

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;
}