OpenCores
URL https://opencores.org/ocsvn/forwardcom/forwardcom/trunk

Subversion Repositories forwardcom

[/] [forwardcom/] [bintools/] [disasm2.cpp] - Blame information for rev 50

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 50 Agner
/****************************  disasm2.cpp   ********************************
2
* Author:        Agner Fog
3
* Date created:  2017-04-26
4
* Last modified: 2021-07-16
5
* Version:       1.11
6
* Project:       Binary tools for ForwardCom instruction set
7
* Module:        disassem.h
8
* Description:
9
* Disassembler for ForwardCom
10
*
11
* Copyright 2007-2021 GNU General Public License http://www.gnu.org/licenses
12
*****************************************************************************/
13
#include "stdafx.h"
14
 
15
static const char * commentSeparator = "//";       // Comment separator in output assembly file
16
 
17
 
18
/**************************  class CDisassembler  *****************************
19
Most member functions of CDisassembler are defined in disasm1.cpp
20
 
21
Only the functions that produce output are defined here:
22
******************************************************************************/
23
 
24
 
25
void CDisassembler::writeSymbolName(uint32_t symi) {
26
    // Write symbol name. symi = symbol index
27
    uint32_t sname = symbols[symi].st_name;
28
    if (sname == 0) outFile.put("no_name");
29
    else if (sname >= stringBuffer.dataSize()) outFile.put("(illegal name index)");
30
    else outFile.put((char*)stringBuffer.buf() + sname);
31
}
32
 
33
 
34
void CDisassembler::writeSectionName(int32_t SegIndex) {
35
    // Write name of section, segment or group from section index
36
    const char * name = "noname";
37
    if (sectionHeaders[SegIndex].sh_name < stringBuffer.dataSize()) {
38
        name = (char*)stringBuffer.buf() + sectionHeaders[SegIndex].sh_name;
39
    }
40
    outFile.put(name);
41
}
42
 
43
 
44
// Find any labels at current position and next
45
void CDisassembler::writeLabels() {
46
    // check section type
47
    uint8_t sectionType = sectionHeaders[section].sh_type;
48
    if (!(sectionType & SHT_ALLOCATED)) {
49
        return;   // section is not allocated
50
    }
51
    // start at new line
52
    if (outFile.getColumn() && !debugMode) outFile.newLine();
53
 
54
    if (iInstr == currentFunctionEnd && currentFunction) {
55
        // Current function is ending here
56
        writeSymbolName(currentFunction);
57
        outFile.put(' '); outFile.tabulate(asmTab2); // at least one space
58
        outFile.put("end");
59
        outFile.newLine();
60
        currentFunction = 0; currentFunctionEnd = 0;
61
    }
62
    //bool isFunction = false;
63
 
64
    // Make dummy symbol to search for
65
    ElfFwcSym currentPosition;
66
    currentPosition.st_section = section;
67
    currentPosition.st_value = iInstr;
68
    symbolExeAddress(currentPosition);
69
 
70
    // Search for any symbol here. Look for any misplaced symbols we might have skipped before last output
71
    uint32_t numSymbols = 0; // Check if multiple symbols at same place
72
    while (nextSymbol < symbols.numEntries()
73
        && symbols[nextSymbol] < currentPosition) {
74
        if (symbols[nextSymbol].st_section == currentPosition.st_section && iInstr
75
            && symbols[nextSymbol].st_type != STT_CONSTANT) {
76
            outFile.put(commentSeparator);
77
            outFile.put(" Warning: Misplaced symbol: ");
78
            writeSymbolName(nextSymbol);
79
            outFile.put(" at offset ");
80
            outFile.putHex(symbols[nextSymbol].st_value);
81
            outFile.newLine();
82
            symbols[nextSymbol].st_other |= 0x80000000;    // Remember symbol has been written
83
        }
84
        nextSymbol++;
85
    }
86
    // Write all symbols at current position
87
    while (nextSymbol < symbols.numEntries() && symbols[nextSymbol] == currentPosition) {
88
        if (symbols[nextSymbol].st_type != STT_CONSTANT) {
89
            if (numSymbols++) {           // Multiple symbols at same position
90
                if (debugMode) {
91
                    outFile.put(";  ");  // cannot show multiple lines at same address in debug mode
92
                }
93
                else {
94
                    outFile.put("\n");   // put on separate lines
95
                }
96
            }
97
            writeSymbolName(nextSymbol);
98
            if (symbols[nextSymbol].st_type == STT_FUNC && symbols[nextSymbol].st_bind != STB_LOCAL) {
99
                // This is a function            
100
                if (debugMode) {
101
                    outFile.put(": ");
102
                }
103
                else outFile.put(": function");
104
                //isFunction = true;
105
                currentFunction = nextSymbol;                  // Remember which function we are in
106
                if (symbols[nextSymbol].st_unitsize) {         // Calculate end of current function
107
                    if (symbols[nextSymbol].st_unitnum == 0) symbols[nextSymbol].st_unitnum = 1;
108
                    currentFunctionEnd = iInstr + symbols[nextSymbol].st_unitsize * symbols[nextSymbol].st_unitnum;
109
                }
110
                else currentFunctionEnd = 0;                   // Function size is not known
111
            }
112
            else if (codeMode & 1) { // local label        
113
                outFile.put(": ");
114
            }
115
            symbols[nextSymbol].st_other |= 0x80000000;        // Remember symbol has been written
116
        }
117
        nextSymbol++;
118
    }
119
    if (numSymbols) {
120
        if (codeMode == 1) {
121
            // if (!isFunction) outFile.put(':');          // has already been written
122
            if (!debugMode) outFile.newLine();             // Code. Put label on separate line
123
        }
124
        else {
125
            outFile.put(':');                              // Data. Make space after last label
126
        }
127
    }
128
}
129
 
130
 
