Now my comments should be in english....
[pspdecompiler.git] / decoder.c
blob2e2e3e6ab691d073160b02544829c140aba9d34e
1 /**
2 * Author: Humberto Naves (hsnaves@gmail.com)
3 */
5 #include <string.h>
7 #include "code.h"
8 #include "utils.h"
10 int decode_instructions (struct code *c)
12 struct location *base;
13 uint32 i, numopc, size, address;
14 const uint8 *code;
15 int slot = FALSE;
17 address = c->file->programs->vaddr;
18 size = c->file->modinfo->expvaddr - 4;
19 code = c->file->programs->data;
21 numopc = size >> 2;
23 if ((size & 0x03) || (address & 0x03)) {
24 error (__FILE__ ": size/address is not multiple of 4");
25 return 0;
28 base = (struct location *) xmalloc ((numopc) * sizeof (struct location));
29 memset (base, 0, (numopc) * sizeof (struct location));
31 c->base = base;
32 c->end = &base[numopc - 1];
33 c->baddr = address;
34 c->numopc = numopc;
36 for (i = 0; i < numopc; i++) {
37 struct location *loc = &base[i];
38 uint32 tgt;
41 loc->opc = code[i << 2];
42 loc->opc |= code[(i << 2) + 1] << 8;
43 loc->opc |= code[(i << 2) + 2] << 16;
44 loc->opc |= code[(i << 2) + 3] << 24;
45 loc->insn = allegrex_decode (loc->opc, FALSE);
46 loc->address = address + (i << 2);
48 if (loc->insn == NULL) {
49 loc->error = ERROR_INVALID_OPCODE;
50 slot = FALSE;
51 continue;
55 if (INSN_TYPE (loc->insn->flags) != INSN_ALLEGREX) {
56 slot = FALSE;
57 continue;
61 if (loc->insn->flags & (INSN_BRANCH | INSN_JUMP)) {
62 if (slot) c->base[i - 1].error = ERROR_DELAY_SLOT;
63 slot = TRUE;
64 } else {
65 slot = FALSE;
68 if (loc->insn->flags & INSN_BRANCH) {
69 tgt = loc->opc & 0xFFFF;
70 if (tgt & 0x8000) { tgt |= ~0xFFFF; }
71 tgt += i + 1;
72 if (tgt < numopc) {
73 loc->target = &base[tgt];
74 } else {
75 loc->error = ERROR_TARGET_OUTSIDE_FILE;
78 if (location_gpr_used (loc) == 0 ||
79 ((loc->insn->flags & INSN_READ_GPR_T) && RS (loc->opc) == RT (loc->opc))) {
80 switch (loc->insn->insn) {
81 case I_BEQ:
82 case I_BEQL:
83 case I_BGEZ:
84 case I_BGEZAL:
85 case I_BGEZL:
86 case I_BLEZ:
87 case I_BLEZL:
88 loc->branchalways = TRUE;
89 break;
90 case I_BGTZ:
91 case I_BGTZL:
92 case I_BLTZ:
93 case I_BLTZAL:
94 case I_BLTZALL:
95 case I_BLTZL:
96 case I_BNE:
97 case I_BNEL:
98 loc->error = ERROR_ILLEGAL_BRANCH;
99 break;
100 default:
101 loc->branchalways = FALSE;
105 } else if (loc->insn->insn == I_J || loc->insn->insn == I_JAL) {
106 uint32 target_addr = (loc->opc & 0x3FFFFFF) << 2;;
107 target_addr |= ((loc->address) & 0xF0000000);
108 tgt = (target_addr - address) >> 2;
109 if (tgt < numopc) {
110 loc->target = &base[tgt];
111 } else {
112 loc->error = ERROR_TARGET_OUTSIDE_FILE;
117 if (slot) {
118 c->base[i - 1].error = ERROR_TARGET_OUTSIDE_FILE;
121 return 1;
124 uint32 location_gpr_used (struct location *loc)
126 uint32 result = 0;
128 if (loc->insn->flags & INSN_READ_GPR_S) {
129 if (RS (loc->opc) != 0)
130 result |= 1 << (RS (loc->opc));
133 if (loc->insn->flags & INSN_READ_GPR_T) {
134 if (RT (loc->opc) != 0)
135 result |= 1 << (RT (loc->opc));
138 if (loc->insn->flags & INSN_READ_GPR_D) {
139 if (RD (loc->opc) != 0)
140 result |= 1 << (RD (loc->opc));
143 return result;
146 uint32 location_gpr_defined (struct location *loc)
148 uint32 result = 0;
150 if (loc->insn->flags & INSN_LINK) {
151 result |= 1 << 31;
154 if (loc->insn->flags & INSN_WRITE_GPR_D) {
155 if (RD (loc->opc) != 0)
156 result |= 1 << (RD (loc->opc));
159 if (loc->insn->flags & INSN_WRITE_GPR_T) {
160 if (RT (loc->opc) != 0)
161 result |= 1 << (RT (loc->opc));
163 return result;
166 int location_branch_may_swap (struct location *branch)
168 int gpr_used, gpr_defined;
170 gpr_used = location_gpr_used (branch);
171 gpr_defined = location_gpr_defined (&branch[1]);
172 return (!(gpr_used & gpr_defined));