DEADSOFTWARE

first commit
[awtools.git] / dis.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <stdint.h>
4 #include <string.h>
5 #include <stdbool.h>
7 #include "dis.h"
8 #include "dis_syn.h"
10 /*
11 * Another World script disassembler
12 * Only DOS version are supported
13 */
15 #define MSG_USAGE "usage: disasm [-a | -i | -u] [-p] OBJECT OUTFILE\n"
16 #define MSG_OPENERR "can't open file %s.\n"
17 #define MSG_WRITEERR "can't create file %s.\n"
18 #define MSG_INVALIDOP "invalid opcode 0x%X\n"
19 #define MSG_INVALIDJMP "invalid jump opcode %u\n"
21 char *input, *output;
23 FILE *fp;
25 uint8_t *code;
26 uint16_t codesize;
27 uint16_t pc, adr;
29 struct labelinfo label[MAX_LABEL];
30 int labelnum;
31 bool printcode;
32 bool printadr;
34 void (*printlabel)(int);
35 void (*printopcode)(uint16_t, uint16_t, uint16_t, uint16_t, uint16_t, int);
37 static uint8_t ubyte() {
38 return code[pc++];
39 }
41 static uint16_t uword() {
42 return (ubyte() << 8) | ubyte();
43 }
45 static int addlabel(uint16_t adr, int type) {
46 for(int i = 0; i < labelnum; i++) {
47 if(label[i].adr == adr)
48 return i;
49 }
51 label[labelnum].adr = adr;
52 label[labelnum].type = type;
53 ++labelnum;
54 return labelnum - 1;
55 }
57 static void fndlabel() {
58 for(int i = 0; i < labelnum; i++) {
59 if(label[i].adr == pc) {
60 printlabel(i);
61 return;
62 }
63 }
65 printlabel(-1);
66 }
68 static void step() {
69 adr = pc;
71 if(printcode)
72 fndlabel();
74 uint8_t op = ubyte();
75 uint16_t x = -1, y = -1, z = -1, w = -1;
76 int label = -666;
78 if(op & 0x80) { /* spr */
79 w = (((op << 8) | ubyte()) << 1) & 0x7FFF;
80 x = ubyte();
81 y = ubyte();
82 } else if(op & 0x40) { /* spr */
83 w = (uword() << 1) & 0x7FFF;
85 x = ubyte();
86 if((op & 48) == 0)
87 x = (x << 8) | ubyte();
88 else if((op & 48) == 48)
89 x = x + 256;
91 y = ubyte();
92 if((op & 12) == 0)
93 y = (y << 8) | ubyte();
95 if((op & 3) == 1 || (op & 3) == 2)
96 z = ubyte();
97 else
98 z = 64;
99 } else {
100 switch(op) {
101 case 0x0: /* seti */
102 x = ubyte();
103 y = uword();
104 break;
105 case 0x1: /* set */
106 x = ubyte();
107 y = ubyte();
108 break;
109 case 0x2: /* add */
110 x = ubyte();
111 y = ubyte();
112 break;
113 case 0x3: /* addi */
114 x = ubyte();
115 y = uword();
116 break;
117 case 0x4: /* jsr */
118 x = uword();
119 label = addlabel(x, LT_CALL);
120 break;
121 case 0x5: /* return */
122 break;
123 case 0x6: /* break */
124 break;
125 case 0x7: /* jmp */
126 x = uword();
127 label = addlabel(x, LT_JUMP);
128 break;
129 case 0x8: /* setvec */
130 x = ubyte();
131 y = uword();
132 label = addlabel(y, LT_VEC);
133 break;
134 case 0x9: /* dbra */
135 x = ubyte();
136 y = uword();
137 label = addlabel(y, LT_JUMP);
138 break;
139 case 0xA: /* si */
140 w = ubyte();
141 x = ubyte();
143 if(w & 0x80)
144 y = ubyte();
145 else if(w & 0x40)
146 y = uword();
147 else
148 y = ubyte();
150 if((w & 7) > 5) {
151 printf(MSG_INVALIDJMP, w & 0x7);
152 exit(1);
155 z = uword();
156 label = addlabel(z, LT_JUMP);
157 break;
158 case 0xB: /* fade */
159 x = uword() >> 8;
160 break;
161 case 0xC: /* vec */
162 x = ubyte();
163 y = ubyte();
164 z = ubyte();
165 break;
166 case 0xD: /* setws */
167 x = ubyte();
168 break;
169 case 0xE: /* clr */
170 x = ubyte();
171 y = ubyte();
172 break;
173 case 0xF: /* copy */
174 x = ubyte();
175 y = ubyte();
176 break;
177 case 0x10: /* show */
178 x = ubyte();
179 break;
180 case 0x11: /* bigend */
181 break;
182 case 0x12: /* text */
183 z = uword();
184 x = ubyte();
185 y = ubyte();
186 w = ubyte();
187 break;
188 case 0x13: /* sub */
189 x = ubyte();
190 y = ubyte();
191 break;
192 case 0x14: /* andi */
193 x = ubyte();
194 y = uword();
195 break;
196 case 0x15: /* ori */
197 x = ubyte();
198 y = uword();
199 break;
200 case 0x16: /* lsl */
201 x = ubyte();
202 y = uword();
203 break;
204 case 0x17: /* lsr */
205 x = ubyte();
206 y = uword();
207 break;
208 case 0x18: /* play */
209 z = uword();
210 x = ubyte();
211 y = ubyte();
212 w = ubyte();
213 break;
214 case 0x19: /* load */
215 x = uword();
216 break;
217 case 0x1A: /* song */
218 x = uword();
219 y = uword();
220 z = ubyte();
221 break;
222 default:
223 printf(MSG_INVALIDOP, op);
224 exit(1);
228 if(printcode)
229 printopcode(op, x, y, z, w, label);
232 static void readarg(int argc, char **argv) {
233 if(argc < 3)
234 goto error;
236 printadr = false;
237 printlabel = aw_printlabel;
238 printopcode = aw_printopcode;
240 int i = 1;
241 while((i < argc) && (argv[i][0] == '-')) {
242 if(strcmp("-a", argv[i]) == 0) {
243 printlabel = aw_printlabel;
244 printopcode = aw_printopcode;
245 } else if(strcmp("-i", argv[i]) == 0) {
246 printlabel = intel_printlabel;
247 printopcode = intel_printopcode;
248 } else if(strcmp("-u", argv[i]) == 0) {
249 printlabel = att_printlabel;
250 printopcode = att_printopcode;
251 } else if(strcmp("-p", argv[i]) == 0) {
252 printadr = true;
253 } else {
254 goto error;
257 ++i;
260 if((argc - i) != 2)
261 goto error;
263 input = argv[i];
264 output = argv[i + 1];
265 return;
267 error:
268 printf(MSG_USAGE);
269 exit(1);
272 int main(int argc, char **argv) {
273 readarg(argc, argv);
275 if((fp = fopen(input, "r")) == NULL) {
276 printf(MSG_OPENERR, input);
277 exit(1);
280 fseek(fp, 0, SEEK_END);
281 codesize = ftell(fp);
282 fseek(fp, 0, SEEK_SET);
284 code = malloc(codesize);
285 fread(code, codesize, 1, fp);
286 fclose(fp);
288 if((fp = fopen(output, "w")) == NULL) {
289 printf(MSG_WRITEERR, output);
290 exit(1);
293 labelnum = 0;
295 pc = 0;
296 printcode = false;
297 while(pc < codesize)
298 step(); /* read labels */
300 pc = 0;
301 printcode = true;
302 while(pc < codesize)
303 step(); /* print code */
305 fclose(fp);
306 free(code);
308 return 0;