131
void CDisassembler::writeDataItems() {
132
    // Write contents of data section to output file
133
    uint32_t nextLabel = 0;
134
    uint32_t nextRelocation = 0;
135
    uint32_t dataSize = 4;
136
    uint32_t currentSymbol;
137
    uint32_t sequenceEnd;
138
    ElfFwcReloc rel;                            // relocation record for searching
139
    uint32_t irel;                               // index to relocation record
140
    uint32_t numRel;                             // number of relocations found at current position
141
 
142
    operandType = 2;
143
    bool isFloat = false;
144
 
145
    // translate addresses if executable
146
    ElfFwcSym currentPosition;
147
    currentPosition.st_section = section;
148
    currentPosition.st_value = iInstr;
149
    symbolExeAddress(currentPosition);
150
 
151
    // find first relocation
152
    rel.r_offset = iInstr;
153
    rel.r_section = section;
154
    irel = relocations.findFirst(rel);
155
    irel &= 0x7FFFFFFF;
156
    if (irel < relocations.numEntries() && relocations[irel].r_section == section) {
157
        nextRelocation = (uint32_t)relocations[irel].r_offset;
158
    }
159
    else nextRelocation = sectionEnd;
160
 
161
    // Loop through section
162
    while (iInstr < sectionEnd) {
163
        // Search for symbol labels
164
        writeLabels();
165
        if (nextSymbol > 1) {
166
            // Get data size from current symbol
167
            currentSymbol = nextSymbol - 1;
168
            if (symbols[currentSymbol].st_section == currentPosition.st_section) {
169
                dataSize = symbols[currentSymbol].st_unitsize;
170
                if (dataSize > 8) dataSize = 8;
171
                if (dataSize == 0) dataSize = 4;
172
                isFloat = (symbols[currentSymbol].st_other & STV_FLOAT) != 0;
173
            }
174
        }
175
        // Get position of next symbol
176
        if (nextSymbol < symbols.numEntries()) {
177
            nextLabel = (uint32_t)symbols[nextSymbol].st_value;
178
            // translate to local offset
179
            if (isExecutable) nextLabel -= (uint32_t)sectionHeaders[section].sh_addr;
180
        }
181
        else nextLabel = sectionEnd;
182
 
183
        // Search for relocations
184
        rel.r_offset = iInstr;
185
        numRel = relocations.findAll(&irel, rel);
186
        if (numRel) {
187
            // Relocation found. Find size
188
            // Relocation size overrides any symbol size
189
            switch (relocations[irel].r_type & R_FORW_RELSIZEMASK) {
190
            case R_FORW_8:
191
                dataSize = 1;
192
                break;
193
            case R_FORW_16: case R_FORW_32LO: case R_FORW_32HI:
194
                dataSize = 2;
195
                break;
196
            case R_FORW_24:
197
                dataSize = 4;    // 3 bytes. Round up to 4
198
                break;
199
            case R_FORW_32: case R_FORW_64LO: case R_FORW_64HI:
200
                dataSize = 4;
201
                break;
202
            case R_FORW_64:
203
                dataSize = 8;
204
                break;
205
            default:
206
                writeError("Unknown data size for relocation");
207
                dataSize = 4;
208
                break;
209
            }
210
            isFloat = false;
211
            if (numRel > 1) writeError("Overlapping relocations");
212
            // Find position of next relocation
213
            if (irel+1 < relocations.numEntries() && relocations[irel+1].r_section == section) {
214
                nextRelocation = (uint32_t)relocations[irel+1].r_offset;
215
            }
216
            else nextRelocation = sectionEnd;
217
        }
218
 
219
        if (numRel) {
220
            // There is a relocation here. Write only one data item
221
            // Write type
222
            outFile.tabulate(asmTab1);
223
            switch (dataSize) {
224
            case 1: outFile.put("int8 "); break;
225
            case 2: outFile.put("int16 "); break;
226
            case 4: outFile.put("int32 "); break;
227
            case 8: outFile.put("int64 "); break;
228
            }
229
            outFile.tabulate(asmTab2);
230
            writeRelocationTarget(iInstr, dataSize);
231
 
232
            // Write comment with relocation type
233
            outFile.put(' '); outFile.tabulate(asmTab3);
234
            outFile.put(commentSeparator); outFile.put(' ');
235
            if (sectionEnd + sectionAddress> 0xFFFF) outFile.putHex((uint32_t)(iInstr + sectionAddress), 2);
236
            else outFile.putHex((uint16_t)(iInstr + sectionAddress), 2);
237
            outFile.put(" _ ");
238
            switch(relocations[irel].r_type & R_FORW_RELTYPEMASK) {
239
            case R_FORW_ABS:
240
                outFile.put("absolute address"); break;
241
            case R_FORW_SELFREL:
242
                outFile.put("self-relative"); break;
243
            case R_FORW_IP_BASE:
244
                outFile.put("relative to __ip_base"); break;
245
            case R_FORW_DATAP:
246
                outFile.put("relative to __datap_base"); break;
247
            case R_FORW_THREADP:
248
                outFile.put("relative to __threadp_base"); break;
249
            case R_FORW_REFP:
250
                outFile.put("relative to ");
251
                writeSymbolName(relocations[irel].r_refsym & 0x7FFFFFFF); break;
252
            case R_FORW_SYSFUNC:
253
                outFile.put("system function ID"); break;
254
            case R_FORW_SYSMODUL:
255
                outFile.put("system module ID"); break;
256
            case R_FORW_SYSCALL:
257
                outFile.put("system module and function ID"); break;
258
            case R_FORW_DATASTACK:
259
                outFile.put("data stack size"); break;
260
            case R_FORW_CALLSTACK:
261
                outFile.put("call stack size"); break;
262
            case R_FORW_REGUSE:
263
                outFile.put("register use"); break;
264
            default:
265
                outFile.put("unknown relocation type"); break;
266
            }
267
            iInstr += dataSize;
268
        }
269
        else {
270
            // Write multiple data items. Find where sequence ends
271
            sequenceEnd = sectionEnd;
272
            if (nextLabel < sequenceEnd && nextLabel > iInstr) sequenceEnd = nextLabel;
273
            if (nextRelocation < sequenceEnd && nextRelocation > iInstr) sequenceEnd = nextRelocation;
274
            // Number of data items in this sequence
275
            uint32_t num = (sequenceEnd - iInstr) / dataSize;
276
            if (num == 0) {
277
                dataSize = sequenceEnd - iInstr;  // Reduce data size to avoid going past sequenceEnd
278
                while (dataSize & (dataSize-1)) dataSize--; // Round down to nearest power of 2                
279
                num = 1;
280
            }
281
            // Number of data items per line
282
            uint32_t itemsPerLine = 4;
283
            if (dataSize > 4) itemsPerLine = 2;
284
            if (dataSize < 2) itemsPerLine = 8;
285
            uint32_t lineEnd = iInstr + itemsPerLine * dataSize;
286
            if (lineEnd > sequenceEnd) {
287
                // Round down to multiple of dataSize
288
                itemsPerLine = (sequenceEnd - iInstr) / dataSize;
289
                lineEnd = iInstr + itemsPerLine * dataSize;
290
            }
291
            // Write type
292
            outFile.tabulate(asmTab1);
293
            switch (dataSize) {
294
            case 1: outFile.put("int8 "); break;
295
            case 2: outFile.put("int16 "); break;
296
            case 4: outFile.put("int32 "); break;
297
            case 8: outFile.put("int64 "); break;
298
            }
299
            outFile.tabulate(asmTab2);
300
 
301
            // Write items
302
            uint32_t lineBegin = iInstr;
303
            while (iInstr < lineEnd) {
304
                if (sectionHeaders[section].sh_type == SHT_NOBITS) {
305
                    // BSS section has no data in buffer
306
                    outFile.put('0');
307
                }
308
                else {
309
                    // Write item
310
                    switch (dataSize) {
311
                    case 1:
312
                        outFile.putHex(*(uint8_t*)(sectionBuffer + iInstr));
313
                        break;
314
                    case 2:
315
                        outFile.putHex(*(uint16_t*)(sectionBuffer + iInstr));
316
                        break;
317
                    case 4:
318
                        outFile.putHex(*(uint32_t*)(sectionBuffer + iInstr));
319
                        break;
320
                    case 8:
321
                        outFile.putHex(*(uint64_t*)(sectionBuffer + iInstr));
322
                        break;
323
                    }
324
                }
325
                iInstr += dataSize;
326
                if (iInstr < lineEnd) outFile.put(", ");  // comma if not the last item on line
327
            }
328
            // Write data comment
329
            outFile.put(' '); outFile.tabulate(asmTab3);
330
            outFile.put(commentSeparator); outFile.put(' ');
331
 
332
            // write address
333
            uint64_t address = lineBegin + sectionAddress;
334
            if (sectionHeaders[section].sh_flags & SHF_IP) {
335
                // IP based section. subtract ip_base for continuity with code section
336
                address -= fileHeader.e_ip_base;
337
            }
338
            if (sectionEnd + sectionAddress > 0xFFFF) outFile.putHex(uint32_t(address), 2);
339
            else outFile.putHex(uint16_t(address), 2);
340
 
341
            if (sectionHeaders[section].sh_type != SHT_NOBITS) { // skip data if BSS section
342
                outFile.put(" _ ");
343
                // Write data in alternative form
344
                for (uint32_t i = lineBegin; i < lineEnd; i += dataSize) {
345
                    switch (dataSize) {
346
                    case 1: {  // bytes. Write as characters
347
                        char c = *(char*)(sectionBuffer + i);
348
                        outFile.put((uint8_t)c < ' ' ? '.' : c);
349
                        break; }
350
                    case 2:
351
                        if (isFloat) { // half precision float
352
                            outFile.putFloat(half2float(*(uint16_t*)(sectionBuffer + i)));
353
                        }
354
                        else { // 16 bit integer. Write as signed decimal
355
                            outFile.putDecimal(*(int16_t*)(sectionBuffer + i), 1);
356
                        }
357
                        if (i + dataSize < lineEnd) outFile.put(", "); // Comma except before last item
358
                        break;
359
                    case 4:
360
                        if (isFloat) { // single precision float
361
                            outFile.putFloat(*(float*)(sectionBuffer + i));
362
                        }
363
                        else { // 16 bit integer. Write as signed decimal
364
                            outFile.putDecimal(*(int32_t*)(sectionBuffer + i), 1);
365
                        }
366
                        if (i + dataSize < lineEnd) outFile.put(", "); // Comma except before last item
367
                        break;
368
                    case 8:
369
                        if (isFloat) { // double precision float
370
                            outFile.putFloat(*(double*)(sectionBuffer + i));
371
                        }
372
                        else {  // 64 bit integer. Write as signed decimal if not huge
373
                            int64_t x = *(int64_t*)(sectionBuffer + i);
374
                            if (x == (int32_t)x) outFile.putDecimal((int32_t)x, 1);
375
                        }
376
                        if (i + dataSize < lineEnd) outFile.put(", "); // Comma except before last item
377
                        break;
378
                    default:;
379
                    }
380
                }
381
            }
382
        }
383
        if (iInstr < sectionEnd) outFile.newLine();
384
    }
385
    // write label at end of data section, if any
386
    if ((section + 1 == sectionHeaders.numEntries() ||
387
    ((sectionHeaders[section].sh_flags ^ sectionHeaders[section + 1].sh_flags) & SHF_BASEPOINTER))
388
    && nextSymbol < symbols.numEntries()) {
389
        writeLabels();
390
    }
391
}
392
 
393
static const uint32_t relocationSizes[16] = {0, 1, 2, 3, 4, 4, 4, 8, 8, 8, 0, 0, 0, 0, 0, 0};
394
 
395
void CDisassembler::writeRelocationTarget(uint32_t src, uint32_t size) {
396
    // Write relocation target for this source position
397
    // Find relocation
398
    ElfFwcReloc rel;
399
    rel.r_offset = src;
400
    rel.r_section = section;
401
    //uint32_t irel;  // index to relocation record
402
    uint32_t n = relocations.findAll(&relocation, rel);
403
    if (n == 0) return;
404
    if (n > 1) {
405
        writeWarning(n ? "Overlapping relocations" : "No relocation found here");
406
        return;
407
    }
408
    relocation++;    // add 1 to avoid zero
409
    relocations[relocation-1].r_refsym |= 0x80000000;              // Remember relocation has been used OK
410
    // write scale factor if scale factor != 1 and not a jump target
411
    bool writeScale = relocations[relocation-1].r_type & R_FORW_RELSCALEMASK;
412
    if (writeScale || codeMode > 1) outFile.put('(');
413
    uint32_t isym = relocations[relocation-1].r_sym;
414
    writeSymbolName(isym);
415
    // Find any addend
416
    int32_t expectedAddend = 0;
417
    int32_t addend = relocations[relocation-1].r_addend;
418
    if ((relocations[relocation-1].r_type & R_FORW_RELTYPEMASK) == R_FORW_SELFREL) {
419
        if (fInstr) {                                      // Expected addend for self-relative address
420
            if (fInstr->addrSize) {                        // Jump instruction or memory operand
421
                expectedAddend = fInstr->addrPos - instrLength * 4;
422
            }
423
            else {                                         // Relocation of immediate operand
424
                expectedAddend = fInstr->immPos - instrLength * 4;
425
            }
426
        }
427
    }
428
    addend -= expectedAddend;
429
    if ((relocations[relocation-1].r_type & R_FORW_RELTYPEMASK) == R_FORW_REFP) {
430
        // has reference point
431
        outFile.put('-');
432
        uint32_t isym2 = relocations[relocation-1].r_refsym & 0x7FFFFFFF; // remove 0x80000000 flag
433
        writeSymbolName(isym2);
434
    }
435
    if (writeScale) {
436
        // write scale factor
437
        outFile.put(")/");
438
        outFile.putDecimal(1 << relocations[relocation-1].r_type & R_FORW_RELSCALEMASK);
439
    }
440
 
441
    // Check size of relocation
442
    if (addend > 0) {
443
        outFile.put('+'); outFile.putHex((uint32_t)addend);
444
    }
445
    else if (addend < 0) {
446
        outFile.put('-'); outFile.putHex(uint32_t(-addend));
447
    }
448
    if (codeMode > 1 && !writeScale) outFile.put(')');
449
 
450
    // Check for errors
451
    if (n > 1) writeError("Overlapping relocations here");
452
    uint32_t relSize = relocationSizes[relocations[relocation-1].r_type >> 8 & 0x0F];
453
    if (relSize < size) writeWarning("Relocation size less than data field");
454
    if (relSize > size) writeError("Relocation size bigger than data field");
455
}
456
 
