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

Subversion Repositories forwardcom

[/] [forwardcom/] [bintools/] [assem6.cpp] - Blame information for rev 124

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 46 Agner
/****************************    assem6.cpp    ********************************
2
* Author:        Agner Fog
3
* Date created:  2017-08-07
4
* Last modified: 2021-02-23
5
* Version:       1.11
6
* Project:       Binary tools for ForwardCom instruction set
7
* Module:        assem.cpp
8
* Description:
9
* Module for assembling ForwardCom .as files.
10
* This module contains:
11
* - pass4(): Resolve internal cross references, optimize forward references
12
* - pass5(): Make binary file
13
* Copyright 2017-2021 GNU General Public License http://www.gnu.org/licenses
14
******************************************************************************/
15
#include "stdafx.h"
16
 
17
 
18
// Resolve symbol addresses and internal cross references, optimize forward references
19
void CAssembler::pass4() {
20
    uint32_t addr = 0;                 // address relative to current section begin
21
    //uint32_t instructId;               // instruction id
22
    uint32_t i;                        // loop counter
23
    uint32_t symi;                     // symbol index
24
    uint32_t numUncertain;             // number of instructions with unresolved size in current section
25
    uint32_t totUncertain;             // number of instructions with unresolved size in all sections
26
    uint32_t changes = 1;              // number of size changes during each optimization pass
27
    uint32_t optiPass = 0;             // count optimization passes
28
    uint32_t nSections = sectionHeaders.numEntries(); // number of sections
29
    uint32_t const maxOptiPass = 10;   // maximum number of optimization passes
30
 
31
    // multiple optimization passes until size is certain or no changes
32
    for (optiPass = 1; optiPass <= maxOptiPass; optiPass++) {
33
        code_size = cmd.codeSizeOption;    // initialize options in case they have been changed during pass 3 or 4
34
        data_size = cmd.dataSizeOption;
35
 
36
        if (changes == 0 && (totUncertain == 0 || optiPass > 2)) break;
37
        changes = 0;                   // count instructions with changed size
38
        section = 0;
39
        numUncertain = totUncertain = 0;
40
        for (i = 1; i < nSections; i++) {
41
            sectionHeaders[i].sh_link = 0;  // reset count of uncertain instruction sizes
42
            sectionHeaders[i].sh_size = 0;
43
        }
44
        // loop through code objects
45
        for (i = 0; i < codeBuffer.numEntries(); i++) {
46
            //instructId = codeBuffer[i].instr1;
47
            if (codeBuffer[i].section == 0 || codeBuffer[i].section >= nSections)
48
                continue;
49
            if (codeBuffer[i].section != section) {
50
                if (section) {
51
                    // save results of previous section
52
                    sectionHeaders[section].sh_size = addr;
53
                    sectionHeaders[section].sh_link = numUncertain;  // sh_link is temporarily used for indicating number of instructions with uncertain size                
54
                    totUncertain += numUncertain;
55
                }
56
                // restore status for current section
57
                section = codeBuffer[i].section;
58
                addr = (uint32_t)sectionHeaders[section].sh_size;
59
                numUncertain = sectionHeaders[section].sh_link;
60
            }
61
            codeBuffer[i].address = addr;
62
            if (codeBuffer[i].label) {
63
                // there is a label here. put the address into the symbol record
64
                symi = findSymbol(codeBuffer[i].label);
65
                if (symi > 0 && symi < symbols.numEntries()) {
66
                    // the upper half of st_value is temporarily used for indicating if address is not yet precise
67
                    symbols[symi].st_value = addr | (uint64_t)numUncertain << 32;
68
                    symbols[symi].st_unitsize = 1;     // set an arbitrary size to indicate that a value has been assigned
69
                }
70
            }
71
            if (codeBuffer[i].sizeUnknown) {
72
                // update the size of this instruction
73
                uint8_t lastSize = codeBuffer[i].size;
74
                if (codeBuffer[i].instr1) {  // update normal instruction
75
                    if (optiPass >= maxOptiPass - 1) {
76
                        // rare case. optimization has slow convergence. choose larger instruction size if uncertain
77
                        if (codeBuffer[i].fitAddr) codeBuffer[i].fitAddr |= IFIT_LARGE;
78
                        if (codeBuffer[i].fitJump) codeBuffer[i].fitJump |= IFIT_LARGE;
79
                    }
80
                    sectionHeaders[section].sh_link = numUncertain;
81
                    fitConstant(codeBuffer[i]);                     // recalculate necessary size of immediate constant
82
                    fitAddress(codeBuffer[i]);                      // recalculate necessary size of address
83
                    fitCode(codeBuffer[i]);                         // fit instruction to new size
84
                    if (codeBuffer[i].size != lastSize) changes++;  // count changes if size changed
85
                }
86
                else {  // not an instruction
87
                    if (codeBuffer[i].instruction == II_ALIGN) {
88
                        // align directive. round up address to nearest multiple of alignment value
89
                        uint32_t ali = bitScanReverse(codeBuffer[i].value.u);
90
                        uint32_t newAddress = (addr + ali - 1) & uint32_t(-(int32_t)ali);
91
                        codeBuffer[i].size = (newAddress - addr) >> 2;    // size of alignment fillers
92
                        if (codeBuffer[i].size != lastSize) changes++;    // count changes if size changed
93
                        if (numUncertain) numUncertain += (ali >> 2) - 1 - codeBuffer[i].size; // maximum additional size if size of previous instructions change
94
                        if (section && sectionHeaders[section].sh_align < ali) {
95
                            sectionHeaders[section].sh_align = ali; // adjust alignment of this section
96
                        }
97
                    }
98
                    else if (codeBuffer[i].instruction == II_OPTIONS) {
99
                        // options directive. change option
100
                        // This code object was created by CAssembler::interpretOptionsLine()
101
                        switch (codeBuffer[i].fitNum) {
102
                        case 1:
103
                            code_size = codeBuffer[i].value.u;
104
                            break;
105
                        case 2:
106
                            data_size = codeBuffer[i].value.u;
107
                            break;
108
                        }
109
                    }
110
                }
111
            }
112
            addr += codeBuffer[i].size * 4;  // update address
113
            numUncertain += codeBuffer[i].sizeUnknown & 0x7F;  // update uncertainty
114
        }
115
        // update last section
116
        if (section) {
117
            // save results of previous section
118
            sectionHeaders[section].sh_size = addr;
119
            sectionHeaders[section].sh_link = numUncertain;
120
            totUncertain += numUncertain;
121
        }
122
    }
123
    // remove temporary uncertainty information from symbol records
124
    for (symi = 1; symi < symbols.numEntries(); symi++) {
125
        if (symbols[symi].st_type == STT_OBJECT || symbols[symi].st_type == STT_FUNC) {
126
            symbols[symi].st_value &= 0xFFFFFFFFU;
127
        }
128
    }
129
 
130
    // make public symbol definitions
131
    for (linei = 1; linei < lines.numEntries(); linei++) {
132
        if (lines[linei].type == LINE_PUBLICDEF) {
133
            interpretPublicDirective();
134
        }
135
    }
136
}
137
 
