Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
1126 | savelij | 1 | /* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ |
2 | #include "stdinc.h" |
||
3 | #include "nlmessages.h" |
||
4 | #include "stringlists.h" |
||
5 | #include "codechunks.h" |
||
6 | #include "entryaddress.h" |
||
7 | #include "invaddress.h" |
||
8 | #include "strutil.h" |
||
9 | #include "cmdarg.h" |
||
10 | #include "msg_level.h" |
||
11 | #include "dasmdef.h" |
||
12 | #include "cpulist.h" |
||
13 | #include "console.h" |
||
14 | #include "nls.h" |
||
15 | #include "version.h" |
||
16 | #include "das.rsc" |
||
17 | |||
18 | #include "deco68.h" |
||
19 | #include "deco87c800.h" |
||
20 | #include "deco4004.h" |
||
21 | |||
22 | #define TABSIZE 8 |
||
23 | |||
24 | char *pEnvName = "DASCMD"; |
||
25 | |||
26 | void WrCopyRight(const char *Msg) |
||
27 | { |
||
28 | printf("%s\n%s\n", Msg, InfoMessCopyright); |
||
29 | } |
||
30 | |||
31 | typedef void (*tChunkCallback)(const OneChunk *pChunk, Boolean IsData, void *pUser); |
||
32 | |||
33 | static void IterateChunks(tChunkCallback Callback, void *pUser) |
||
34 | { |
||
35 | Word NextCodeChunk, NextDataChunk; |
||
36 | const OneChunk *pChunk; |
||
37 | Boolean IsData; |
||
38 | |||
39 | NextCodeChunk = NextDataChunk = 0; |
||
40 | while ((NextCodeChunk < UsedCodeChunks.RealLen) || (NextDataChunk < UsedDataChunks.RealLen)) |
||
41 | { |
||
42 | if (NextCodeChunk >= UsedCodeChunks.RealLen) |
||
43 | { |
||
44 | pChunk = UsedDataChunks.Chunks + (NextDataChunk++); |
||
45 | IsData = True; |
||
46 | } |
||
47 | else if (NextDataChunk >= UsedDataChunks.RealLen) |
||
48 | { |
||
49 | pChunk = UsedCodeChunks.Chunks + (NextCodeChunk++); |
||
50 | IsData = False; |
||
51 | } |
||
52 | else if (UsedDataChunks.Chunks[NextDataChunk].Start < UsedCodeChunks.Chunks[NextCodeChunk].Start) |
||
53 | { |
||
54 | pChunk = UsedDataChunks.Chunks + (NextDataChunk++); |
||
55 | IsData = True; |
||
56 | } |
||
57 | else |
||
58 | { |
||
59 | pChunk = UsedCodeChunks.Chunks + (NextCodeChunk++); |
||
60 | IsData = False; |
||
61 | } |
||
62 | |||
63 | Callback(pChunk, IsData, pUser); |
||
64 | } |
||
65 | } |
||
66 | |||
67 | typedef struct |
||
68 | { |
||
69 | FILE *pDestFile; |
||
70 | LargeWord Sum; |
||
71 | } tDumpIteratorData; |
||
72 | |||
73 | static void DumpIterator(const OneChunk *pChunk, Boolean IsData, void *pUser) |
||
74 | { |
||
75 | String Str; |
||
76 | tDumpIteratorData *pData = (tDumpIteratorData*)pUser; |
||
77 | |||
78 | HexString(Str, sizeof(Str), pChunk->Start, 0); |
||
79 | fprintf(pData->pDestFile, "\t\t; %s...", Str); |
||
80 | HexString(Str, sizeof(Str), pChunk->Start + pChunk->Length - 1, 0); |
||
81 | fprintf(pData->pDestFile, "%s (%s)\n", Str, IsData ? "data" :"code"); |
||
82 | pData->Sum += pChunk->Length; |
||
83 | } |
||
84 | |||
85 | static void DumpChunks(const ChunkList *NChunk, FILE *pDestFile) |
||
86 | { |
||
87 | tDumpIteratorData Data; |
||
88 | String Str; |
||
89 | |||
90 | UNUSED(NChunk); |
||
91 | |||
92 | Data.pDestFile = pDestFile; |
||
93 | Data.Sum = 0; |
||
94 | fprintf(pDestFile, "\t\t; disassembled area:\n"); |
||
95 | IterateChunks(DumpIterator, &Data); |
||
96 | as_snprintf(Str, sizeof(Str), "\t\t; %lllu/%lllu bytes disassembled", Data.Sum, GetCodeChunksStored(&CodeChunks)); |
||
97 | fprintf(pDestFile, "%s\n", Str); |
||
98 | } |
||
99 | |||
100 | static int tabbedstrlen(const char *s) |
||
101 | { |
||
102 | int Result = 0; |
||
103 | |||
104 | for (; *s; s++) |
||
105 | { |
||
106 | if (*s == '\t') |
||
107 | Result += TABSIZE - (Result % TABSIZE); |
||
108 | else |
||
109 | Result++; |
||
110 | } |
||
111 | return Result; |
||
112 | } |
||
113 | |||
114 | static void PrTabs(FILE *pDestFile, int TargetLen, int ThisLen) |
||
115 | { |
||
116 | while (ThisLen < TargetLen) |
||
117 | { |
||
118 | fputc('\t', pDestFile); |
||
119 | ThisLen += TABSIZE - (ThisLen % TABSIZE); |
||
120 | } |
||
121 | } |
||
122 | |||
123 | static as_cmd_result_t ArgError(int MsgNum, const char *pArg) |
||
124 | { |
||
125 | if (pArg) |
||
126 | fprintf(stderr, "%s:", pArg); |
||
127 | fprintf(stderr, "%s\n", getmessage(MsgNum)); |
||
128 | |||
129 | return e_cmd_err; |
||
130 | } |
||
131 | |||
132 | static as_cmd_result_t CMD_BinFile(Boolean Negate, const char *pArg) |
||
133 | { |
||
134 | LargeWord Start = 0, Len = 0, Gran = 1; |
||
135 | char *pStart = NULL, *pLen = NULL, *pGran = NULL; |
||
136 | String Arg; |
||
137 | Boolean OK; |
||
138 | tCodeChunk Chunk; |
||
139 | |||
140 | if (Negate || !*pArg) |
||
141 | return ArgError(Num_ErrMsgFileArgumentMissing, NULL); |
||
142 | |||
143 | strmaxcpy(Arg, pArg, sizeof(Arg)); |
||
144 | if ((pStart = strchr(Arg, '@'))) |
||
145 | { |
||
146 | *pStart++ = '\0'; |
||
147 | if ((pLen = strchr(pStart, ','))) |
||
148 | { |
||
149 | *pLen++ = '\0'; |
||
150 | if ((pGran = strchr(pLen, ','))) |
||
151 | *pGran++ = '\0'; |
||
152 | } |
||
153 | } |
||
154 | |||
155 | if (pStart && *pStart) |
||
156 | { |
||
157 | Start = ConstLongInt(pStart, &OK, 10); |
||
158 | if (!OK) |
||
159 | return ArgError(Num_ErrMsgInvalidNumericValue, pStart); |
||
160 | } |
||
161 | else |
||
162 | Start = 0; |
||
163 | |||
164 | if (pLen && *pLen) |
||
165 | { |
||
166 | Len = ConstLongInt(pLen, &OK, 10); |
||
167 | if (!OK) |
||
168 | return ArgError(Num_ErrMsgInvalidNumericValue, pLen); |
||
169 | } |
||
170 | else |
||
171 | Len = 0; |
||
172 | |||
173 | if (pGran && *pGran) |
||
174 | { |
||
175 | Gran = ConstLongInt(pGran, &OK, 10); |
||
176 | if (!OK) |
||
177 | return ArgError(Num_ErrMsgInvalidNumericValue, pGran); |
||
178 | } |
||
179 | else |
||
180 | Gran = 1; |
||
181 | |||
182 | InitCodeChunk(&Chunk); |
||
183 | if (ReadCodeChunk(&Chunk, Arg, Start, Len, Gran)) |
||
184 | return ArgError(Num_ErrMsgCannotReadBinaryFile, Arg); |
||
185 | MoveCodeChunkToList(&CodeChunks, &Chunk, TRUE); |
||
186 | |||
187 | return e_cmd_arg; |
||
188 | } |
||
189 | |||
190 | static void ResizeBuffer(Byte* *ppBuffer, LargeWord *pAllocLen, LargeWord ReqLen) |
||
191 | { |
||
192 | if (ReqLen > *pAllocLen) |
||
193 | { |
||
194 | Byte *pNew = *ppBuffer ? realloc(*ppBuffer, ReqLen) : malloc(ReqLen); |
||
195 | if (pNew) |
||
196 | { |
||
197 | *ppBuffer = pNew; |
||
198 | *pAllocLen = ReqLen; |
||
199 | } |
||
200 | } |
||
201 | } |
||
202 | |||
203 | static Boolean GetByte(char* *ppLine, Byte *pResult) |
||
204 | { |
||
205 | if (!as_isxdigit(**ppLine)) |
||
206 | return False; |
||
207 | *pResult = isdigit(**ppLine) ? (**ppLine - '0') : (as_toupper(**ppLine) - 'A' + 10); |
||
208 | (*ppLine)++; |
||
209 | if (!as_isxdigit(**ppLine)) |
||
210 | return False; |
||
211 | *pResult = (*pResult << 4) | (isdigit(**ppLine) ? (**ppLine - '0') : (as_toupper(**ppLine) - 'A' + 10)); |
||
212 | (*ppLine)++; |
||
213 | return True; |
||
214 | } |
||
215 | |||
216 | static void FlushChunk(tCodeChunk *pChunk) |
||
217 | { |
||
218 | pChunk->Granularity = 1; |
||
219 | pChunk->pLongCode = (LongWord*)pChunk->pCode; |
||
220 | pChunk->pWordCode = (Word*)pChunk->pCode; |
||
221 | MoveCodeChunkToList(&CodeChunks, pChunk, TRUE); |
||
222 | InitCodeChunk(pChunk); |
||
223 | } |
||
224 | |||
225 | /* ------------------------------------------------------- */ |
||
226 | |||
227 | static Boolean write_version_exit, write_help_exit, write_cpu_list_exit; |
||
228 | |||
229 | static int screen_height = 0; |
||
230 | |||
231 | static void write_console_next(const char *p_line) |
||
232 | { |
||
233 | static int LineZ; |
||
234 | |||
235 | WrConsoleLine(p_line, True); |
||
236 | if (screen_height && (++LineZ >= screen_height)) |
||
237 | { |
||
238 | LineZ = 0; |
||
239 | WrConsoleLine(getmessage(Num_KeyWaitMsg), False); |
||
240 | fflush(stdout); |
||
241 | while (getchar() != '\n'); |
||
242 | } |
||
243 | } |
||
244 | |||
245 | static as_cmd_result_t CMD_HexFile(Boolean Negate, const char *pArg) |
||
246 | { |
||
247 | FILE *pFile; |
||
248 | char Line[300], *pLine; |
||
249 | size_t Len; |
||
250 | Byte *pLineBuffer = NULL, *pDataBuffer = 0, RecordType, Tmp; |
||
251 | LargeWord LineBufferStart = 0, LineBufferAllocLen = 0, LineBufferLen = 0, |
||
252 | Sum; |
||
253 | tCodeChunk Chunk; |
||
254 | unsigned z; |
||
255 | |||
256 | if (Negate || !*pArg) |
||
257 | return ArgError(Num_ErrMsgFileArgumentMissing, NULL); |
||
258 | |||
259 | pFile = fopen(pArg, "r"); |
||
260 | if (!pFile) |
||
261 | { |
||
262 | return ArgError(Num_ErrMsgCannotReadHexFile, pArg); |
||
263 | } |
||
264 | |||
265 | InitCodeChunk(&Chunk); |
||
266 | while (!feof(pFile)) |
||
267 | { |
||
268 | fgets(Line, sizeof(Line), pFile); |
||
269 | Len = strlen(Line); |
||
270 | if ((Len > 0) && (Line[Len -1] == '\n')) |
||
271 | Line[--Len] = '\0'; |
||
272 | if ((Len > 0) && (Line[Len -1] == '\r')) |
||
273 | Line[--Len] = '\0'; |
||
274 | if (*Line != ':') |
||
275 | continue; |
||
276 | |||
277 | Sum = 0; |
||
278 | pLine = Line + 1; |
||
279 | if (!GetByte(&pLine, &Tmp)) |
||
280 | return ArgError(Num_ErrMsgInvalidHexData, pArg); |
||
281 | ResizeBuffer(&pLineBuffer, &LineBufferAllocLen, Tmp); |
||
282 | LineBufferLen = Tmp; |
||
283 | Sum += Tmp; |
||
284 | |||
285 | LineBufferStart = 0; |
||
286 | for (z = 0; z < 2; z++) |
||
287 | { |
||
288 | if (!GetByte(&pLine, &Tmp)) |
||
289 | return ArgError(Num_ErrMsgInvalidHexData, pArg); |
||
290 | LineBufferStart = (LineBufferStart << 8) | Tmp; |
||
291 | Sum += Tmp; |
||
292 | } |
||
293 | |||
294 | if (!GetByte(&pLine, &RecordType)) |
||
295 | return ArgError(Num_ErrMsgInvalidHexData, pArg); |
||
296 | Sum += RecordType; |
||
297 | if (RecordType != 0) |
||
298 | continue; |
||
299 | |||
300 | for (z = 0; z < LineBufferLen; z++) |
||
301 | { |
||
302 | if (!GetByte(&pLine, &pLineBuffer[z])) |
||
303 | return ArgError(Num_ErrMsgInvalidHexData, pArg); |
||
304 | Sum += pLineBuffer[z]; |
||
305 | } |
||
306 | |||
307 | if (!GetByte(&pLine, &Tmp)) |
||
308 | return ArgError(Num_ErrMsgInvalidHexData, pArg); |
||
309 | Sum += Tmp; |
||
310 | if (Sum & 0xff) |
||
311 | return ArgError(Num_ErrMsgHexDataChecksumError, pArg); |
||
312 | |||
313 | if (Chunk.Start + Chunk.Length == LineBufferStart) |
||
314 | { |
||
315 | ResizeBuffer(&Chunk.pCode, &Chunk.Length, Chunk.Length + LineBufferLen); |
||
316 | memcpy(&Chunk.pCode[Chunk.Length - LineBufferLen], pLineBuffer, LineBufferLen); |
||
317 | } |
||
318 | else |
||
319 | { |
||
320 | if (Chunk.Length) |
||
321 | FlushChunk(&Chunk); |
||
322 | ResizeBuffer(&Chunk.pCode, &Chunk.Length, LineBufferLen); |
||
323 | memcpy(Chunk.pCode, pLineBuffer, LineBufferLen); |
||
324 | Chunk.Start = LineBufferStart; |
||
325 | } |
||
326 | } |
||
327 | if (Chunk.Length) |
||
328 | FlushChunk(&Chunk); |
||
329 | |||
330 | if (pLineBuffer) |
||
331 | free(pLineBuffer); |
||
332 | if (pDataBuffer) |
||
333 | free(pDataBuffer); |
||
334 | fclose(pFile); |
||
335 | return e_cmd_ok; |
||
336 | } |
||
337 | |||
338 | static as_cmd_result_t CMD_EntryAddress(Boolean Negate, const char *pArg) |
||
339 | { |
||
340 | LargeWord Address; |
||
341 | char *pName = NULL; |
||
342 | String Arg, Str; |
||
343 | Boolean OK; |
||
344 | |||
345 | if (Negate || !*pArg) |
||
346 | return ArgError(Num_ErrMsgAddressArgumentMissing, NULL); |
||
347 | |||
348 | strmaxcpy(Arg, pArg, sizeof(Arg)); |
||
349 | if ((pName = ParenthPos(Arg, ','))) |
||
350 | *pName++ = '\0'; |
||
351 | |||
352 | if (*Arg) |
||
353 | { |
||
354 | if (*Arg == '(') |
||
355 | { |
||
356 | Byte Vector[8]; |
||
357 | char *pVectorAddress = NULL, *pAddrLen = NULL, *pEndianess = NULL; |
||
358 | LargeWord AddrLen, VectorAddress = 0, z; |
||
359 | Boolean VectorMSB; |
||
360 | int l; |
||
361 | |||
362 | pVectorAddress = Arg + 1; |
||
363 | l = strlen(pVectorAddress); |
||
364 | if (pVectorAddress[l - 1] != ')') |
||
365 | return ArgError(Num_ErrMsgClosingPatentheseMissing, pVectorAddress); |
||
366 | pVectorAddress[l - 1] = '\0'; |
||
367 | |||
368 | if ((pAddrLen = strchr(pVectorAddress, ','))) |
||
369 | { |
||
370 | *pAddrLen++ = '\0'; |
||
371 | if ((pEndianess = strchr(pAddrLen, ','))) |
||
372 | *pEndianess++ = '\0'; |
||
373 | } |
||
374 | |||
375 | if (pVectorAddress && *pVectorAddress) |
||
376 | { |
||
377 | VectorAddress = ConstLongInt(pVectorAddress, &OK, 10); |
||
378 | if (!OK) |
||
379 | return ArgError(Num_ErrMsgInvalidNumericValue, pVectorAddress); |
||
380 | } |
||
381 | else |
||
382 | pVectorAddress = 0; |
||
383 | |||
384 | if (pAddrLen && *pAddrLen) |
||
385 | { |
||
386 | AddrLen = ConstLongInt(pAddrLen, &OK, 10); |
||
387 | if (!OK || (AddrLen > sizeof(Vector))) |
||
388 | return ArgError(Num_ErrMsgInvalidNumericValue, pAddrLen); |
||
389 | } |
||
390 | else |
||
391 | AddrLen = 1; |
||
392 | |||
393 | if (pEndianess && *pEndianess) |
||
394 | { |
||
395 | if (!as_strcasecmp(pEndianess, "MSB")) |
||
396 | VectorMSB = True; |
||
397 | else if (!as_strcasecmp(pEndianess, "LSB")) |
||
398 | VectorMSB = False; |
||
399 | else |
||
400 | return ArgError(Num_ErrMsgInvalidEndinaness, pEndianess); |
||
401 | } |
||
402 | else |
||
403 | VectorMSB = True; /* TODO: depend on CPU */ |
||
404 | |||
405 | if (!RetrieveCodeFromChunkList(&CodeChunks, VectorAddress, Vector, AddrLen)) |
||
406 | return ArgError(Num_ErrMsgCannotRetrieveEntryAddressData, NULL); |
||
407 | |||
408 | Address = 0; |
||
409 | for (z = 0; z < AddrLen; z++) |
||
410 | { |
||
411 | Address <<= 8; |
||
412 | Address |= VectorMSB ? Vector[z] : Vector[AddrLen - 1 - z]; |
||
413 | } |
||
414 | as_snprintf(Str, sizeof Str, "indirect address @ %lllx -> 0x%lllx", VectorAddress, Address); |
||
415 | printf("%s\n", Str); |
||
416 | AddChunk(&UsedDataChunks, VectorAddress, AddrLen, True); |
||
417 | |||
418 | if (pName && *pName) |
||
419 | { |
||
420 | String Str; |
||
421 | |||
422 | as_snprintf(Str, sizeof(Str), "Vector_2_%s", pName); |
||
423 | AddInvSymbol(Str, VectorAddress); |
||
424 | } |
||
425 | } |
||
426 | else |
||
427 | { |
||
428 | Address = ConstLongInt(pArg, &OK, 10); |
||
429 | if (!OK) |
||
430 | return ArgError(Num_ErrMsgInvalidNumericValue, pArg); |
||
431 | } |
||
432 | } |
||
433 | else |
||
434 | Address = 0; |
||
435 | |||
436 | if (pName && *pName) |
||
437 | AddInvSymbol(pName, Address); |
||
438 | AddEntryAddress(Address); |
||
439 | |||
440 | return e_cmd_arg; |
||
441 | } |
||
442 | |||
443 | static as_cmd_result_t CMD_Symbol(Boolean Negate, const char *pArg) |
||
444 | { |
||
445 | LargeWord Address; |
||
446 | char *pName = NULL; |
||
447 | String Arg; |
||
448 | Boolean OK; |
||
449 | |||
450 | if (Negate || !*pArg) |
||
451 | return ArgError(Num_ErrMsgSymbolArgumentMissing, NULL); |
||
452 | |||
453 | strmaxcpy(Arg, pArg, sizeof(Arg)); |
||
454 | if ((pName = strchr(Arg, '='))) |
||
455 | *pName++ = '\0'; |
||
456 | |||
457 | if (*Arg) |
||
458 | { |
||
459 | Address = ConstLongInt(Arg, &OK, 10); |
||
460 | if (!OK) |
||
461 | return ArgError(Num_ErrMsgInvalidNumericValue, Arg); |
||
462 | } |
||
463 | else |
||
464 | Address = 0; |
||
465 | |||
466 | if (pName && *pName) |
||
467 | AddInvSymbol(pName, Address); |
||
468 | |||
469 | return e_cmd_arg; |
||
470 | } |
||
471 | |||
472 | static as_cmd_result_t CMD_CPU(Boolean Negate, const char *pArg) |
||
473 | { |
||
474 | const tCPUDef *pCPUDef; |
||
475 | |||
476 | if (Negate || !*pArg) |
||
477 | return ArgError(Num_ErrMsgCPUArgumentMissing, NULL); |
||
478 | |||
479 | if (!as_strcasecmp(pArg, "?") || !as_strcasecmp(pArg, "LIST")) |
||
480 | { |
||
481 | write_cpu_list_exit = True; |
||
482 | return e_cmd_ok; |
||
483 | } |
||
484 | |||
485 | pCPUDef = LookupCPUDefByName(pArg); |
||
486 | if (!pCPUDef) |
||
487 | return ArgError(Num_ErrMsgUnknownCPU, pArg); |
||
488 | |||
489 | pCPUDef->SwitchProc(pCPUDef->pUserData); |
||
490 | |||
491 | return e_cmd_arg; |
||
492 | } |
||
493 | |||
494 | static as_cmd_result_t CMD_HexLowerCase(Boolean Negate, const char *Arg) |
||
495 | { |
||
496 | UNUSED(Arg); |
||
497 | |||
498 | HexStartCharacter = Negate ? 'A' : 'a'; |
||
499 | return e_cmd_ok; |
||
500 | } |
||
501 | |||
502 | static as_cmd_result_t CMD_PrintVersion(Boolean Negate, const char *Arg) |
||
503 | { |
||
504 | UNUSED(Arg); |
||
505 | |||
506 | if (Negate) |
||
507 | return e_cmd_err; |
||
508 | |||
509 | write_version_exit = True; |
||
510 | return e_cmd_ok; |
||
511 | } |
||
512 | |||
513 | static as_cmd_result_t CMD_PrintHelp(Boolean Negate, const char *Arg) |
||
514 | { |
||
515 | UNUSED(Arg); |
||
516 | |||
517 | if (Negate) |
||
518 | return e_cmd_err; |
||
519 | |||
520 | write_help_exit = True; |
||
521 | return e_cmd_ok; |
||
522 | } |
||
523 | |||
524 | static as_cmd_result_t CMD_screen_height(Boolean negate, const char *p_arg) |
||
525 | { |
||
526 | Boolean ok; |
||
527 | int new_screen_height; |
||
528 | |||
529 | if (negate) |
||
530 | { |
||
531 | screen_height = 0; |
||
532 | return e_cmd_ok; |
||
533 | } |
||
534 | new_screen_height = ConstLongInt(p_arg, &ok, 10); |
||
535 | if (!ok) |
||
536 | return e_cmd_err; |
||
537 | screen_height = new_screen_height; |
||
538 | return e_cmd_arg; |
||
539 | } |
||
540 | |||
541 | static as_cmd_rec_t DASParams[] = |
||
542 | { |
||
543 | { "CPU" , CMD_CPU }, |
||
544 | { "BINFILE" , CMD_BinFile }, |
||
545 | { "HEXFILE" , CMD_HexFile }, |
||
546 | { "ENTRYADDRESS" , CMD_EntryAddress }, |
||
547 | { "SCREENHEIGHT" , CMD_screen_height }, |
||
548 | { "SYMBOL" , CMD_Symbol }, |
||
549 | { "h" , CMD_HexLowerCase }, |
||
550 | { "HELP" , CMD_PrintHelp }, |
||
551 | { "VERSION" , CMD_PrintVersion } |
||
552 | }; |
||
553 | |||
554 | typedef struct |
||
555 | { |
||
556 | FILE *pDestFile; |
||
557 | int MaxSrcLineLen, MaxLabelLen; |
||
558 | } tDisasmData; |
||
559 | |||
560 | static void DisasmIterator(const OneChunk *pChunk, Boolean IsData, void *pUser) |
||
561 | { |
||
562 | LargeWord Address; |
||
563 | char NumString[50]; |
||
564 | tDisassInfo Info; |
||
565 | tDisasmData *pData = (tDisasmData*)pUser; |
||
566 | const char *pLabel; |
||
567 | Byte Code[100]; |
||
568 | unsigned z; |
||
569 | int DataSize = -1; |
||
570 | |||
571 | Address = pChunk->Start; |
||
572 | HexString(NumString, sizeof(NumString), Address, 0); |
||
573 | fprintf(pData->pDestFile, "\n"); |
||
574 | PrTabs(pData->pDestFile, pData->MaxLabelLen, 0); |
||
575 | fprintf(pData->pDestFile, "org\t$%s\n", NumString); |
||
576 | while (Address < pChunk->Start + pChunk->Length) |
||
577 | { |
||
578 | pLabel = LookupInvSymbol(Address); |
||
579 | if (pLabel && !strncmp(pLabel, "Vector_", 7) && IsData) |
||
580 | { |
||
581 | String Num; |
||
582 | char *pEnd = strchr(pLabel + 7, '_'); |
||
583 | |||
584 | if (pEnd) |
||
585 | { |
||
586 | int l = pEnd - (pLabel + 7); |
||
587 | |||
588 | memcpy(Num, pLabel + 7, l); |
||
589 | Num[l] = '\0'; |
||
590 | DataSize = strtol(Num, &pEnd, 10); |
||
591 | if (*pEnd) |
||
592 | DataSize = -1; |
||
593 | } |
||
594 | } |
||
595 | |||
596 | Disassemble(Address, &Info, IsData, DataSize); |
||
597 | if (Info.pRemark) |
||
598 | { |
||
599 | PrTabs(pData->pDestFile, pData->MaxLabelLen, 0); |
||
600 | fprintf(pData->pDestFile, "; %s\n", Info.pRemark); |
||
601 | } |
||
602 | |||
603 | if (pLabel) |
||
604 | { |
||
605 | fprintf(pData->pDestFile, "%s:", pLabel); |
||
606 | PrTabs(pData->pDestFile, pData->MaxLabelLen, tabbedstrlen(pLabel) + 1); |
||
607 | } |
||
608 | else |
||
609 | PrTabs(pData->pDestFile, pData->MaxLabelLen, 0); |
||
610 | fprintf(pData->pDestFile, "%s", Info.SrcLine); |
||
611 | |||
612 | PrTabs(pData->pDestFile, pData->MaxSrcLineLen, tabbedstrlen(Info.SrcLine)); |
||
613 | fprintf(pData->pDestFile, ";"); |
||
614 | RetrieveCodeFromChunkList(&CodeChunks, Address, Code, Info.CodeLen); |
||
615 | for (z = 0; z < Info.CodeLen; z++) |
||
616 | { |
||
617 | HexString(NumString, sizeof(NumString), Code[z], 2); |
||
618 | fprintf(pData->pDestFile, " %s", NumString); |
||
619 | } |
||
620 | fputc('\n', pData->pDestFile); |
||
621 | |||
622 | Address += Info.CodeLen; |
||
623 | } |
||
624 | } |
||
625 | |||
626 | int main(int argc, char **argv) |
||
627 | { |
||
628 | LargeWord Address, NextAddress; |
||
629 | Boolean NextAddressValid; |
||
630 | tDisassInfo Info; |
||
631 | unsigned z; |
||
632 | tDisasmData Data; |
||
633 | int ThisSrcLineLen; |
||
634 | as_cmd_results_t cmd_results; |
||
635 | |||
636 | strutil_init(); |
||
637 | nls_init(); |
||
638 | NLS_Initialize(&argc, argv); |
||
639 | dasmdef_init(); |
||
640 | cpulist_init(); |
||
641 | msg_level_init(); |
||
642 | nlmessages_init("das.msg", *argv, MsgId1, MsgId2); |
||
643 | deco68_init(); |
||
644 | deco87c800_init(); |
||
645 | deco4004_init(); |
||
646 | write_version_exit = write_help_exit = write_cpu_list_exit = False; |
||
647 | |||
648 | as_cmd_register(DASParams, as_array_size(DASParams)); |
||
649 | if (e_cmd_err == as_cmd_process(argc, argv, pEnvName, &cmd_results)) |
||
650 | { |
||
651 | fprintf(stderr, "%s%s\n", getmessage(cmd_results.error_arg_in_env ? Num_ErrMsgInvEnvParam : Num_ErrMsgInvParam), cmd_results.error_arg); |
||
652 | exit(4); |
||
653 | } |
||
654 | |||
655 | if ((msg_level >= e_msg_level_verbose) || write_version_exit) |
||
656 | { |
||
657 | String Ver; |
||
658 | |||
659 | as_snprintf(Ver, sizeof(Ver), "DAS V%s", Version); |
||
660 | WrCopyRight(Ver); |
||
661 | } |
||
662 | |||
663 | if (write_help_exit) |
||
664 | { |
||
665 | char *ph1, *ph2; |
||
666 | String Tmp; |
||
667 | as_snprintf(Tmp, sizeof(Tmp), "%s%s%s", getmessage(Num_InfoMessHead1), as_cmdarg_get_executable_name(), getmessage(Num_InfoMessHead2)); |
||
668 | write_console_next(Tmp); |
||
669 | for (ph1 = getmessage(Num_InfoMessHelp), ph2 = strchr(ph1, '\n'); ph2; ph1 = ph2 + 1, ph2 = strchr(ph1, '\n')) |
||
670 | { |
||
671 | *ph2 = '\0'; |
||
672 | write_console_next(ph1); |
||
673 | *ph2 = '\n'; |
||
674 | } |
||
675 | } |
||
676 | |||
677 | if (write_cpu_list_exit) |
||
678 | { |
||
679 | printf("%s\n", getmessage(Num_InfoMessCPUList)); |
||
680 | PrintCPUList(write_console_next); |
||
681 | } |
||
682 | |||
683 | if (write_version_exit || write_help_exit || write_cpu_list_exit) |
||
684 | exit(0); |
||
685 | |||
686 | if (!Disassemble) |
||
687 | { |
||
688 | fprintf(stderr, "no CPU set, aborting\n"); |
||
689 | exit(3); |
||
690 | } |
||
691 | |||
692 | /* walk through code */ |
||
693 | |||
694 | NextAddress = 0; |
||
695 | NextAddressValid = False; |
||
696 | Data.MaxSrcLineLen = 0; |
||
697 | while (EntryAddressAvail()) |
||
698 | { |
||
699 | Address = GetEntryAddress(NextAddressValid, NextAddress); |
||
700 | Disassemble(Address, &Info, False, -1); |
||
701 | AddChunk(&UsedCodeChunks, Address, Info.CodeLen, True); |
||
702 | if ((ThisSrcLineLen = tabbedstrlen(Info.SrcLine)) > Data.MaxSrcLineLen) |
||
703 | Data.MaxSrcLineLen = ThisSrcLineLen; |
||
704 | for (z = 0; z < Info.NextAddressCount; z++) |
||
705 | if (!AddressInChunk(&UsedCodeChunks, Info.NextAddresses[z])) |
||
706 | AddEntryAddress(Info.NextAddresses[z]); |
||
707 | NextAddress = Address + Info.CodeLen; |
||
708 | NextAddressValid = True; |
||
709 | } |
||
710 | |||
711 | /* round up src line & symbol length to next multiple of tabs */ |
||
712 | |||
713 | Data.MaxSrcLineLen += TABSIZE - (Data.MaxSrcLineLen % TABSIZE); |
||
714 | Data.MaxLabelLen = GetMaxInvSymbolNameLen() + 1; |
||
715 | Data.MaxLabelLen += TABSIZE - (Data.MaxLabelLen % TABSIZE); |
||
716 | Data.pDestFile = stdout; |
||
717 | |||
718 | /* bring areas into order */ |
||
719 | |||
720 | SortChunks(&UsedCodeChunks); |
||
721 | SortChunks(&UsedDataChunks); |
||
722 | |||
723 | /* dump them out */ |
||
724 | |||
725 | IterateChunks(DisasmIterator, &Data); |
||
726 | |||
727 | /* summary */ |
||
728 | |||
729 | DumpChunks(&UsedCodeChunks, Data.pDestFile); |
||
730 | |||
731 | return 0; |
||
732 | } |