457
void CDisassembler::writeJumpTarget(uint32_t src, uint32_t size) {
458
    // Write relocation jump target for this source position
459
    // Find relocation
460
    ElfFwcReloc rel;
461
    rel.r_offset = src;
462
    rel.r_section = section;
463
    //uint32_t irel;  // index to relocation record
464
    uint32_t n = relocations.findAll(&relocation, rel);
465
    if (n == 0) return;
466
    if (n > 1) {
467
        writeWarning(n ? "Overlapping relocations" : "No relocation found here");
468
        return;
469
    }
470
    relocation++;    // add 1 to avoid zero
471
    relocations[relocation-1].r_refsym |= 0x80000000;              // Remember relocation has been used OK
472
                                                                   // write scale factor if scale factor != 1 and not a jump target
473
    if (codeMode > 1) outFile.put('(');
474
    uint32_t isym = relocations[relocation-1].r_sym;
475
    writeSymbolName(isym);
476
    // Find any addend
477
    int32_t expectedAddend = 0;
478
    int32_t addend = relocations[relocation-1].r_addend;
479
    if ((relocations[relocation-1].r_type & R_FORW_RELTYPEMASK) == R_FORW_SELFREL && fInstr) {
480
        expectedAddend = fInstr->jumpPos - instrLength * 4;
481
    }
482
    addend -= expectedAddend;
483
 
484
    // Check size of relocation
485
    uint32_t expectedRelSize = size;                              // Expected size of relocation
486
    if (fInstr) {
487
        expectedRelSize = fInstr->jumpSize;
488
    }
489
    if (addend > 0) {
490
        outFile.put('+'); outFile.putHex((uint32_t)addend);
491
    }
492
    else if (addend < 0) {
493
        outFile.put('-'); outFile.putHex(uint32_t(-addend));
494
    }
495
    if (codeMode > 1) outFile.put(')');
496
 
497
    // Check for errors
498
    if (n > 1) writeError("Overlapping relocations here");
499
    uint32_t relSize = relocationSizes[relocations[relocation-1].r_type >> 8 & 0x0F];
500
    if (relSize < expectedRelSize) writeWarning("Relocation size less than data field");
501
    if (relSize > expectedRelSize) writeError("Relocation size bigger than data field");
502
}
503
 
504
 
505
/*
506
int CDisassembler::writeFillers() {
507
    return 1;
508
}
509
 
510
void CDisassembler::writeAlign(uint32_t a) {
511
    // Write alignment directive
512
    outFile.put("ALIGN");
513
    outFile.tabulate(asmTab1);
514
    outFile.putDecimal(a);
515
    outFile.newLine();
516
} */
517
 
518
void CDisassembler::writeFileBegin() {
519
    outFile.setFileType(FILETYPE_ASM);
520
    if (debugMode) return;
521
 
522
    // Initial comment
523
    outFile.put(commentSeparator);
524
    if (outputFile == cmd.outputListFile) {
525
        outFile.put(" Assembly listing of file: ");
526
    }
527
    else {
528
        outFile.put(" Disassembly of file: ");
529
    }
530
    outFile.put(cmd.getFilename(cmd.inputFile));
531
    outFile.newLine();
532
    // Date and time. 
533
    // Note: will fail after year 2038 on computers that use 32-bit time_t
534
    time_t time1 = time(0);
535
    char * timestring = ctime(&time1);
536
    if (timestring) {
537
        // Remove terminating '\n' in timestring
538
        for (char *c = timestring; *c; c++) {
539
            if (*c < ' ') *c = 0;
540
        }
541
        // Write date and time as comment
542
        outFile.put(commentSeparator); outFile.put(' ');
543
        outFile.put(timestring);
544
        outFile.newLine();
545
    }
546
    // Write special symbols and addresses if executable file
547
    if (isExecutable) {
548
        outFile.newLine();  outFile.put(commentSeparator);
549
        outFile.put(" __ip_base = ");  outFile.putHex(fileHeader.e_ip_base);
550
        outFile.newLine();  outFile.put(commentSeparator);
551
        outFile.put(" __datap_base = ");  outFile.putHex(fileHeader.e_datap_base);
552
        outFile.newLine();  outFile.put(commentSeparator);
553
        outFile.put(" __threadp_base = ");  outFile.putHex(fileHeader.e_threadp_base);
554
        outFile.newLine();  outFile.put(commentSeparator);
555
        outFile.put(" __entry_point = ");  outFile.putHex(fileHeader.e_entry);
556
        outFile.newLine();
557
    }
558
 
559
    // Write imported and exported symbols
560
    outFile.newLine();
561
    writePublicsAndExternals();
562
}
563
 
564
 
565
void CDisassembler::writePublicsAndExternals() {
566
    // Write public and external symbol definitions
567
    if (debugMode) return;
568
    uint32_t i;                                     // Loop counter
569
    uint32_t linesWritten = 0;                      // Count lines written
570
 
571
    // Loop through public symbols
572
    for (i = 0; i < symbols.numEntries(); i++) {
573
        if (symbols[i].st_bind && symbols[i].st_section) {
574
            // Symbol is public
575
            outFile.put("public ");
576
            // Write name
577
            writeSymbolName(i);
578
            // Code or data
579
            if (symbols[i].st_type == STT_FUNC) {
580
                outFile.put(": function");
581
                if (symbols[i].st_other & STV_REGUSE) {
582
                    // Write register use
583
                    outFile.put(", registeruse = ");  outFile.putHex(symbols[i].st_reguse1);
584
                    outFile.put(", ");  outFile.putHex(symbols[i].st_reguse2);
585
                }
586
            }
587
            else if (symbols[i].st_other & STV_EXEC) outFile.put(": function");
588
            else if (symbols[i].st_type == STT_OBJECT || symbols[i].st_type == STT_SECTION) {
589
                // data object. get base pointer
590
                if (symbols[i].st_other & (STV_IP | STV_EXEC)) outFile.put(": ip");
591
                else if (symbols[i].st_other & STV_DATAP) outFile.put(": datap");
592
                else if (symbols[i].st_other & STV_THREADP) outFile.put(": threadp");
593
                else if (symbols[i].st_other & STV_WRITE) outFile.put(": datap");
594
            }
595
            //else if (symbols[i].st_type == STT_FILE) outFile.put(": filename");
596
            //else if (symbols[i].st_type == STT_SECTION) outFile.put(": section");
597
            else if (symbols[i].st_type == STT_CONSTANT) {
598
                outFile.put(": constant"); outFile.newLine();  // write value
599
                outFile.put("% "); writeSymbolName(i); outFile.put(" = ");
600
                outFile.putHex(symbols[i].st_value);
601
            }
602
            else if (symbols[i].st_type == 0) {
603
                outFile.put(": absolute"); outFile.newLine();
604
            }
605
            else {
606
                outFile.put(": unknown type. type="); outFile.putHex(symbols[i].st_type);
607
                outFile.put(", bind="); outFile.putHex(symbols[i].st_bind);
608
                outFile.put(", other="); outFile.putHex(symbols[i].st_other);
609
            }
610
            // Check if weak or communal
611
            if (symbols[i].st_bind & STB_WEAK) {
612
                outFile.put(" weak");
613
            }
614
            if (symbols[i].st_type == STT_COMMON || (symbols[i].st_other & STV_COMMON)) outFile.put(", communal");
615
            outFile.newLine();  linesWritten++;
616
        }
617
    }
618
    // Blank line if anything written
619
    if (linesWritten) {
620
        outFile.newLine();
621
        linesWritten = 0;
622
    }
623
    // Loop through external symbols
624
    for (i = 0; i < symbols.numEntries(); i++) {
625
        if (symbols[i].st_bind && !symbols[i].st_section) {
626
            // Symbol is external
627
            outFile.put("extern ");
628
            // Write name
629
            writeSymbolName(i);
630
            // Code or data
631
            if (symbols[i].st_type == STT_FUNC) {
632
                outFile.put(": function");
633
                if (symbols[i].st_other & STV_REGUSE) {
634
                    // Write register use
635
                    outFile.put(", registeruse = ");  outFile.putHex(symbols[i].st_reguse1);
636
                    outFile.put(", ");  outFile.putHex(symbols[i].st_reguse2);
637
                }
638
            }
639
            else if (symbols[i].st_other & STV_EXEC) outFile.put(": function");
640
            //else if (symbols[i].st_other & (STV_READ | SHF_WRITE)) outFile.put(": data");
641
            else if (symbols[i].st_other & STV_IP) outFile.put(": ip");
642
            else if (symbols[i].st_other & STV_DATAP) outFile.put(": datap");
643
            else if (symbols[i].st_other & STV_THREADP) outFile.put(": threadp");
644
            else if (symbols[i].st_type == STT_OBJECT) outFile.put(": datap");
645
            else if (symbols[i].st_type == STT_CONSTANT) outFile.put(": constant");
646
            else if (symbols[i].st_type == 0) outFile.put(": absolute");
647
            else {
648
                outFile.put(": unknown type. type="); outFile.putHex(symbols[i].st_type);
649
                outFile.put(", other="); outFile.putHex(symbols[i].st_other);
650
            }
651
            // Check if weak or communal
652
            if (symbols[i].st_bind & STB_WEAK) {
653
                if (symbols[i].st_bind == STB_UNRESOLVED) outFile.put(" // unresolved!");
654
                else outFile.put(", weak");
655
            }
656
            if (symbols[i].st_type == STT_COMMON) outFile.put(", communal");
657
            // Finished line
658
            outFile.newLine();  linesWritten++;
659
        }
660
    }
661
    // Blank line if anything written
662
    if (linesWritten) {
663
        outFile.newLine();
664
        linesWritten = 0;
665
    }
666
}
667
 
668
 
669
void CDisassembler::writeFileEnd() {
670
    // Write end of file
671
}
672
 
673
void CDisassembler::writeSectionBegin() {
674
    // Write begin of section
675
    outFile.newLine();                            // Blank line
676
 
677
    // Check if section is valid
678
    if (section == 0 || section >= sectionHeaders.numEntries()) {
679
        // Illegal segment entry
680
        outFile.put("UNKNOWN SEGMENT");  outFile.newLine();
681
        return;
682
    }
683
 
684
    // Write segment name
685
    writeSectionName(section); outFile.put(" ");
686
    // tabulate
687
    outFile.tabulate(asmTab1);
688
    // Write "segment"
689
    outFile.put("section");
690
 
691
    // Write type
692
    if (sectionHeaders[section].sh_flags & SHF_READ) outFile.put(" read");
693
    if (sectionHeaders[section].sh_flags & SHF_WRITE) outFile.put(" write");
694
    if (sectionHeaders[section].sh_flags & SHF_EXEC) outFile.put(" execute");
695
    else if (sectionHeaders[section].sh_flags & SHF_IP) outFile.put(" ip");
696
    if (sectionHeaders[section].sh_flags & SHF_DATAP) outFile.put(" datap");
697
    if (sectionHeaders[section].sh_flags & SHF_THREADP) outFile.put(" threadp");
698
    if (sectionHeaders[section].sh_flags & SHF_EXCEPTION_HND) outFile.put(" exception_hand");
699
    if (sectionHeaders[section].sh_flags & SHF_EVENT_HND) outFile.put(" event_hand");
700
    if (sectionHeaders[section].sh_flags & SHF_DEBUG_INFO) outFile.put(" debug_info");
701
    if (sectionHeaders[section].sh_flags & SHF_COMMENT) outFile.put(" comment_info");
702
    if (sectionHeaders[section].sh_type == SHT_NOBITS) outFile.put(" uninitialized");
703
    if (sectionHeaders[section].sh_type == SHT_COMDAT) outFile.put(" communal");
704
 
705
    // Write alignment
706
    uint32_t align = 1 << sectionHeaders[section].sh_align;
707
    outFile.put(" align=");
708
    if (align < 16) outFile.putDecimal(align); else outFile.putHex(align);
709
 
710
    // tabulate to comment
711
    outFile.put(" ");  outFile.tabulate(asmTab3);
712
    outFile.put(commentSeparator);
713
    if (codeMode == 1) {  // code section
714
        outFile.put(" address/4. ");
715
    }
716
    else {
717
        outFile.put(" address.   ");
718
    }
719
    // Write section number
720
    outFile.put("section ");
721
    outFile.putDecimal(section);
722
    // Write library and module, if available
723
    if (sectionHeaders[section].sh_module && sectionHeaders[section].sh_module < secStringTableLen) {
724
        outFile.put(". ");
725
        if (sectionHeaders[section].sh_library) {
726
            outFile.put(secStringTable + sectionHeaders[section].sh_library);
727
            outFile.put(':');
728
        }
729
        outFile.put(secStringTable + sectionHeaders[section].sh_module);
730
    }
731
 
732
    // New line
733
    outFile.newLine();
734
}
735
 