138
 
139
// interpret public name: options {, name: options}
140
void CAssembler::interpretPublicDirective() {
141
    int state = 0;           // 0: start
142
                             // 1: after 'public' or ','
143
                             // 2: after name
144
                             // 3: after ':'
145
                             // 4: after attribute
146
 
147
    uint32_t symi = 0;       // symbol index
148
    uint32_t symn;           // symbol name index
149
    uint32_t tok;            // token index
150
    uint32_t symtok = 0;     // symbol token
151
    SToken token;            // current token
152
 
153
    tokenB = lines[linei].firstToken;      // first token in line        
154
    tokenN = lines[linei].numTokens;       // number of tokens in line 
155
    // loop through tokens on this line
156
    for (tok = tokenB; tok < tokenB + tokenN; tok++) {
157
        token = tokens[tok];
158
        switch (state) {
159
        case 0:  // start
160
            if (token.id == DIR_PUBLIC) state = 1; else return;
161
            break;
162
        case 1:  // expect symbol name
163
            if (token.type == TOK_SYM) {
164
                symtok = tok;
165
                symn = token.id;
166
                symi = findSymbol(symn);
167
                if ((int32_t)symi < 1) {
168
                    errors.report(token.pos, token.stringLength, ERR_SYMBOL_UNDEFINED);  return;
169
                }
170
                state = 2;
171
            }
172
            else if (token.type == TOK_NAM) {
173
                // name found. find symbol
174
                symi = findSymbol((char*)buf() + tokens[tok].pos, tokens[tok].stringLength);
175
                if ((int32_t)symi < 1) {
176
                    errors.report(token.pos, token.stringLength, ERR_SYMBOL_UNDEFINED);  return;
177
                }
178
                symtok = tok;
179
                symn = symbols[symi].st_name;
180
                state = 2;
181
            }
182
            else errors.report(token);
183
            break;
184
        case 2:  // after name. expect ':' or ','
185
            if (token.type == TOK_OPR && token.id == ':') state = 3;
186
            else if (token.type == TOK_OPR && token.id == ',') {
187
            EXPORT_SYMBOL:
188
                // check if external
189
                if (symbols[symi].st_section == 0) {
190
                    errors.report(tokens[symtok].pos, tokens[symtok].stringLength, ERR_CANNOT_EXPORT);
191
                    state = 1;
192
                    continue;
193
                }
194
                // check symbol type
195
                switch (symbols[symi].st_type) {
196
                case STT_NOTYPE:  // type missing. set type
197
                    symbols[symi].st_type = (symbols[symi].st_other & STV_EXEC) ? STT_FUNC : STT_OBJECT;
198
                    break;
199
                case STT_OBJECT:
200
                case STT_FUNC:
201
                    break;  // ok
202
                case STT_CONSTANT:
203
                    if (sectionHeaders.numEntries() == 0) {
204
                        // file must have at least one section because constant needs a section idex
205
                        err.submit(ERR_ELF_NO_SECTIONS);
206
                    }
207
                    break;  // ok
208
                case STT_VARIABLE:  // meta-variable has been assigned multiple values
209
                    errors.report(tokens[symtok].pos, tokens[symtok].stringLength, ERR_SYMBOL_REDEFINED);
210
                    state = 1;
211
                    continue;
212
                case STT_EXPRESSION:  // cannot export expression
213
                    errors.report(tokens[symtok].pos, tokens[symtok].stringLength, ERR_EXPORT_EXPRESSION);
214
                    state = 1;
215
                    continue;
216
                default:
217
                    errors.report(tokens[symtok].pos, tokens[symtok].stringLength, ERR_CANNOT_EXPORT);
218
                    state = 1;
219
                    continue;
220
                }
221
                // make symbol global or weak
222
                if (symbols[symi].st_bind != STB_WEAK) symbols[symi].st_bind = STB_GLOBAL;
223
                state = 1;
224
            }
225
            else {
226
                errors.report(token);  return;
227
            }
228
            break;
229
        case 3:  // after ':'. expect attribute
230
            SET_ATTRIBUTE:
231
            if (token.id == ATT_WEAK) {
232
                symbols[symi].st_bind = STB_WEAK;
233
            }
234
            else if (token.id == ATT_CONSTANT && symbols[symi].st_type != STT_OBJECT && symbols[symi].st_type != STT_FUNC) {
235
                symbols[symi].st_type = STT_CONSTANT;
236
            }
237
            else if (token.id == DIR_FUNCTION) {
238
                symbols[symi].st_type = STT_FUNC;
239
            }
240
            else if (token.id == REG_IP) {
241
                symbols[symi].st_other = (symbols[symi].st_other & ~ (SHF_DATAP | SHF_THREADP)) | STV_IP;
242
            }
243
            else if (token.id == REG_DATAP) {
244
                symbols[symi].st_other = (symbols[symi].st_other & ~ (STV_IP | SHF_THREADP)) | SHF_DATAP;
245
            }
246
            else if (token.id == REG_THREADP) {
247
                symbols[symi].st_other = (symbols[symi].st_other & ~ (STV_IP | SHF_DATAP)) | SHF_THREADP;
248
            }
249
            else if (token.id == ATT_REGUSE) {
250
                if (tokens[tok + 1].id == '=' && tokens[tok + 2].type == TOK_NUM) {
251
                    tok += 2;
252
                    symbols[symi].st_reguse1 = expression(tok, 1, 0).value.w;
253
                    symbols[symi].st_other |= STV_REGUSE;
254
                    if (tokens[tok + 1].id == ',' && tokens[tok + 2].type == TOK_NUM) {
255
                        tok += 2;
256
                        symbols[symi].st_reguse2 = expression(tok, 1, 0).value.w;
257
                    }
258
                }
259
            }
260
            else errors.report(token);
261
            state = 4;
262
            break;
263
        case 4:  // after attribute. expect ',' or more attributes
264
            if (token.type == TOK_OPR && token.id == ',') {
265
                uint32_t typ2 = tokens[tok+1].type;
266
                if (typ2 == TOK_ATT || typ2 == TOK_DIR || typ2 == TOK_REG) break;
267
                else goto EXPORT_SYMBOL;
268
            }
269
            if (token.type == TOK_ATT || token.type == TOK_DIR || token.type == TOK_REG)
270
                goto SET_ATTRIBUTE;
271
            errors.report(token);
272
            return;
273
        }
274
    }
275
    if (state > 1) goto EXPORT_SYMBOL;  // unfinished symbol
276
}
277
 
