Details | Last modification | View Log | RSS feed
| Rev | Author | Line No. | Line | 
|---|---|---|---|
| 1186 | 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 | } |