736
 
737
void CDisassembler::writeSectionEnd() {
738
    // Write end of section
739
   outFile.newLine();
740
 
741
   // Write segment name
742
   writeSectionName(section);  outFile.put(" ");  outFile.tabulate(asmTab1);
743
   // Write "segment"
744
   outFile.put("end");  outFile.newLine();
745
}
746
 
747
 
748
void CDisassembler::writeInstruction() {
749
    // Write instruction and operands
750
    // Check if instruction crosses section boundary
751
    if (iInstr + instrLength * 4 > sectionEnd) writeError("Instruction crosses section boundary");
752
 
753
    // Find instruction in instruction_list
754
    SInstruction2 iRecSearch;
755
 
756
    iRecSearch.format = format;
757
    iRecSearch.category = fInstr->category;
758
    iRecSearch.op1 = pInstr->a.op1;
759
    relocation = 0;
760
 
761
    if (iRecSearch.category == 4) {                        // jump instruction
762
        // Set op1 = opj for jump instructions in format 2.5.x and 3.1.0
763
        if (fInstr->imm2 & 0x80) {
764
            iRecSearch.op1 = pInstr->b[0];                 // OPJ is in IM1
765
            if (fInstr->imm2 & 0x40) iRecSearch.op1 = 63;  // OPJ has fixed value
766
            if (fInstr->imm2 & 0x10) iRecSearch.op1 = pInstr->b[7];  // OPJ is in upper part of IM2
767
        }
768
        // Set op1 for template D
769
        if (fInstr->tmplate == 0xD) iRecSearch.op1 &= 0xF8;
770
    }
771
 
772
    // Insert op2 only if template E
773
    if (instrLength > 1 && fInstr->tmplate == 0xE && !(fInstr->imm2 & 0x100)) {
774
        iRecSearch.op2 = pInstr->a.op2;
775
    }
776
    else iRecSearch.op2 = 0;
777
 
778
    uint32_t index, n, i;
779
    n = instructionlist.findAll(&index, iRecSearch);
780
    if (n == 0) {    // Instruction not found in list
781
        writeWarning("Unknown instruction: ");
782
        for (i = 0; i < instrLength; i++) {
783
            outFile.putHex(pInstr->i[i]);
784
            if (i + 1 < instrLength) outFile.put(" ");
785
        }
786
        writeCodeComment();  outFile.newLine();
787
        return;
788
    }
789
    // One or more matches in instruction table. Check if one of these fits the operand type and format
790
    uint32_t otMask = 0x101 << operandType; // operand type mask for supported + optional
791
    bool otFits = true;          // Check if operand type fits
792
    bool formatFits = true;      // Check if format fits
793
    for (i = 0; i < n; i++) {    // search through matching instruction table entries
794
        if (operandType < 4 && !(fInstr->vect & 1)) {   // general purpose register            
795
            otFits = (instructionlist[index + i].optypesgp & otMask) != 0;
796
        }
797
        else { // vector register
798
            otFits = ((instructionlist[index + i].optypesscalar | instructionlist[index + i].optypesvector) & otMask) != 0;
799
        }
800
        if (fInstr->category >= 3) {
801
            // Multi format or jump instruction. Check if format allowed
802
            formatFits = (instructionlist[index+i].format & ((uint64_t)1 << fInstr->formatIndex)) != 0;
803
        }
804
        if (instructionlist[index+i].opimmediate == OPI_IMPLICIT) {
805
            // check if implicit operand fits
806
            const uint8_t * bb = pInstr->b;
807
            uint32_t x = 0; // get value of immediate operand
808
            switch (fInstr->immSize) {
809
            case 1:   // 8 bits
810
                x = *(int8_t*)(bb + fInstr->immPos);
811
                break;
812
            case 2:    // 16 bits
813
                x = *(int16_t*)(bb + fInstr->immPos);
814
                break;
815
            case 4: default:  // 32 bits
816
                x = *(int32_t*)(bb + fInstr->immPos);
817
                break;
818
            }
819
            if (instructionlist[index+i].implicit_imm != x) formatFits = false;
820
        }
821
        if (otFits && formatFits) {
822
            index += i;          // match found
823
            break;
824
        }
825
    }
826
    if (!otFits) {
827
        writeWarning("No instruction fits the operand type");
828
    }
829
    else if (!formatFits) {
830
        writeWarning("Error in instruction format");
831
    }
832
    // Save pointer to record
833
    iRecord = &instructionlist[index];
834
 
835
    // Template C or D has no OT field. Get operand type from instruction list if template C or D
836
    if (((iRecord->templt) & 0xFE) == 0xC) {
837
        uint32_t i, optypeSuppport = iRecord->optypesgp;
838
        if (fInstr->vect) optypeSuppport = iRecord->optypesscalar | iRecord->optypesvector;
839
        for (i = 0; i < 16; i++) {                     // Search for supported operand type
840
            if (optypeSuppport & (1 << i)) break;
841
        }
842
        operandType = i & 7;
843
    }
844
    // Get variant and options
845
    variant = iRecord->variant;
846
 
847
    // Write jump instruction or normal instruction
848
    if (fInstr->category == 4 && fInstr->jumpSize) {
849
        writeJumpInstruction();
850
    }
851
    else {
852
        writeNormalInstruction();
853
    }
854
    // Write comment    
855
    writeCodeComment();
856
 
857
    // End instruction
858
    outFile.newLine();
859
}
860
 
861
// Select a register from template
862
uint8_t getRegister(const STemplate * pInstr, int i) {
863
    // i = 5: RT, 6: RS, 7: RU, 8: RD
864
    uint8_t r = 0xFF;
865
    switch (i) {
866
    case 5: r = pInstr->a.rt;  break;
867
    case 6: r = pInstr->a.rs;  break;
868
    case 7: r = pInstr->a.ru;  break;
869
    case 8: r = pInstr->a.rd;  break;
870
    }
871
    return r;
872
}
873
 
874
uint8_t findFallback(SFormat const * fInstr, STemplate const * pInstr, int nOperands) {
875
    // Find the fallback register for an instruction code.
876
    // The return value is the register that is used for fallback
877
    // The return value is 0xFF if the fallback is zero or there is no fallback
878
    if (fInstr->tmplate != 0xA && fInstr->tmplate != 0xE) {
879
        return 0xFF;                                       // cannot have fallback
880
    }
881
 
882
    uint8_t operands[6] = {0,0,0,0,0,0};                   // Make list of operands
883
 
884
    int j = 5;
885
    if (fInstr->opAvail & 0x01) operands[j--] = 1;         // immediate operand
886
    if (fInstr->opAvail & 0x02) operands[j--] = 2;         // memory operand
887
    if (fInstr->opAvail & 0x10) operands[j--] = 5;         // register RT
888
    if (fInstr->opAvail & 0x20) operands[j--] = 6;         // register RS
889
    if (fInstr->opAvail & 0x40) operands[j--] = 7;         // register RU
890
    //if (fInstr->opAvail & 0x80) operands[j--] = 8;       // don't include register RD yet
891
    uint8_t fallback;                                      // fallback register
892
    bool fallbackSeparate = false;                         // fallback register is not first source register
893
 
894
    if (nOperands >= 3 && j < 3) {
895
        fallback = operands[3];                            // first of three source operands
896
    }
897
    else if (5-j-nOperands > 1) {                          // more than one vacant register field
898
        fallback = operands[3];                            // first of three possible source operands
899
        fallbackSeparate = true;
900
    }
901
    else if (5-j-nOperands == 1) {                         // one vacant register field used for fallback
902
        fallback = operands[j+1];
903
        fallbackSeparate = true;
904
    }
905
    else if (5-j-nOperands == 0) {                         // no vacant register field. RD not used for source operand
906
        fallback = operands[j+1];                          // first source operand
907
    }
908
    else if (fInstr->opAvail & 0x80) {                     // RD is first source operand
909
        fallback = 8;                                      // fallback is RD
910
    }
911
    else {
912
        fallback = 0xFF;
913
    }
914
    fallback = getRegister(pInstr, fallback);              // find register in specified register field
915
    if (fallback == 0x1F && fallbackSeparate) {
916
        return 0xFF;                                       // fallback is zero if register 31 is specified and not also a source register
917
    }
918
    return fallback;
919
}
920
 
921
 