278
 
279
// Make binary file
280
void CAssembler::pass5() {
281
 
282
    // make a databuffer for each section
283
    uint32_t nSections = sectionHeaders.numEntries();
284
    dataBuffers.setSize(nSections);
285
    section = 0;
286
 
287
    // make binary code from code records
288
    makeBinaryCode();
289
 
290
    // make binary data for data sections
291
    makeBinaryData();
292
 
293
    // make sections
294
    copySections();
295
 
296
    // copy symbols
297
    copySymbols();
298
 
299
    // copy relocations
300
    makeBinaryRelocations();
301
 
302
    // make output list file
303
    if (cmd.outputListFile) makeListFile();
304
 
305
    // remove local and external symbols if there is no relocation reference to them, 
306
    // and adjust relocation records with new symbol indexes, after making list file.
307
    // Preserve local symbols if debugOptions > 0
308
    outFile.removePrivateSymbols(cmd.debugOptions);
309
 
310
    // write assembly output file
311
    outFile.join(0);                             // make ELF file from sections, etc.
312
}
313
 
314
// copy sections to outFile
315
void CAssembler::copySections() {
316
    for (uint32_t i = 1; i < sectionHeaders.numEntries(); i++) {
317
        if (dataBuffers[i].dataSize() > sectionHeaders[i].sh_size) {  // dataSize() is zero for uninitialized data sections
318
            sectionHeaders[i].sh_size = dataBuffers[i].dataSize();    // this should never be necessary
319
        }
320
        sectionHeaders[i].sh_link = 0;  // remove temporary information used during optimization passes
321
        outFile.addSection(sectionHeaders[i], symbolNameBuffer, dataBuffers[i]);
322
    }
323
}
324
 
325
// copy symbols to outFile
326
void CAssembler::copySymbols() {
327
    for (uint32_t i = 0; i < symbols.numEntries(); i++) {
328
        // exclude section symbols and local constants
329
        if (symbols[i].st_type != STT_SECTION && symbols[i].st_type < STT_VARIABLE) {
330
            // check if symbol is in a communal section
331
            uint32_t sect = symbols[i].st_section;
332
            if (sect && sect < sectionHeaders.numEntries() && sectionHeaders[sect].sh_type == SHT_COMDAT && symbols[i].st_bind == STB_GLOBAL) {
333
                // public symbol in communal section must be weak
334
                symbols[i].st_bind = STB_WEAK;
335
            }
336
            uint32_t newSymi = outFile.addSymbol(symbols[i], symbolNameBuffer);
337
            // save new symbol index for use in relocation records
338
            symbols[i].st_unitnum = newSymi;
339
        }
340
    }
341
}
342
 
