Passo intermediario, ainda falta um longo caminho
[pspdecompiler.git] / decoder.c
blob7493c2d636f8654e83be8532e8a9956e768a08d3
2 #include <string.h>
4 #include "code.h"
5 #include "utils.h"
7 int decode_instructions (struct code *c)
9 struct location *base;
10 uint32 i, numopc, size, address;
11 const uint8 *code;
12 int slot = FALSE;
14 address = c->file->programs->vaddr;
15 size = c->file->modinfo->expvaddr - 4;
16 code = c->file->programs->data;
18 numopc = size >> 2;
20 if ((size & 0x03) || (address & 0x03)) {
21 error (__FILE__ ": size/address is not multiple of 4");
22 return 0;
25 base = (struct location *) xmalloc ((numopc) * sizeof (struct location));
26 memset (base, 0, (numopc) * sizeof (struct location));
28 c->base = base;
29 c->end = &base[numopc - 1];
30 c->baddr = address;
31 c->numopc = numopc;
33 for (i = 0; i < numopc; i++) {
34 struct location *loc = &base[i];
35 uint32 tgt;
38 loc->opc = code[i << 2];
39 loc->opc |= code[(i << 2) + 1] << 8;
40 loc->opc |= code[(i << 2) + 2] << 16;
41 loc->opc |= code[(i << 2) + 3] << 24;
42 loc->insn = allegrex_decode (loc->opc, FALSE);
43 loc->address = address + (i << 2);
45 if (loc->insn == NULL) {
46 loc->error = ERROR_INVALID_OPCODE;
47 slot = FALSE;
48 continue;
52 if (INSN_TYPE (loc->insn->flags) != INSN_ALLEGREX) {
53 slot = FALSE;
54 continue;
58 if (loc->insn->flags & (INSN_BRANCH | INSN_JUMP)) {
59 if (slot) c->base[i - 1].error = ERROR_DELAY_SLOT;
60 slot = TRUE;
61 } else {
62 slot = FALSE;
65 if (loc->insn->flags & INSN_BRANCH) {
66 tgt = loc->opc & 0xFFFF;
67 if (tgt & 0x8000) { tgt |= ~0xFFFF; }
68 tgt += i + 1;
69 if (tgt < numopc) {
70 loc->target = &base[tgt];
71 } else {
72 loc->error = ERROR_TARGET_OUTSIDE_FILE;
75 if (location_gpr_used (loc) == 0 ||
76 ((loc->insn->flags & INSN_READ_GPR_T) && RS (loc->opc) == RT (loc->opc))) {
77 switch (loc->insn->insn) {
78 case I_BEQ:
79 case I_BEQL:
80 case I_BGEZ:
81 case I_BGEZAL:
82 case I_BGEZL:
83 case I_BLEZ:
84 case I_BLEZL:
85 loc->branchalways = TRUE;
86 break;
87 case I_BGTZ:
88 case I_BGTZL:
89 case I_BLTZ:
90 case I_BLTZAL:
91 case I_BLTZALL:
92 case I_BLTZL:
93 case I_BNE:
94 case I_BNEL:
95 loc->error = ERROR_ILLEGAL_BRANCH;
96 break;
97 default:
98 loc->branchalways = FALSE;
102 } else if (loc->insn->insn == I_J || loc->insn->insn == I_JAL) {
103 uint32 target_addr = (loc->opc & 0x3FFFFFF) << 2;;
104 target_addr |= ((loc->address) & 0xF0000000);
105 tgt = (target_addr - address) >> 2;
106 if (tgt < numopc) {
107 loc->target = &base[tgt];
108 } else {
109 loc->error = ERROR_TARGET_OUTSIDE_FILE;
114 if (slot) {
115 c->base[i - 1].error = ERROR_TARGET_OUTSIDE_FILE;
118 return 1;
121 uint32 location_gpr_used (struct location *loc)
123 uint32 result = 0;
125 if (loc->insn->flags & INSN_READ_GPR_S) {
126 if (RS (loc->opc) != 0)
127 result |= 1 << (RS (loc->opc));
130 if (loc->insn->flags & INSN_READ_GPR_T) {
131 if (RT (loc->opc) != 0)
132 result |= 1 << (RT (loc->opc));
135 if (loc->insn->flags & INSN_READ_GPR_D) {
136 if (RD (loc->opc) != 0)
137 result |= 1 << (RD (loc->opc));
140 return result;
143 uint32 location_gpr_defined (struct location *loc)
145 uint32 result = 0;
147 if (loc->insn->flags & INSN_LINK) {
148 result |= 1 << 31;
151 if (loc->insn->flags & INSN_WRITE_GPR_D) {
152 if (RD (loc->opc) != 0)
153 result |= 1 << (RD (loc->opc));
156 if (loc->insn->flags & INSN_WRITE_GPR_T) {
157 if (RT (loc->opc) != 0)
158 result |= 1 << (RT (loc->opc));
160 return result;
163 int location_branch_may_swap (struct location *branch)
165 int gpr_used, gpr_defined;
167 gpr_used = location_gpr_used (branch);
168 gpr_defined = location_gpr_defined (&branch[1]);
169 return (!(gpr_used & gpr_defined));