922
void CDisassembler::writeNormalInstruction() {
923
    // Write operand type
924
    if (!((variant & VARIANT_D0) /*|| iRecord->sourceoperands == 0*/)) { // skip if no operand type
925
        if ((variant & VARIANT_U0) && operandType < 5 && !debugMode) outFile.put('u');   // Unsigned
926
        else if (variant & VARIANT_U3 && operandType < 5) {
927
            // Unsigned if option bit 5 is set. 
928
            // Option bit is in IM3 in E formats
929
            if (fInstr->tmplate == 0xE && (fInstr->imm2 & 2) && (pInstr->a.im3 & 0x8) && !debugMode) {
930
                outFile.put('u');
931
            }
932
        }
933
        outFile.tabulate(asmTab0);
934
        writeOperandType(operandType); outFile.put(' ');
935
    }
936
    outFile.tabulate(asmTab1);
937
 
938
    // Write destination operand
939
    if (!(variant & (VARIANT_D0 | VARIANT_D1 | VARIANT_D3))) {          // skip if no destination operands        
940
        if (variant & VARIANT_M0) {
941
            writeMemoryOperand();                          // Memory destination operand
942
        }
943
        else {
944
            if (variant & VARIANT_SPECD) writeSpecialRegister(pInstr->a.rd, variant >> VARIANT_SPECB);
945
            else if (fInstr->vect == 0 || (variant & VARIANT_R0)) writeGPRegister(pInstr->a.rd);
946
            else writeVectorRegister(pInstr->a.rd);
947
        }
948
        outFile.put(" = ");
949
    }
950
 
951
    // Write instruction name
952
    outFile.put(iRecord->name);
953
 
954
    /*  Source operands are selected according to the following algorithm:
955
    1.  Read nOp = number of operands from instruction list.
956
    2.  Select nOp operands from the following list, in order of priority:
957
        immediate, memory, RT, RS, RU, RD
958
        If one in the list is not available, go to the next
959
    3.  The selected operands are used as source operands in the reversed order
960
    */
961
    int nOperands = (int)iRecord->sourceoperands;                // Number of source operands
962
 
963
    // Make list of operands from available operands. 0=none, 1=immediate, 2=memory, 5=RT, 6=RS, 7=RU, 8=RD
964
    uint8_t opAvail = fInstr->opAvail;    // Bit index of available operands
965
                                          // opAvail bits: 1 = immediate, 2 = memory,
966
                                          // 0x10 = RT, 0x20 = RS, 0x40 = RU, 0x80 = RD 
967
    if (fInstr->category != 3) {                           // Single format instruction. Immediate operand determined by instruction table
968
        if (iRecord->opimmediate) opAvail |= 1;
969
        else opAvail &= ~1;
970
    }
971
    if (variant & VARIANT_M0) opAvail &= ~2;               // Memory operand already written as destination
972
 
973
    // (simular to emulator1.cpp:)
974
    // Make list of operands from available operands.
975
    // The operands[] array must have 6 elements to avoid overflow here,
976
    // even if some elements are later overwritten and used for other purposes
977
    uint8_t operands[6] = {0,0,0,0,0,0};                   // Make list of operands
978
 
979
    int j = 5;
980
    if (opAvail & 0x01) operands[j--] = 1;                 // immediate operand
981
    if (opAvail & 0x02) operands[j--] = 2;                 // memory operand
982
    if (opAvail & 0x10) operands[j--] = 5;                 // register RT
983
    if (opAvail & 0x20) operands[j--] = 6;                 // register RS
984
    if (opAvail & 0x40) operands[j--] = 7;                 // register RU
985
    if (opAvail & 0x80) operands[j--] = 8;                 // register RD
986
    operands[0] = 8;                                       // destination
987
 
988
    // Write source operands
989
    if (nOperands) {                                   // Skip if no source operands
990
        outFile.put("(");
991
        // Loop through operands
992
        int iop = 0;                                      // operand number
993
        for (j = 6 - nOperands; j < 6; j++, iop++) {
994
            uint8_t reg = getRegister(pInstr, operands[j]);// select register
995
            //uint8_t reg = operands[j];// select register
996
            switch (operands[j]) {
997
            case 1:  // Immediate operand
998
                writeImmediateOperand();
999
                break;
1000
            case 2:  // Memory operand
1001
                writeMemoryOperand();
1002
                break;
1003
            case 5:  // RT
1004
                if (variant & VARIANT_SPECS) writeSpecialRegister(reg, variant >> VARIANT_SPECB);
1005
                else if (fInstr->vect == 0 || (variant & VARIANT_RL) || ((uint32_t)variant & VARIANT_R123 & (1 << (VARIANT_R1B + iop)))) writeGPRegister(reg);
1006
                else writeVectorRegister(reg);
1007
                break;
1008
            case 6:  // RS
1009
            case 7:  // RU
1010
                if (variant & VARIANT_SPECS) writeSpecialRegister(reg, variant >> VARIANT_SPECB);
1011
                else if (fInstr->vect == 0 || ((uint32_t)variant & VARIANT_R123 & (1 << (VARIANT_R1B + iop)))) writeGPRegister(reg);
1012
                else writeVectorRegister(reg);
1013
                break;
1014
            case 8:  // RD
1015
                if (variant & VARIANT_SPECS) writeSpecialRegister(reg, variant >> VARIANT_SPECB);
1016
                else if (fInstr->vect == 0 || ((uint32_t)variant & VARIANT_R123 & (1 << (VARIANT_R1B + iop))) || (variant & VARIANT_D3R0) == VARIANT_D3R0) {
1017
                    writeGPRegister(reg);
1018
                }
1019
                else writeVectorRegister(reg);
1020
                break;
1021
            }
1022
            if (operands[j] && j < 5 &&
1023
            (iRecord->opimmediate != OPI_IMPLICIT || operands[j+1] != 1)) {
1024
                outFile.put(", ");              // Comma if not the last operand
1025
            }
1026
        }
1027
        // end parameter list
1028
        outFile.put(")");    // we prefer to end the parenthesis before the mask and options
1029
 
1030
        // write mask register
1031
        if ((fInstr->tmplate == 0xA || fInstr->tmplate == 0xE) && (pInstr->a.mask != 7 || (variant & VARIANT_F1))) {
1032
            if (pInstr->a.mask != 7) {
1033
                outFile.put(", mask=");
1034
                if (fInstr->vect) writeVectorRegister(pInstr->a.mask); else writeGPRegister(pInstr->a.mask);
1035
            }
1036
            // write fallback
1037
            if (!(variant & VARIANT_F0)) {
1038
                uint8_t fb = findFallback(fInstr, pInstr, nOperands);       // find fallback register
1039
                if (fb == 0xFF) {
1040
                    outFile.put(", fallback=0");
1041
                }
1042
                else if (!(variant & VARIANT_F1) || getRegister(pInstr, operands[6-nOperands]) != fb)  {
1043
                    outFile.put(", fallback=");
1044
                    if (fInstr->vect) writeVectorRegister(fb & 0x1F); else writeGPRegister(fb & 0x1F);
1045
                }
1046
            }
1047
        }
1048
        // write options = IM3, if IM3 is used and not already written by writeImmediateOperand
1049
        if ((variant & VARIANT_On) && (fInstr->imm2 & 2)
1050
        && (fInstr->category == 3 || (iRecord->opimmediate != 0 && iRecord->opimmediate != OPI_INT886))
1051
            ) {
1052
            outFile.put(", options=");
1053
            outFile.putHex(pInstr->a.im3);
1054
        }
1055
    }
1056
}
1057
 
1058
 
1059
void CDisassembler::writeJumpInstruction(){
1060
    // Write operand type
1061
    if (!(variant & VARIANT_D0 || iRecord->sourceoperands == 1)) { // skip if no operands other than target
1062
        outFile.tabulate(asmTab0);
1063
        if ((variant & VARIANT_U0) && operandType < 5) outFile.put("u"); // unsigned
1064
        writeOperandType(operandType);
1065
    }
1066
    outFile.tabulate(asmTab1);
1067
 
1068
    // Split instruction name into arithmetic operation and jump condition
1069
    char iname[maxINameLen+1];
1070
    char * jname;
1071
    strncpy(iname, iRecord->name, maxINameLen);  iname[maxINameLen] = 0;
1072
    jname = strchr(iname, '/');
1073
    if (jname) {
1074
        *jname = 0; // end first part of name
1075
        jname++;    // point to second part of name
1076
    }
1077
    else jname = iname;
1078
 
1079
    if (iRecord->sourceoperands > 1) {
1080
        // Instruction has arithmetic operands
1081
 
1082
        if (!(variant & (VARIANT_D0 | VARIANT_D1 | VARIANT_D3))) {
1083
            // Write destination operand
1084
            writeRegister(pInstr->a.rd, operandType);
1085
            outFile.put(" = ");
1086
        }
1087
 
1088
        // Write first part of instruction name
1089
        outFile.put(iname);  outFile.put("(");
1090
 
1091
        // Write arithmetic operands
1092
        if (iRecord->sourceoperands > 2) {
1093
            if ((fInstr->opAvail & 0x30) == 0x30) {  // RS and RT
1094
                writeRegister(pInstr->a.rs, operandType); outFile.put(", ");
1095
                writeRegister(pInstr->a.rt, operandType);
1096
            }
1097
            else {
1098
                uint32_t r1 = pInstr->a.rd;                              // First source operand
1099
                if ((fInstr->opAvail & 0x21) == 0x21) r1 = pInstr->a.rs; // Two registers and an immediate operand        
1100
                writeRegister(r1, operandType);                          // Write operand
1101
                outFile.put(", ");
1102
 
1103
                // Second source operand
1104
                if (fInstr->opAvail & 2) {
1105
                    writeMemoryOperand();
1106
                    if (fInstr->opAvail & 1) {
1107
                        outFile.put(", "); writeImmediateOperand();
1108
                    }
1109
                }
1110
                else if (fInstr->opAvail & 1) {
1111
                    writeImmediateOperand();
1112
                }
1113
                else {
1114
                    writeRegister(pInstr->a.rs, operandType);
1115
                }
1116
            }
1117
        }
1118
        else {
1119
            writeRegister(pInstr->a.rs, operandType);                // the only operand is rs
1120
        }
1121
 
1122
        // End operand list
1123
        if (fInstr->opAvail & 0x80) outFile.put("), ");
1124
 
1125
    }
1126
    // Write second part of instruction name
1127
    outFile.put(jname);
1128
 
1129
    // Write jump target
1130
    outFile.put(' ');
1131
    writeJumpTarget(iInstr + fInstr->jumpPos, fInstr->jumpSize);
1132
}
1133
 