343
// make binary data for code sections
344
void CAssembler::makeBinaryCode() {
345
    uint32_t i;                // loop counter
346
    STemplate instr;           // instruction template
347
    uint32_t format;           // format 
348
    uint32_t templ;            // format template
349
    uint32_t instructId;       // instruction as index into instructionlistId
350
    SFormat const * formatp = 0; // record in formatList
351
    uint32_t nSections = sectionHeaders.numEntries();
352
 
353
    // loop through code objects
354
    for (i = 0; i < codeBuffer.numEntries(); i++) {
355
        instructId = codeBuffer[i].instr1;
356
        if (instructId == 0) {
357
            // not an instruction. possibly label or directive
358
            if (codeBuffer[i].instruction == II_ALIGN && section) {
359
                // alignment directive. size has been calculated in pass 4
360
                int32_t asize = codeBuffer[i].size;
361
                instr.q = 0;  // nop instruction
362
                if (asize & 1) {
363
                    dataBuffers[section].push(&instr, 4);  // single size nop
364
                    asize -= 1;
365
                }
366
                instr.a.il = 2;  // double size nop
367
                while (asize >= 2) {
368
                    dataBuffers[section].push(&instr, 8);  // add double size nop
369
                    asize -= 2;
370
                }
371
            }
372
            // else if (codeBuffer[i].instruction == II_OPTIONS) {} // II_OPTIONS can be ignored here 
373
            continue;  // skip the rest
374
        }
375
        section = codeBuffer[i].section;
376
        if (section == 0 || section >= nSections) continue;
377
 
378
        instr.q = 0;           // reset template
379
        formatp = codeBuffer[i].formatp;
380
        templ = formatp->tmplate;
381
        format = formatp->format2;
382
 
383
        // assign registers
384
        uint8_t opAvail = formatp->opAvail;  // registers available in this format
385
 
386
        int nOp = instructionlistId[instructId].sourceoperands;
387
        if (nOp > 3 && instructionlistId[instructId].opimmediate) {
388
            opAvail |= 1;  // 3 registers and an immediate currently used only in truth_tab3 instruction
389
        }
390
 
391
        if (templ == 0xA || templ == 0xE) nOp++;  // make one more register for fallback, even if it is unused
392
 
393
        uint8_t operands[4] = {0,0,0,0};
394
        int a = 0;                              // bit index to opAvail
395
        int j = 3;                              // Index into operands
396
                                                // Loop through the bits in opAvail in reverse order to pick operands according to priority
397
        while (j >= 0 && a < 8) {
398
            if (opAvail & (1 << a)) {
399
                operands[j--] = 1 << a;
400
            }
401
            a++;
402
        }
403
 
404
        // List register operands
405
        uint8_t  registers[4] = {0,0,0,0};
406
        a = 3;
407
        if (codeBuffer[i].etype & XPR_REG3) registers[a--] = codeBuffer[i].reg3;
408
        if (codeBuffer[i].etype & XPR_REG2) registers[a--] = codeBuffer[i].reg2;
409
        if (codeBuffer[i].etype & XPR_REG1) registers[a--] = codeBuffer[i].reg1;
410
        // Make any remaining registers equal to fallback or first source 
411
        // to avoid false dependence on unused register in superscalar processor
412
        while (a >= 0) {
413
            if (codeBuffer[i].etype & (XPR_MASK | XPR_FALLBACK)) {
414
                registers[a--] = codeBuffer[i].fallback;
415
            }
416
            else {
417
                registers[a--] = codeBuffer[i].reg1;
418
            }
419
        }
420
 
421
        // Loop through operands to assign registers
422
        for (j = 3, a = 3; j >= 0; j--) {
423
            // put next operand in the sequence reg3, reg2, reg1, fallback into rt, rs, ru, or rd
424
            // these may be overwritten below in template B, C, and D.
425
            switch (operands[j]) {
426
            case 0x10:  // rt
427
                instr.a.rt = registers[a--] & 0x1F;
428
                break;
429
            case 0x20:  // rs
430
                instr.a.rs = registers[a--] & 0x1F;
431
                break;
432
            case 0x40:  // ru
433
                instr.a.ru = registers[a--] & 0x1F;
434
                break;
435
            case 0x80:  // rd
436
                instr.a.rd = registers[a--] & 0x1F;
437
                break;
438
            default:;  // memory and immediate operands or nothing
439
            }
440
        }
441
 
442
        // insert other fields
443
        instr.a.il = (format >> 8) & 3;  // il = instruction length
444
        instr.a.mode = (format >> 4) & 7;  // mode
445
        instr.a.op1 = instructionlistId[instructId].op1;  // operation
446
        if (templ != 0xD) {
447
            if (codeBuffer[i].dest != 2 && codeBuffer[i].dest != 0) instr.a.rd = codeBuffer[i].dest & 0x1F;  // destination register        
448
            if (templ != 0xC) {
449
                instr.a.ot = codeBuffer[i].dtype & 7;  // operand type
450
                if (format & 0x80) instr.a.ot |= 4;    // M bit
451
                if (templ != 0xB) {
452
                    if (codeBuffer[i].etype & XPR_MASK) {
453
                        instr.a.mask = codeBuffer[i].mask;  // mask register
454
                    }
455
                    else {
456
                        instr.a.mask = 7;        // no mask
457
                    }
458
                }
459
            }
460
        }
461
 
462
        uint8_t * instr_b = instr.b;  // avoid pedantic warnings from Gnu compiler
463
        // memory operand
464
        if (formatp->mem) {
465
            if (formatp->mem & 2) instr.a.rs = codeBuffer[i].base  & 0x1F;     // base in rs
466
            if (formatp->mem & 4) instr.a.rt = codeBuffer[i].index & 0x1F;     // index in rt
467
            uint8_t oldBase = codeBuffer[i].base;                              // save base pointer
468
 
469
            // calculate offset, possibly involving symbols. make relocation if necessary
470
            int64_t offset = calculateMemoryOffset(codeBuffer[i]);
471
 
472
            if (codeBuffer[i].base != oldBase) {
473
                // base pointer changed by calculateMemoryOffset
474
                switch (codeBuffer[i].formatp->mem & 3) {
475
                case 1:  // base in RT. obsolete
476
                    instr.a.rt = codeBuffer[i].base;  break;
477
                case 2:  // base in RS
478
                    instr.a.rs = codeBuffer[i].base;  break;
479
                }
480
            }
481
 
482
            // insert limit
483
            if (codeBuffer[i].etype & XPR_LIMIT) offset = codeBuffer[i].value.i;
484
 
485
            uint32_t addrPos = formatp->addrPos;  // position of offset field
486
            switch (formatp->addrSize) { // size of offset
487
            case 0:    // no offset
488
                break;
489
            case 1:    // 8 bits offset
490
                instr.b[addrPos] = uint8_t(offset);
491
                break;
492
            case 2:    // 16 bits offset
493
                *(int16_t *)(instr_b + addrPos) = int16_t(offset);
494
                break;
495
            case 4:    // 32 bits offset
496
                *(int32_t *)(instr_b + addrPos) = int32_t(offset);
497
                break;
498
            case 8:    // 64 bits offset
499
                *(int64_t *)(instr_b + addrPos) = offset;
500
            }
501
            // memory length or broadcast
502
            if (formatp->vect & 6) instr.a.rt = codeBuffer[i].length;
503
        }
504
 
505
        // jump offset
506
        if (formatp->jumpSize) {
507
 
508
            // calculate offset, possibly involving symbols. make relocation if necessary
509
            int64_t offset = calculateJumpOffset(codeBuffer[i]);
510
 
511
            uint32_t addrSize = formatp->jumpSize;    // size of offset field
512
            uint32_t addrPos  = formatp->jumpPos;  // position of offset field
513
 
514
            switch (addrSize) { // size of offset
515
            case 0:    // no offset
516
                break;
517
            case 1:    // 8 bits offset
518
                instr.b[addrPos] = uint8_t(offset);
519
                break;
520
            case 2:    // 16 bits offset
521
                *(int16_t *)(instr_b + addrPos) = int16_t(offset);
522
                break;
523
            case 3:   // 24 bits offset
524
                *(int16_t *)(instr_b + addrPos) = int16_t(offset);          // first 16 of 24 bits
525
                *(int8_t *)(instr_b + addrPos + 2) = int8_t(offset >> 16);  // last 8 bits
526
                break;
527
            case 4:    // 32 bits offset
528
                *(int32_t *)(instr_b + addrPos) = int32_t(offset);
529
                break;
530
            case 8:    // 64 bits offset
531
                *(int64_t *)(instr_b + addrPos) = offset;
532
            }
533
        }
534
 
535
        // immediate operand
536
        if (formatp->immSize) {
537
            int64_t value = codeBuffer[i].value.i;  // value of operand
538
            if (codeBuffer[i].sym3) {
539
                // calculation of symbol address. add relocation if needed
540
                value = calculateConstantOperand(codeBuffer[i], codeBuffer[i].address + codeBuffer[i].formatp->immPos, codeBuffer[i].formatp->immSize);
541
                if (codeBuffer[i].etype & XPR_ERROR) {
542
                    linei = codeBuffer[i].line;
543
                    errors.reportLine(codeBuffer[i].value.w); // report error
544
                }
545
            }
546
 
547
            uint32_t immPos = formatp->immPos;  // position of immediate field
548
            switch (formatp->immSize) { // size of immediate field
549
            case 1:    // 8 bits immediate
550
                if ((codeBuffer[i].etype & XPR_IMMEDIATE) == XPR_FLT) {
551
                    *(int8_t *)(instr_b + immPos) = (int8_t)(int)(codeBuffer[i].value.d);  // convert double to float16
552
                }
553
                else {
554
                    instr.b[immPos] = uint8_t(value);
555
                }
556
                break;
557
            case 2:    // 16 bits immediate
558
                if (instructionlistId[instructId].opimmediate == OPI_INT1632 && format > 0x200) {
559
                    // 16-bit + 32 bit integer operands
560
                    *(int16_t *)(instr_b + immPos) = int16_t(value >> 32);
561
                    *(int32_t *)(instr_b + 4) = int32_t(value);
562
                }
563
                else if ((codeBuffer[i].etype & XPR_IMMEDIATE) == XPR_FLT) {
564
                    *(int16_t *)(instr_b + immPos) = double2half(codeBuffer[i].value.d);  // convert double to float16
565
                }
566
                else {
567
                    *(int16_t *)(instr_b + immPos) = int16_t(value);
568
                }
569
                break;
570
            case 4:    // 32 bits immediate
571
                if (instructionlistId[instructId].opimmediate == OPI_2INT16) {
572
                    // two 16-bit integer operands
573
                    value = (uint32_t)value << 16 | uint32_t(value >> 32);
574
                    *(int32_t *)(instr_b + immPos) = int32_t(value);
575
                }
576
                else if ((codeBuffer[i].etype & XPR_IMMEDIATE) == XPR_FLT) {   // convert double to float
577
                    *(float *)(instr_b + immPos) = float(codeBuffer[i].value.d);
578
                }
579
                else {
580
                    *(int32_t *)(instr_b + immPos) = int32_t(value);
581
                    if (formatp->imm2 & 8) instr.a.im2 = uint16_t((uint64_t)value >> 32);
582
                }
583
                break;
584
            case 8:    // 64 bits immediate
585
                if (instructionlistId[instructId].opimmediate == OPI_2INT32) {
586
                    // two 32-bit integers. swap them
587
                    value = value >> 32 | value << 32;
588
                }
589
                *(int64_t *)(instr_b + immPos) = value;
590
            }
591
        }
592
        else if (opAvail & 1) {   // special case: three registers and an immediate
593
            int64_t value = calculateConstantOperand(codeBuffer[i], codeBuffer[i].address + codeBuffer[i].formatp->immPos, codeBuffer[i].formatp->immSize);
594
            *(int16_t *)(instr_b + 4) = int16_t(value);
595
        }
596
        else if (formatp->tmplate == 0xC && instructionlistId[instructId].opimmediate == OPI_IMPLICIT) {
597
            // insert implicit operand
598
            instr.i[0] |= instructionlistId[instructId].implicit_imm;
599
        }
600
        if (formatp->imm2 & 0x80) {  // various placements of OPJ
601
            if (formatp->imm2 & 0x10) {
602
                instr.b[7] = instructionlistId[instructId].op1; // OPJ in high part of IM2
603
            }
604
            else if (formatp->imm2 & 0x40) {    // no OPJ
605
            }
606
            else  {
607
                instr.b[0] = instructionlistId[instructId].op1;    // OPJ is in IM1
608
            }
609
            instr.a.op1 = format & 7;     // op1 is part of format       
610
        }
611
        if (formatp->imm2 & 0x40) {
612
            // insert constant
613
            if (formatp->format2 == 0x155) {
614
                instr.i[0] = fillerInstruction;  // filler instruction
615
            }
616
        }
617
        // additional fields for format E
618
        if (templ == 0xE) {
619
            instr.a.mode2 = format & 7;
620
            if (formatp->imm2 & 2) instr.a.im3 = codeBuffer[i].optionbits;
621
            if (!(formatp->imm2 & 0x100))
622
                instr.a.op2 = instructionlistId[instructId].op2;
623
        }
624
 
625
        if (formatp->category == 3 && instr.a.op1 == 0 && instr.a.op2 == 0) {
626
            // simplify NOP instruction. Remove all unnecessary bits
627
            instr.a.mask = 0;
628
            instr.a.ot = 0;
629
            if (instr.a.il > 1) instr.i[1] = 0;
630
        }
631
 
632
        // save code
633
        uint32_t ilen = instr.a.il;
634
        if (ilen == 0) ilen = 1;
635
        dataBuffers[section].push(&instr, ilen * 4);
636
    }
637
}
638
 