1134
void CDisassembler::writeCodeComment() {
1135
    // Write hex listing of instruction as comment after single-format or multi-format instruction
1136
    //    uint32_t i;                                     // Index to current byte
1137
    //    uint32_t fieldSize;                             // Number of bytes in field
1138
    //    const char * spacer;                          // Space between fields
1139
 
1140
    outFile.tabulate(asmTab3);                    // tabulate to comment field
1141
    if (debugMode) return;
1142
    outFile.put(commentSeparator); outFile.put(' '); // Start comment
1143
 
1144
    writeAddress();            // Write address
1145
 
1146
    if (cmd.dumpOptions & 2) { // option "-b": binary listing
1147
        outFile.putHex(pInstr->i[0], 2);
1148
        if (instrLength > 1) {
1149
            outFile.put(" "); outFile.putHex(pInstr->i[1], 2);
1150
        }
1151
        if (instrLength > 2) {
1152
            outFile.put(" "); outFile.putHex(pInstr->i[2], 2);
1153
        }
1154
        outFile.put(" | ");
1155
    }
1156
 
1157
    if (fInstr->tmplate == 0xE && instrLength > 1) {                       // format E
1158
        // Write format_template op1.op2 ot rd.rs.rt.ru mask IM2 IM3
1159
        outFile.putHex((format >> 8) & 0xF, 0); outFile.putHex(uint8_t(format), 2); outFile.put('_'); // format
1160
        outFile.putHex(uint8_t(fInstr->tmplate), 0); outFile.put(' ');
1161
        outFile.putHex(uint8_t(pInstr->a.op1), 2); outFile.put('.'); // op1.op2
1162
        if (!(fInstr->imm2 & 0x100)) {
1163
            outFile.putHex(uint8_t(pInstr->a.op2), 0); outFile.put(' ');
1164
        }
1165
        outFile.putHex(operandType, 0); outFile.put(' ');
1166
        outFile.putHex(uint8_t(pInstr->a.rd), 2);  outFile.put('.'); // registers rd,rs,rt,ru
1167
        outFile.putHex(uint8_t(pInstr->a.rs), 2);  outFile.put('.');
1168
        outFile.putHex(uint8_t(pInstr->a.rt), 2);  outFile.put('.');
1169
        outFile.putHex(uint8_t(pInstr->a.ru), 2);  outFile.put(' ');
1170
        if (pInstr->a.mask != 7) outFile.putHex(pInstr->a.mask, 0); // mask
1171
        else outFile.put('_'); // no mask
1172
        outFile.put(' ');
1173
        outFile.putHex(pInstr->s[2], 2);  outFile.put(' ');  // IM2
1174
        outFile.putHex(uint8_t(pInstr->a.im3), 2);           // IM3
1175
        if (instrLength == 3) {
1176
            outFile.put(' ');
1177
            outFile.putHex(pInstr->i[2], 2);                 // IM4
1178
        }
1179
    }
1180
    else if (fInstr->tmplate == 0xD) {
1181
        // Write format_template op1 data
1182
        outFile.putHex((format >> 8) & 0xF, 0); outFile.putHex(uint8_t(format), 2); outFile.put('_');
1183
        outFile.putHex(uint8_t(fInstr->tmplate), 0); outFile.put(' ');
1184
        outFile.putHex(uint8_t(pInstr->a.op1), 2); outFile.put(' ');
1185
        outFile.putHex(uint32_t(pInstr->d.im2 & 0xFFFFFF), 0);
1186
    }
1187
    else {
1188
        // Write format_template op1 ot rd.rs.rt mask
1189
        outFile.putHex((format >> 8) & 0xF, 0); outFile.putHex(uint8_t(format), 2); outFile.put('_');
1190
        outFile.putHex(uint8_t(fInstr->tmplate), 0); outFile.put(' ');
1191
        outFile.putHex(uint8_t(pInstr->a.op1), 2); outFile.put(' ');
1192
        if (fInstr->tmplate == 0xC) {                           // Format C has 16 bit immediate
1193
            outFile.putHex(uint8_t(pInstr->a.rd), 2); outFile.put(' ');
1194
            outFile.putHex(pInstr->s[0], 2);
1195
        }
1196
        else { // not format C
1197
            outFile.putHex(operandType, 0); outFile.put(' ');
1198
            outFile.putHex(uint8_t(pInstr->a.rd), 2); outFile.put('.');
1199
            outFile.putHex(uint8_t(pInstr->a.rs), 2);
1200
            if (fInstr->tmplate == 0xB) {                       // Format B has 8 bit immediate
1201
                outFile.put(' '); outFile.putHex(pInstr->b[0], 2);
1202
            }
1203
            else {                                             // format A or E
1204
                outFile.put('.'); outFile.putHex(uint8_t(pInstr->a.rt), 2); outFile.put(' ');
1205
                if (pInstr->a.mask != 7) outFile.putHex(pInstr->a.mask, 0);
1206
                else outFile.put('_'); // no mask            
1207
            }
1208
        }
1209
        if (instrLength > 1) {
1210
            outFile.put(' ');
1211
            if (instrLength == 2) {                       // format A2, B2, C2
1212
                outFile.putHex(pInstr->i[1], 2);
1213
            }
1214
            else if (instrLength == 3) {                       // format A3, B3
1215
                uint8_t const * bb = pInstr->b;
1216
                uint64_t q = *(uint64_t*)(bb + 4);
1217
                outFile.putHex(q, 2);
1218
            }
1219
            else { // unsupported formats longer than 1
1220
                for (uint32_t j = 1; j < instrLength; j++) {
1221
                    outFile.putHex(pInstr->i[j], 2); outFile.put(' ');
1222
                }
1223
            }
1224
        }
1225
    }
1226
    // Write relocation comment
1227
    if (relocation && !(relocations[relocation-1].r_type & 0x80000000)) { // 0x80000000 indicates no real relocation
1228
        uint32_t reltype = relocations[relocation-1].r_type;
1229
        outFile.put(". Rel: ");
1230
        const char * rtyp = "", * rsize = "";
1231
        switch ((reltype >> 16) & 0xFF) {
1232
        case R_FORW_ABS >> 16:
1233
            rtyp = "abs "; break;
1234
        case R_FORW_SELFREL >> 16:
1235
            rtyp = "ip "; break;
1236
        case R_FORW_DATAP >> 16:
1237
            rtyp = "datap "; break;
1238
        case R_FORW_THREADP >> 16:
1239
            rtyp = "threadp "; break;
1240
        case R_FORW_REFP >> 16:
1241
            rtyp = "refpt "; break;
1242
        default:
1243
            rtyp = "other "; break;
1244
        }
1245
        switch ((reltype >> 8) & 0xFF) {
1246
        case R_FORW_8 >> 8:
1247
            rsize = "8 bit"; break;
1248
        case R_FORW_16 >> 8:
1249
            rsize = "16 bit"; break;
1250
        case R_FORW_32 >> 8:
1251
            rsize = "32 bit"; break;
1252
        case R_FORW_64 >> 8:
1253
            rsize = "64 bit"; break;
1254
        case R_FORW_32LO >> 8:
1255
            rsize = "32 low bits"; break;
1256
        case R_FORW_32HI >> 8:
1257
            rsize = "32 high bits"; break;
1258
        case R_FORW_64LO >> 8:
1259
            rsize = "64 low bits"; break;
1260
        case R_FORW_64HI >> 8:
1261
            rsize = "64 high bits"; break;
1262
        }
1263
        int scale = 1 << (reltype & 0xF);
1264
        outFile.put(rtyp);
1265
        outFile.put(rsize);
1266
        if (scale > 1) {
1267
            outFile.put(" * ");
1268
            outFile.putDecimal(scale);
1269
        }
1270
    }
1271
 
1272
    // Write warnings and errors detected after we started writing instruction
1273
    if (instructionWarning) {
1274
        if (instructionWarning & 0x100) {
1275
            outFile.put(". Unsupported format for this instruction");
1276
            instructionWarning = 0; // Suppress further warnings
1277
        }
1278
        if (instructionWarning & 0x200) {
1279
            outFile.put(". Unsupported operand type for this instruction");
1280
            instructionWarning = 0; // Suppress further warnings
1281
        }
1282
        if (instructionWarning & 4)  outFile.put(". Warning: float in double size field");
1283
        if (instructionWarning & 2)  outFile.put(". Warning: unused immediate operand");
1284
        if (instructionWarning & 1)  outFile.put(". Optional");
1285
    }
1286
}
1287
 
1288
 
1289
const char * baseRegisterNames[4] = {"thread", "datap", "ip", "sp"};
1290
 
1291
 
1292
void CDisassembler::writeMemoryOperand() {
1293
    // Check if there is a memory operand
1294
    if (fInstr->mem == 0) {
1295
        writeWarning("No memory operand");
1296
        return;
1297
    }
1298
    int itemsWritten = 0;                 // items inside []
1299
    bool symbolFound = false;             // address corresponds to symbol
1300
 
1301
    // Check if there is a relocation here
1302
    relocation = 0;  // index to relocation record
1303
    if (fInstr->addrSize) {
1304
        ElfFwcReloc rel;
1305
        rel.r_offset = iInstr + fInstr->addrPos;
1306
        rel.r_section = section;
1307
        uint32_t nrel = relocations.findAll(&relocation, rel);
1308
        if (nrel) relocation++;  // add 1 to avoid zero
1309
    }
1310
    // Enclose in square bracket
1311
    outFile.put('[');
1312
    uint32_t baseP = pInstr->a.rs;       // Base pointer is RS
1313
 
1314
    if (fInstr->mem & 0x10) {   // has relocated symbol
1315
        if (relocation) {
1316
            writeRelocationTarget(iInstr + fInstr->addrPos, fInstr->addrSize);
1317
            itemsWritten++;
1318
        }
1319
        else if (isExecutable) {
1320
            // executable file has no relocation record. Find nearest symbol
1321
            ElfFwcSym needle;  // symbol address to search for
1322
            needle.st_section = 0;
1323
            needle.st_value = 0;
1324
            if (fInstr->addrSize > 1 && baseP >= 28 && baseP <= 30) {
1325
                needle.st_section = 31 - baseP; // 1: IP, 2: datap, 3: threadp
1326
 
1327
                int64_t offset = 0;
1328
                switch (fInstr->addrSize) {  // Read offset of correct size
1329
                case 2:
1330
                    offset = *(int16_t*)(sectionBuffer + iInstr + fInstr->addrPos);
1331
                    break;
1332
                case 4:
1333
                    offset = *(int32_t*)(sectionBuffer + iInstr + fInstr->addrPos);
1334
                    break;
1335
                }
1336
                switch (baseP) {
1337
                case 28: // threadp
1338
                    offset += fileHeader.e_threadp_base;
1339
                    break;
1340
 
1341
                case 29: // datap
1342
                    offset += fileHeader.e_datap_base;
1343
                    break;
1344
 
1345
                case 30: // ip, self-relative
1346
                    offset += sectionAddress + int64_t(iInstr) + instrLength * 4;
1347
                    break;
1348
                }
1349
                needle.st_value = offset;     // Symbol position
1350
                int32_t isym = symbols.findFirst(needle);
1351
                if (isym >= 0) {   // symbol found at target address
1352
                    writeSymbolName(isym);
1353
                    symbolFound = true; itemsWritten++;
1354
                }
1355
                else { // find nearest preceding symbol
1356
                    isym &= 0x7FFFFFFF;  // remove not-found bit
1357
                    if (uint32_t(isym) < symbols.numEntries()) {  // near symbol found                    
1358
                        if (isym > 0 && symbols[isym-1].st_section == needle.st_section) {
1359
                            isym--;  // use nearest preceding symbol if in same section
1360
                        }
1361
                        if (symbols[isym].st_section == needle.st_section) { // write nearest symbol
1362
                            writeSymbolName(isym);  outFile.put('+');
1363
                            outFile.putHex((uint32_t)(offset - symbols[isym].st_value), 1); // write offset relative to symbol
1364
                            symbolFound = true;  itemsWritten++;
1365
                        }
1366
                    }
1367
                }
1368
            }
1369
        }
1370
    }
1371
    if (!symbolFound) {
1372
        if (fInstr->addrSize > 1 && baseP >= 28 && !(fInstr->mem & 0x20)) {  // Special pointers used if at least 16 bit offset
1373
            if (baseP == 31 || !relocation) {  // Do not write base pointer if implicit in relocated symbol
1374
                if (itemsWritten) outFile.put('+');
1375
                outFile.put(baseRegisterNames[baseP - 28]);  itemsWritten++;
1376
            }
1377
        }
1378
        else {
1379
            if (itemsWritten) outFile.put('+');
1380
            writeGPRegister(baseP);  itemsWritten++;
1381
        }
1382
    }
1383
 
1384
    if ((fInstr->mem & 4) && pInstr->a.rt != 31) { // Has index in RT
1385
        if (fInstr->scale & 4) { // Negative index
1386
            outFile.put('-');  writeGPRegister(pInstr->a.rt);
1387
        }
1388
        else {  // Positive, scaled index
1389
            if (itemsWritten) outFile.put('+');
1390
            writeGPRegister(pInstr->a.rt);
1391
            if ((fInstr->scale & 2) && operandType > 0) { // Index is scaled
1392
                outFile.put('*');
1393
                outFile.putDecimal(dataSizeTable[operandType & 7]);
1394
            }
1395
        }
1396
        itemsWritten++;
1397
    }
1398
    if (fInstr->mem & 0x10) { // Has offset
1399
        if (relocation || symbolFound) {   // has relocated symbol
1400
            // has been written above
1401
            //writeRelocationTarget(iInstr + fInstr->addrPos, fInstr->addrSize);
1402
        }
1403
        else {
1404
            int32_t offset = 0;
1405
            switch (fInstr->addrSize) {  // Read offset of correct size
1406
            case 1:
1407
                offset = *(int8_t*)(sectionBuffer + iInstr + fInstr->addrPos);
1408
                break;
1409
            case 2:
1410
                offset = *(int16_t*)(sectionBuffer + iInstr + fInstr->addrPos);
1411
                break;
1412
            case 4:
1413
                offset = *(int32_t*)(sectionBuffer + iInstr + fInstr->addrPos);
1414
                break;
1415
            }
1416
            if (offset > 0) {    // Write positive offset
1417
                outFile.put('+');
1418
                outFile.putHex((uint32_t)offset, 1);
1419
            }
1420
            else if (offset < 0) {    // Write negative offset
1421
                outFile.put('-');
1422
                outFile.putHex((uint32_t)(-offset), 1);
1423
            }
1424
            if ((fInstr->scale & 1) && offset != 0) { // Offset is scaled
1425
                outFile.put('*');
1426
                outFile.putDecimal(dataSizeTable[operandType & 7]);
1427
            }
1428
            itemsWritten++;
1429
        }
1430
    }
1431
    if (fInstr->mem & 0x20) {  // Has limit
1432
        outFile.put(", limit=");
1433
        if (fInstr->addrSize == 4) {   // 32 bit limit
1434
            outFile.putHex(*(uint32_t*)(sectionBuffer + iInstr + fInstr->addrPos));
1435
        }
1436
        else {                       // 16 bit limit
1437
            outFile.putHex(*(uint16_t*)(sectionBuffer + iInstr + fInstr->addrPos));
1438
        }
1439
    }
1440
    if ((fInstr->vect & 2) && pInstr->a.rt != 31) {  // Has vector length
1441
        outFile.put(", length=");
1442
        writeGPRegister(pInstr->a.rt);
1443
    }
1444
    else if ((fInstr->vect & 4) && pInstr->a.rt != 31) {  // Has broadcast
1445
        outFile.put(", broadcast=");
1446
        writeGPRegister(pInstr->a.rt);
1447
    }
1448
    else if (fInstr->vect & 7 || ((fInstr->vect & 0x10) && (pInstr->a.ot & 4))) {  //  Scalar
1449
        outFile.put(", scalar");
1450
    }
1451
 
1452
    outFile.put(']');  // End square bracket
1453
}
1454
 
1455
 
1456
void CDisassembler::writeImmediateOperand() {
1457
    // Write immediate operand depending on type in instruction list
1458
    // Check if there is a relocation here
1459
    ElfFwcReloc rel;
1460
    rel.r_offset = (uint64_t)iInstr + fInstr->immPos;
1461
    rel.r_section = section;
1462
    uint32_t irel;  // index to relocation record
1463
    uint32_t numRel = relocations.findAll(&irel, rel);
1464
    if (numRel) {  // Immediate value is relocated
1465
        writeRelocationTarget(iInstr + fInstr->immPos, fInstr->immSize);
1466
        return;
1467
    }
1468
    // Value is not relocated
1469
 
1470
    /*if ((variant & VARIANT_M1) && (fInstr->tmplate) == 0xE && (fInstr->opAvail & 2)) {
1471
        // VARIANT_M1: immediate operand is in IM3
1472
        outFile.putDecimal(pInstr->a.im3);
1473
        return;
1474
    } */
1475
    const uint8_t * bb = pInstr->b;  // use this for avoiding pedantic warnings from Gnu compiler when type casting
1476
    if (operandType == 1 && (variant & VARIANT_H0)) operandType = 8;  // half precision float
1477
    if (operandType < 5 || iRecord->opimmediate || (variant & VARIANT_I2)) {
1478
        // integer, or type specified in instruction list
1479
        // Get value of right size
1480
        int64_t x = 0;
1481
        switch (fInstr->immSize) {
1482
        case 1:   // 8 bits
1483
            x = *(int8_t*)(bb + fInstr->immPos);
1484
            break;
1485
        case 2:    // 16 bits
1486
            x = *(int16_t*)(bb + fInstr->immPos);
1487
            break;
1488
        case 3:   // 24 bits, sign extend to 32 bits
1489
            x = *(int32_t*)(bb + fInstr->immPos) << 8 >> 8;
1490
            break;
1491
        case 4:   // 32 bits
1492
            x = *(int32_t*)(bb + fInstr->immPos);
1493
            break;
1494
        case 8:
1495
            x = *(int64_t*)(bb + fInstr->immPos);
1496
            break;
1497
        case 0:
1498
            if (fInstr->tmplate == 0xE) {
1499
                x = (pInstr->s[2]);
1500
            }
1501
            break;
1502
            // else continue in default:
1503
        default:
1504
            writeError("Unknown immediate size");
1505
        }
1506
        // Write in the form specified in instruction list
1507
        switch (iRecord->opimmediate) {
1508
        case 0:   // No form specified
1509
        case OPI_OT:  // same as operand type
1510
            if (fInstr->category == 1 && iRecord->opimmediate == 0 && x != 0) instructionWarning |= 2; // Immediate field not used in this instruction. Write nothing
1511
            switch (fInstr->immSize) {  // Output as hexadecimal
1512
            case 1:
1513
                if (operandType > 0) outFile.putDecimal((int32_t)x, 1);  // sign extend to larger size
1514
                else outFile.putHex(uint8_t(x), 1);
1515
                break;
1516
            case 2:
1517
                if ((fInstr->imm2 & 4) && pInstr->a.im3 && !(variant & VARIANT_On)) {  // constant is IM2 << IM3
1518
                    if ((int16_t)x < 0) {
1519
                        outFile.put('-');  x = -x;
1520
                    }
1521
                    outFile.putHex(uint16_t(x), 1);
1522
                    outFile.put(" << ");
1523
                    outFile.putDecimal(pInstr->a.im3);
1524
                }
1525
                else if (operandType > 1) {
1526
                    outFile.putDecimal((int32_t)x, 1);  // sign extend to larger size
1527
                }
1528
                else {
1529
                    outFile.putHex(uint16_t(x), 1);
1530
                }
1531
                break;
1532
            default:
1533
            case 4:
1534
                if ((fInstr->imm2 & 8) && pInstr->a.im2) {  // constant is IM4 << IM2
1535
                    if ((int32_t)x < 0) {
1536
                        outFile.put('-');  x = -x;
1537
                    }
1538
                    outFile.putHex(uint32_t(x), 1);
1539
                    outFile.put(" << ");
1540
                    outFile.putDecimal(pInstr->a.im2);
1541
                }
1542
                else if (operandType <= 2) outFile.putHex(uint32_t(x), 1);
1543
                else if (operandType == 5 || operandType == 6) {
1544
                    outFile.putFloat(*(float*)(bb + fInstr->immPos));
1545
                }
1546
                else {
1547
                    outFile.putDecimal((int32_t)x, 1);  // sign extend to larger size
1548
                }
1549
                break;
1550
            case 8:
1551
                if (operandType == 6) outFile.putFloat(*(double*)(bb + fInstr->immPos));
1552
                else outFile.putHex(uint64_t(x), 1);
1553
                break;
1554
            }
1555
            break;
1556
        case OPI_INT8:
1557
            outFile.putDecimal(int8_t(x), 1);
1558
            break;
1559
        case OPI_INT16:
1560
            outFile.putDecimal(int16_t(x), 1);
1561
            break;
1562
        case OPI_INT32:
1563
            outFile.putDecimal(int32_t(x), 1);
1564
            break;
1565
        case OPI_INT8SH:
1566
            if (int8_t(x >> 8) < 0) {
1567
                outFile.put('-');
1568
                outFile.putHex(uint8_t(-int8_t(x >> 8)), 1);
1569
            }
1570
            else outFile.putHex(uint8_t(x >> 8), 1);
1571
            outFile.put(" << ");
1572
            outFile.putDecimal(uint8_t(x));
1573
            break;
1574
        case OPI_INT16SH16:
1575
            if (x < 0) {
1576
                outFile.put('-');
1577
                x = -x;
1578
            }
1579
            outFile.putHex(uint16_t(x), 1);
1580
            outFile.put(" << 16");
1581
            break;
1582
        case OPI_INT32SH32:
1583
            outFile.putHex(uint32_t(x), 1);
1584
            outFile.put(" << 32");
1585
            break;
1586
        case OPI_UINT8:
1587
            outFile.putHex(uint8_t(x), 1);
1588
            break;
1589
        case OPI_UINT16:
1590
            outFile.putHex(uint16_t(x), 1);
1591
            break;
1592
        case OPI_UINT32:
1593
            outFile.putHex(uint32_t(x), 1);
1594
            break;
1595
        case OPI_INT64: case OPI_UINT64:
1596
            outFile.putHex(uint64_t(x), 1);
1597
            break;
1598
        case OPI_2INT8:                     // Two unsigned integers
1599
            outFile.putHex(uint8_t(x), 1);  outFile.put(", ");
1600
            outFile.putHex(uint8_t(x >> 8), 1);
1601
            break;
1602
        case OPI_INT886:                     // Three unsigned integers, including IM3
1603
            outFile.putDecimal(uint8_t(x));  outFile.put(", ");
1604
            outFile.putDecimal(uint8_t(x >> 8));  outFile.put(", ");
1605
            outFile.putDecimal(uint8_t(pInstr->a.im3));
1606
            break;
1607
        case OPI_2INT16:                     // Two 16-bit unsigned integers
1608
            outFile.putHex(uint16_t(x >> 16), 1);  outFile.put(", ");
1609
            outFile.putHex(uint16_t(x), 1);
1610
            break;
1611
        case OPI_INT1632:                     // One 16-bit and one 32-bit unsigned integer
1612
            outFile.putHex(uint32_t(pInstr->i[1]), 1);  outFile.put(", ");
1613
            outFile.putHex(uint16_t(x), 1);
1614
            break;
1615
        case OPI_2INT32:                     // Two 32-bit unsigned integer
1616
            outFile.putHex(uint32_t(x >> 32), 1);  outFile.put(", ");
1617
            outFile.putHex(uint32_t(x), 1);
1618
            break;
1619
        case OPI_INT1688:                     // 16 + 8 + 8 bits
1620
            outFile.putHex(uint16_t(x), 1);  outFile.put(", ");
1621
            outFile.putHex(uint8_t(x >> 16), 1);  outFile.put(", ");
1622
            outFile.putHex(uint8_t(x >> 24), 1);
1623
            break;
1624
        case OPI_FLOAT16:                     // Half precision float
1625
            outFile.putFloat(half2float(uint16_t(x)));
1626
            break;
1627
        case OPI_IMPLICIT:
1628
            if (x != iRecord->implicit_imm) { // Does not match implicit value. Make value explicit
1629
                if (iRecord->sourceoperands > 1) outFile.put(", ");
1630
                outFile.putHex(uint8_t(x), 1);
1631
            }
1632
            break;
1633
        default:
1634
            writeWarning("Unknown immediate operand type");
1635
        }
1636
    }
1637
    else {  // floating point
1638
        uint32_t immSize = fInstr->immSize;      // Size of immediate field
1639
        if (immSize == 8 && operandType == 5)  {
1640
            immSize = 4;  instructionWarning |= 4;  // float in double size field
1641
        }
1642
        switch (immSize) {
1643
        case 1:    // 8 bits. float as integer
1644
            outFile.putFloat((float)*(int8_t*)(bb + fInstr->immPos));
1645
            break;
1646
        case 2:  { // 16 bits
1647
            uint16_t x = *(uint16_t*)(bb + fInstr->immPos);
1648
            outFile.putFloat(half2float(x));
1649
            break;}
1650
        case 4:  { // float
1651
            float x = *(float*)(bb + fInstr->immPos);
1652
            outFile.putFloat(x);
1653
            break;}
1654
        case 8:  { // double
1655
            double x = *(double*)(bb + fInstr->immPos);
1656
            outFile.putFloat(x);
1657
            break;}
1658
        default:
1659
            writeError("unknown size for float operand");
1660
        }
1661
    }
1662
}
1663
 