639
// make binary data for data sections
640
void CAssembler::makeBinaryData() {
641
    // similar to pass2, but data lines only
642
    section = 0;
643
 
644
    // lines loop
645
    for (linei = 1; linei < lines.numEntries(); linei++) {
646
        tokenB = lines[linei].firstToken;      // first token in line        
647
        tokenN = lines[linei].numTokens; // number of tokens in line 
648
        if (lines[linei].type == LINE_SECTION && tokens[tokenB+1].type == TOK_DIR) {
649
            switch (tokens[tokenB+1].id) {
650
            case DIR_SECTION:   // section starts here
651
                interpretSectionDirective();
652
                break;
653
            case DIR_END:    // section or function end
654
                interpretEndDirective();
655
                break;
656
            default:
657
                errors.report(tokens[tokenB + 1]);
658
            }
659
        }
660
        else if (lines[linei].type == LINE_DATADEF) {
661
            lineError = 0;
662
            tokenB = lines[linei].firstToken;      // first token in line        
663
            tokenN = lines[linei].numTokens; // number of tokens in line
664
            if (tokens[tokenB].type == TOK_DIR) continue;  // ignore directives here
665
            if (tokenN > 1) {               // lines with a single token cannot legally define a symbol name
666
                if (tokens[tokenB].type == TOK_TYP && tokens[tokenB+1].type == TOK_SYM) {
667
                    interpretVariableDefinition2();
668
                }
669
                else if (tokens[tokenB].type == TOK_ATT && tokens[tokenB].id == ATT_ALIGN) {
670
                    interpretAlign();
671
                }
672
                else {
673
                    interpretVariableDefinition1();
674
                }
675
            }
676
        }
677
    }
678
}
679
 
680
 
681
// put relocation records in output file
682
void CAssembler::makeBinaryRelocations() {
683
    uint32_t i;                                  // loop counter
684
    // copy relocation records
685
    for (i = 0; i < relocations.numEntries(); i++) {
686
        // translate symbol indexes in relocation records
687
        int32_t symi1, symi2;                    // symbol index
688
        uint32_t newSymi1, newSymi2;             // symbol index in output file
689
        if (relocations[i].r_sym) {
690
            symi1 = findSymbol(relocations[i].r_sym);
691
            if (symi1 > 0) {
692
                newSymi1 = symbols[symi1].st_unitnum;
693
                relocations[i].r_sym = newSymi1;  // replace by symbol index in outFile
694
                uint32_t sect = symbols[symi1].st_section;
695
                if (sect && symbols[symi1].st_bind == STB_WEAK) {
696
                    // there is a local reference to a weak public symbol. Make it both import and export
697
                    outFile.symbols[newSymi1].st_bind = STB_WEAK2;
698
                }
699
                if (sect && sect < sectionHeaders.numEntries() && sectionHeaders[sect].sh_type == SHT_COMDAT) {
700
                    // there is a local reference to a symbol in a communal section. Make it both import and export
701
                    outFile.symbols[newSymi1].st_bind = STB_WEAK2;
702
                }
703
            }
704
            else relocations[i].r_sym = 0;  // should not occur
705
        }
706
        if (relocations[i].r_refsym) {                 // reference symbol
707
            symi2 = findSymbol(relocations[i].r_refsym);
708
            if (symi2 > 0) {
709
                newSymi2 = symbols[symi2].st_unitnum;
710
                relocations[i].r_refsym = newSymi2;  // replace by symbol index in outFile
711
                if (symbols[symi2].st_section && symbols[symi2].st_bind == STB_WEAK) {
712
                    // there is a local reference to a weak public symbol. Make it both import and export
713
                    outFile.symbols[newSymi2].st_bind = STB_WEAK2;
714
                }
715
            }
716
            else relocations[i].r_refsym = 0;  // should not occur
717
        }
718
        outFile.addRelocation(relocations[i]);  // put relocation in outFile
719
    }
720
}
721
 
722
// make output listing
723
void CAssembler::makeListFile() {
724
    // Use the disassembler for making output listing
725
    CDisassembler disassembler;       // make an instance of CDisassembler
726
    // give all my tables to the disassembler
727
    disassembler.getComponents2(outFile, instructionlist);
728
    // change output file name
729
    disassembler.outputFile = cmd.outputListFile;
730
    // do the disassembly
731
    disassembler.go();
732
}
733
 