1664
 
1665
void CDisassembler::writeRegister(uint32_t r, uint32_t ot) {
1666
    if (r == 31 && !(ot & 4)) outFile.put("sp");
1667
    else {
1668
        outFile.put(ot & 4 ? "v" : "r");  outFile.putDecimal(r);
1669
    }
1670
}
1671
 
1672
 
1673
void CDisassembler::writeGPRegister(uint32_t r) {
1674
    // Write name of general purpose register
1675
    if (r == 31) outFile.put("sp");
1676
    else {
1677
        outFile.put("r");  outFile.putDecimal(r);
1678
    }
1679
}
1680
 
1681
 
1682
void CDisassembler::writeVectorRegister(uint32_t v) {
1683
    // Write name of vector register
1684
    outFile.put("v");  outFile.putDecimal(v);
1685
}
1686
 
1687
// Special register types according to Xn and Yn in 'variant' field in instruction list
1688
static const char * specialRegNamesPrefix[8] = {"?", "spec", "capab", "perf", "sys", "?", "?", "?"};
1689
static const char * pointerRegNames[4] = {"threadp", "datap", "ip", "sp"};
1690
static const char * specialRegNames[] = {"numcontr", "threadp", "datap", "?", "?", "?"};
1691
void CDisassembler::writeSpecialRegister(uint32_t r, uint32_t type) {
1692
    // Write name of other type of register
1693
    if ((type & 0xF) == 0) {
1694
        // May be special pointer
1695
        if (r < 28) {
1696
            writeGPRegister(r);
1697
        }
1698
        else {
1699
            outFile.put(pointerRegNames[(r-28) & 3]);
1700
        }
1701
    }
1702
    else if ((type & 0xF) == 1 && r <= 2) {
1703
        // special registers with unique names
1704
        outFile.put(specialRegNames[r]);
1705
    }
1706
    else {
1707
        outFile.put(specialRegNamesPrefix[type & 7]);
1708
        outFile.putDecimal(r);
1709
    }
1710
}
1711
 
1712
 
1713
// Write name of operand type
1714
static const char * operandTypeNames[8] = {
1715
    "int8", "int16", "int32", "int64", "int128", "float", "double", "float128 "};
1716
 
1717
void CDisassembler::writeOperandType(uint32_t ot) {
1718
    if ((variant & VARIANT_H0) && ot == 1) outFile.put("float16");
1719
    else outFile.put(operandTypeNames[ot & 7]);
1720
}
1721
 
1722
 
1723
void CDisassembler::writeWarning(const char * w) {
1724
    // Write warning to output file
1725
    outFile.put(commentSeparator);
1726
    outFile.put(" Warning: ");
1727
    outFile.put(w);
1728
    outFile.newLine();
1729
}
1730
 
1731
 
1732
void CDisassembler::writeError(const char * w) {
1733
    // Write warning to output file
1734
    outFile.put(commentSeparator);
1735
    outFile.put(" Error: ");
1736
    outFile.put(w);
1737
    outFile.newLine();
1738
}
1739
 
1740
 
1741
void CDisassembler::finalErrorCheck() {
1742
    // Check for illegal entries in symbol table and relocations table
1743
    // Check for orphaned symbols
1744
    uint32_t i;                                  // Loop counter
1745
    uint32_t linesWritten = 0;                   // Count lines written
1746
    // Check for orphaned symbols
1747
    for (i = 0; i < symbols.numEntries(); i++) {
1748
        if ((symbols[i].st_other & 0x80000000) == 0
1749
            && (symbols[i].st_section || symbols[i].st_value)
1750
            && symbols[i].st_type != STT_CONSTANT
1751
            && symbols[i].st_type != STT_FILE) {
1752
            // This symbol has not been written out
1753
            if (linesWritten == 0) {
1754
                // First orphaned symbol. Write text            
1755
                outFile.newLine();  outFile.newLine();  outFile.put(commentSeparator);
1756
                outFile.put(" Warning: Symbols outside address range:");
1757
                outFile.newLine();
1758
            }
1759
            outFile.put(commentSeparator); outFile.put(' ');
1760
            writeSymbolName(i); outFile.put(" = ");
1761
            outFile.putHex(symbols[i].st_section, 0); outFile.put(':'); outFile.putHex(symbols[i].st_value, 0);
1762
            outFile.newLine();  linesWritten++;
1763
        }
1764
    }
1765
    // Check for orphaned relocations
1766
    linesWritten = 0;
1767
    for (i = 0; i < relocations.numEntries(); i++) {
1768
        if (relocations[i].r_type == 0) continue;  // ignore empty relocation 0        
1769
        if ((relocations[i].r_refsym & 0x80000000) == 0) {
1770
            // This relocation has not been used
1771
            if (linesWritten == 0) {
1772
                // First orphaned symbol. Write text            
1773
                outFile.newLine();  outFile.newLine();  outFile.put(commentSeparator);
1774
                outFile.put(" Warning: Unused or misplaced relocations:");
1775
                outFile.newLine();
1776
            }
1777
            outFile.put(commentSeparator); outFile.put(" at ");
1778
            outFile.putHex(uint32_t(relocations[i].r_section)); outFile.put(':');  // Section
1779
            outFile.putHex(uint32_t(relocations[i].r_offset));                     // Offset
1780
            outFile.put(" to symbol ");
1781
            writeSymbolName(relocations[i].r_sym & 0x7FFFFFFF);
1782
            outFile.newLine();  linesWritten++;
1783
        }
1784
    }
1785
}
1786
 
1787
void CDisassembler::writeAddress() {
1788
    // write code address >> 2. Subtract ip_base to put code section at address 0
1789
    uint64_t address = (iInstr + sectionAddress - fileHeader.e_ip_base) >> 2;
1790
 
1791
    if (fileHeader.e_ip_base + sectionEnd + sectionAddress > 0xFFFF * 4) {
1792
        // Write 32 bit address
1793
        outFile.putHex(uint32_t(address), 2);
1794
    }
1795
    else {
1796
        // Write 16 bit address
1797
        outFile.putHex(uint16_t(address), 2);
1798
    }
1799
    if (debugMode) outFile.put(" ");
1800
    else outFile.put(" _ ");    // Space after address
1801
}
1802
 
1803
void CDisassembler::setTabStops() {
1804
    // set tab stops for output
1805
    if (debugMode) {
1806
        asmTab0 = 18;                        // Column for operand type
1807
        asmTab1 = 26;                        // Column for opcode
1808
        asmTab2 = 40;                        // Column for first operand
1809
        asmTab3 = 64;                        // Column for destination value
1810
    }
1811
    else {
1812
        asmTab0 =  0;                        // unused
1813
        asmTab1 =  8;                        // Column for opcode
1814
        asmTab2 = 16;                        // Column for first operand
1815
        asmTab3 = 56;                        // Column for comment
1816
    }
1817
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.