734
// calculate memory address possibly involving symbol. generate relocation if necessary
735
int64_t CAssembler::calculateMemoryOffset(SCode & code) {
736
    int64_t value = 0;
737
    int32_t symi1 = 0, symi2 = 0;
738
    if (code.sym1) symi1 = findSymbol(code.sym1); // target symbol, if any
739
    if (code.sym2) symi2 = findSymbol(code.sym2); // reference symbol, if any
740
    ElfFwcReloc relocation;                       // relocation, if needed
741
    bool needsRelocation = false;                 // relocation needed
742
 
743
    uint8_t fieldPos = code.formatp->addrPos;          // position of address or immediate field
744
    uint8_t fieldSize = code.formatp->addrSize;         // size of address or immediate field
745
 
746
    uint32_t scale = 0;                           // log2 scale factor to address, not including explicit symbol scale
747
    if (fieldSize == 1) {
748
        // scale factor determined by type
749
        uint32_t type = code.dtype;
750
        scale = type & 0xF;
751
        if (type & 0x40) scale -= 3;
752
    }
753
 
754
    // check target symbol
755
    if (symi1) {
756
        if (symi2) {
757
            // difference between two symbols
758
            if (code.symscale1 == 0) code.symscale1 = 1;
759
            if (symbols[symi1].st_section == symbols[symi2].st_section && symbols[symi1].st_bind == STB_LOCAL && symbols[symi2].st_bind == STB_LOCAL) {
760
                // both symbols are local in same section. final value can be calculated
761
                value = (int64_t)(symbols[symi1].st_value - symbols[symi2].st_value) / code.symscale1;
762
                value = (value + code.offset_mem) >> scale;
763
            }
764
            else {
765
                // symbols are in different section or external. relocation needed
766
                relocation.r_type = R_FORW_REFP;          // relative to arbitrary reference point
767
                relocation.r_type |= bitScanReverse(code.symscale1) + scale;  // scale factor
768
                relocation.r_sym = code.sym1;              // Symbol index
769
                relocation.r_refsym = code.sym2;           // Reference symbol
770
                relocation.r_addend = uint32_t(code.offset_mem);      // Addend
771
                needsRelocation = true;
772
            }
773
        }
774
        else {
775
            // a single symbol
776
            // is symbol relative to IP, DATAP, THREADP or constant?
777
            //uint8_t basepointer = 0;
778
            uint32_t symsection = symbols[symi1].st_section;
779
            if (symbols[symi1].st_type == STT_CONSTANT) {
780
                // constant
781
                relocation.r_type = R_FORW_ABS | scale;
782
                relocation.r_sym = code.sym1;              // Symbol index
783
                relocation.r_refsym = 0;           // Reference symbol
784
                relocation.r_addend = uint32_t(code.offset_mem);      // Addend
785
                needsRelocation = true;
786
            }
787
            else if (symsection > 0 && symsection < sectionHeaders.numEntries()) {
788
                // local symbol relative to IP or DATAP
789
                if (sectionHeaders[symsection].sh_flags & (SHF_IP | SHF_EXEC)) {
790
                    if (symsection == section) {
791
                        // symbol in same section relative to IP. calculate address
792
                        code.base = uint8_t(REG_IP >> 16);
793
                        value = (int64_t)(symbols[symi1].st_value - uint64_t(code.address + code.size * 4));
794
                        value = (value + code.offset_mem) >> scale;    // scale offset
795
                    }
796
                    else {
797
                        // local symbol in different IP section. needs relocation
798
                        code.base = uint8_t(REG_IP >> 16);
799
                        relocation.r_type = R_FORW_SELFREL;     // self-relative
800
                        //if (code.instruction & II_JUMP_INSTR) relocation.r_type |= R_FORW_SCALE4; // jump instruction scaled by 4
801
                        relocation.r_addend = fieldPos - code.size * 4;  // position of relocated field relative to instruction end
802
                        relocation.r_sym = code.sym1;          // temporary symbol index. resolve when symbol table created
803
                        relocation.r_refsym = 0;
804
                        relocation.r_addend += (int32_t)code.offset_mem;
805
                        needsRelocation = true;
806
                    }
807
                }
808
                else {
809
                    // relative to DATAP or THREADP. needs relocation
810
                    if (sectionHeaders[symsection].sh_flags & SHF_THREADP) {
811
                        code.base = uint8_t(REG_THREADP >> 16);
812
                        relocation.r_type = R_FORW_THREADP;   // relocation relative to THREADP
813
                    }
814
                    else {
815
                        code.base = uint8_t(REG_DATAP >> 16);
816
                        relocation.r_type = R_FORW_DATAP;     // relocation relative to DATAP
817
                    }
818
                    relocation.r_type |= scale;         // scale factor only if 8-bit offset allowed
819
                    relocation.r_sym = code.sym1;       // temporary symbol index. resolve when symbol table created
820
                    relocation.r_refsym = 0;
821
                    relocation.r_addend = uint32_t(code.offset_mem);
822
                    needsRelocation = true;
823
                }
824
            }
825
            else {
826
                // remote symbol relative to IP or DATAP
827
                if (symbols[symi1].st_other & (STV_IP | STV_EXEC)) {
828
                    // relative to IP
829
                    code.base = uint8_t(REG_IP >> 16);
830
                    relocation.r_type = R_FORW_SELFREL;
831
                    //if (code.instruction & II_JUMP_INSTR) relocation.r_type |= R_FORW_SCALE4;
832
                    relocation.r_addend = fieldPos - code.size * 4;  // position of relocated field relative to instruction end
833
                }
834
                else if (symbols[symi1].st_other & STV_THREADP) {
835
                    // relative to THREADP
836
                    code.base = uint8_t(REG_THREADP >> 16);
837
                    relocation.r_type = R_FORW_THREADP;
838
                    relocation.r_addend = 0;
839
                }
840
                else {
841
                    // relative to DATAP
842
                    code.base = uint8_t(REG_DATAP >> 16);
843
                    relocation.r_type = R_FORW_DATAP;
844
                    relocation.r_addend = 0;
845
                }
846
                relocation.r_sym = code.sym1;          // temporary symbol index. resolve when symbol table created
847
                relocation.r_refsym = 0;
848
                relocation.r_addend += (int32_t)code.offset_mem;
849
                if (code.formatp->addrSize == 1 && !(relocation.r_type & R_FORW_RELSCALEMASK)) {
850
                    relocation.r_type |= scale;
851
                }
852
                needsRelocation = true;
853
            }
854
        }
855
    }
856
    else {
857
        // no symbol
858
        value = code.offset_mem >> scale;
859
    }
860
 
861
    if (needsRelocation) {
862
        // relocation needed. insert source address
863
        relocation.r_type |= fieldSize << 8;      // relocation size
864
        relocation.r_offset = (uint64_t)code.address + fieldPos;
865
        relocation.r_section = code.section;
866
        value = 0;   // value included in relocation addend
867
        relocations.push(relocation);  // save relocation
868
    }
869
    return value;
870
}
871
 
872
int64_t CAssembler::calculateJumpOffset(SCode & code) {   // calculate jump offset possibly involving symbol. generate relocation if necessary
873
    int64_t value = 0;
874
    int32_t symi5 = 0;
875
    if (code.sym5) symi5 = findSymbol(code.sym5); // target symbol, if any
876
    ElfFwcReloc relocation;                      // relocation, if needed
877
    bool needsRelocation = false;                 // relocation needed
878
 
879
    uint8_t fieldSize = code.formatp->jumpSize;       // size of jump offset field
880
    uint8_t fieldPos  = code.formatp->jumpPos;     // position of jump offset field
881
 
882
    uint32_t scale = 2;                      // jumps always scaled by 1 << 2 = 4
883
 
884
    // check target symbol
885
    if (symi5) {
886
        uint32_t symsection = symbols[symi5].st_section;
887
 
888
        if (symsection > 0 && symsection < sectionHeaders.numEntries()) {
889
            // local symbol relative to IP
890
            if (sectionHeaders[symsection].sh_flags & (SHF_IP | SHF_EXEC)) {
891
                if (symsection == section) {
892
                    // symbol in same section relative to IP. calculate address
893
                    value = (int64_t)(symbols[symi5].st_value - uint64_t(code.address + code.size * 4));
894
                    value = (value + code.offset_jump) >> scale;    // scale jump offset by 4                          
895
                                                                   // address size must be at least 2
896
                }
897
                else {
898
                    // local symbol in different IP section. needs relocation
899
                    relocation.r_type = R_FORW_SELFREL;     // self-relative
900
                    relocation.r_type |= R_FORW_SCALE4; // jump instruction scaled by 4
901
                    relocation.r_addend = fieldPos - code.size * 4;  // position of relocated field relative to instruction end
902
                    relocation.r_sym = code.sym5;          // temporary symbol index. resolve when symbol table created
903
                    relocation.r_refsym = 0;
904
                    relocation.r_addend += (int32_t)code.offset_jump;
905
                    needsRelocation = true;
906
                }
907
            }
908
        }
909
        else {
910
            // remote symbol relative to IP
911
            relocation.r_type = R_FORW_SELFREL;
912
            relocation.r_type |= R_FORW_SCALE4;
913
            relocation.r_addend = fieldPos - code.size * 4;  // position of relocated field relative to instruction end
914
            relocation.r_sym = code.sym5;          // temporary symbol index. resolve when symbol table created
915
            relocation.r_refsym = 0;
916
            relocation.r_addend += (int32_t)code.offset_jump;
917
            needsRelocation = true;
918
        }
919
    }
920
    else {
921
        // no symbol
922
        value = code.offset_jump >> scale;
923
    }
924
 
925
    if (needsRelocation) {
926
        // relocation needed. insert source address
927
        relocation.r_type |= fieldSize << 8;      // relocation size
928
        relocation.r_offset = (uint64_t)code.address + fieldPos;
929
        relocation.r_section = code.section;
930
        value = 0;   // value included in relocation addend
931
        relocations.push(relocation);  // save relocation
932
    }
933
    return value;
934
}
935
 
936
 
937
// calculate constant or immediate operand possibly involving symbol. generate relocation if necessary
938
int64_t CAssembler::calculateConstantOperand(SExpression & expr, uint64_t address, uint32_t fieldSize) {
939
    int64_t value = 0;
940
    int32_t symi3 = 0, symi4 = 0;
941
    if (expr.sym3) {
942
        symi3 = findSymbol(expr.sym3); // target symbol, if any
943
        if (symi3 < 1) {errors.reportLine(ERR_SYMBOL_UNDEFINED);  return 0;}
944
    }
945
    if (expr.sym4) {
946
        symi4 = findSymbol(expr.sym4); // reference symbol, if any
947
        if (symi4 < 1) {errors.reportLine(ERR_SYMBOL_UNDEFINED);  return 0;}
948
    }
949
 
950
    ElfFwcReloc relocation;                       // relocation, if needed
951
    bool needsRelocation = false;
952
    // relocation needed
953
 
954
    if (symi3) {
955
        // there is a symbol
956
        if (symi4) {
957
            // difference between two symbols
958
            if (symbols[symi3].st_section == symbols[symi4].st_section && symbols[symi3].st_bind == STB_LOCAL && symbols[symi4].st_bind == STB_LOCAL) {
959
                // both symbols are local in same section. final value can be calculated
960
                value = (int64_t)(symbols[symi3].st_value - symbols[symi4].st_value);
961
                if (expr.symscale1 > 1) value /= expr.symscale1;
962
            }
963
            else {
964
                // symbols are in different section or external. relocation needed
965
                relocation.r_type = R_FORW_REFP;          // relative to arbitrary reference point
966
                if (expr.symscale1 > 1) relocation.r_type |= bitScanReverse(expr.symscale1);  // scale factor
967
                relocation.r_sym = expr.sym3;              // Symbol index
968
                relocation.r_refsym = expr.sym4;           // Reference symbol
969
                relocation.r_addend = int32_t(expr.value.w);      // Addend
970
                needsRelocation = true;
971
            }
972
        }
973
        else {
974
            // single symbol
975
            if (symbols[symi3].st_type & STT_CONSTANT) {
976
                // symbol is an external constant
977
                relocation.r_type = R_FORW_ABS;          // absolute value
978
                if (expr.symscale1 > 1) relocation.r_type |= bitScanReverse(expr.symscale1);  // scale factor
979
                relocation.r_sym = expr.sym3;              // Symbol index
980
                relocation.r_refsym = 0;           // Reference symbol
981
                relocation.r_addend = int32_t(expr.value.w);      // Addend
982
                needsRelocation = true;
983
            }
984
            else if ((sectionHeaders[section].sh_flags & (SHF_WRITE | SHF_DATAP)) && fieldSize >= 4) {
985
                // other symbol. absolute address allowed only in writeable data section
986
                relocation.r_type = R_FORW_ABS;            // absolute value, 64 bits, no scale
987
                relocation.r_sym = expr.sym3;              // Symbol index
988
                relocation.r_refsym = 0;           // Reference symbol
989
                if (expr.symscale1 > 1) relocation.r_type |= bitScanReverse(expr.symscale1);  // scale factor
990
                relocation.r_addend = int32_t(expr.value.w);      // Addend
991
                if (symbols[symi3].st_section && fieldSize < 4) {
992
                    expr.etype = XPR_ERROR;
993
                    value = ERR_ABS_RELOCATION;
994
                }
995
                // warn if absolute address
996
                err.submit(ERR_ABS_RELOCATION_WARN, lines[linei].linenum, (char*)symbolNameBuffer.buf() + symbols[symi3].st_name);
997
                needsRelocation = true;
998
            }
999
            else {
1000
                // symbol without reference point not allowed here
1001
                expr.etype = XPR_ERROR;
1002
                value = ERR_ABS_RELOCATION;
1003
            }
1004
        }
1005
    }
1006
    else {
1007
        // no symbol
1008
        value = expr.value.i;
1009
    }
1010
    if (needsRelocation) {
1011
        // relocation needed. insert source address
1012
        relocation.r_offset = address;
1013
        relocation.r_section = section;
1014
        relocation.r_type |= fieldSize << 8;      // relocation size
1015
        value = 0;   // value included in relocation addend
1016
        relocations.push(relocation);  // save relocation
1017
    }
1018
    return value;
1019
}

powered by: WebSVN 2.1.0

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