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

Subversion Repositories forwardcom

[/] [forwardcom/] [bintools/] [emulator6.cpp] - Blame information for rev 57

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 57 Agner
/****************************  emulator6.cpp  ********************************
2
* Author:        Agner Fog
3
* date created:  2018-02-18
4
* Last modified: 2021-02-19
5
* Version:       1.11
6
* Project:       Binary tools for ForwardCom instruction set
7
* Description:
8
* Emulator: System functions
9
*
10
* Copyright 2018-2021 GNU General Public License http://www.gnu.org/licenses
11
*****************************************************************************/
12
 
13
#include "stdafx.h"
14
 
15
// Data encoding names
16
 
17
// Interrupt names
18
SIntTxt interruptNames[] = {
19
    // Error interrupts
20
    {INT_UNKNOWN_INST,       "Unknown instruction"},
21
    {INT_WRONG_PARAMETERS,       "Illegal instruction code"},
22
    {INT_ACCESS_READ,        "Memory read access violation"},
23
    {INT_ACCESS_WRITE,       "Memory write access violation"},
24
    {INT_ACCESS_EXE,         "Memory execute access violation"},
25
    {INT_CALL_STACK,         "Call stack overflow or underflow"},
26
    {INT_ARRAY_BOUNDS,       "Array bounds violation"},
27
    {INT_MISALIGNED_JUMP,    "Jump to misaligned address"},
28
    {INT_MISALIGNED_MEM,     "Misaligned memory address"},
29
 
30
    // Software traps. Not necessarily supported
31
    {INT_OVERFL_UNSIGN,      "Unsigned integer overflow"},
32
    {INT_OVERFL_SIGN,        "Signed integer overflow"},
33
    {INT_OVERFL_FLOAT,       "Floating point overflow"},
34
    {INT_FLOAT_INVALID,      "Floating point invalid operation"},
35
    {INT_FLOAT_UNDERFL,      "Floating point underflow"},
36
    {INT_FLOAT_NAN_LOSS,     "Floating point NAN in compare or conversion to integer"},
37
    {0xFFFF,                 "Filler interrupt"},
38
};
39
 
40
// System function names
41
SIntTxt systemFunctionNames[] = {
42
    {SYSF_EXIT,              "exit"},       // terminate program
43
    {SYSF_ABORT,             "abort"},      // abort program
44
    {SYSF_TIME,              "time"},       // time in seconds since jan 1, 1970    
45
 
46
// input/output functions
47
    {SYSF_PUTS,              "puts"},       // write string to stdout
48
    {SYSF_PUTCHAR,           "putchar"},    // write character to stdout
49
    {SYSF_PRINTF,            "printf"},     // write formatted output to stdout
50
    {SYSF_FPRINTF,           "fprintf"},    // write formatted output to file
51
    {SYSF_SNPRINTF,          "snprintf"},    // write formatted output to string buffer 
52
    {SYSF_FOPEN,             "fopen"},      //  open file
53
    {SYSF_FCLOSE,            "fclose"},     // SYSF_FCLOSE
54
    {SYSF_FREAD,             "fread"},      // read from file
55
    {SYSF_FWRITE,            "fwrite"},     // write to file 
56
    {SYSF_FFLUSH,            "fflush"},     // flush file 
57
    {SYSF_FEOF,              "feof"},       // check if end of file 
58
    {SYSF_FTELL,             "ftell"},      // get file position 
59
    {SYSF_FSEEK,             "fseek"},      // set file position 
60
    {SYSF_FERROR,            "ferror"},     // get file error    
61
    {SYSF_GETCHAR,           "getchar"},    // read character from stdin 
62
    {SYSF_FGETC,             "fgetc"},      // read character from file 
63
    {SYSF_FGETS,             "fgets"},      // read string from file 
64
    {SYSF_SCANF,             "scanf"},      // read formatted input from stdio 
65
    {SYSF_FSCANF,            "fscanf"},     // read formatted input from file 
66
    {SYSF_SSCANF,            "sscanf"},     // read formatted input from string buffer 
67
    {SYSF_REMOVE,            "remove"},     // delete file 
68
};
69
 
70
// number of entries in list
71
const int numSystemFunctionNames = sizeof(systemFunctionNames) / sizeof(SIntTxt);
72
 
73
 
74
// interrupt or trap
75
// To trace a runtime error, set a breakpoint here
76
void CThread::interrupt(uint32_t n) {
77
    // check if error is disabled
78
    uint32_t capabbit = 0;                  // bit in capabilities register
79
    switch (n) {
80
    case INT_BREAKPOINT:                    // debug breakpoint
81
        listOut.tabulate(emulator->disassembler.asmTab0);
82
        listOut.put("breakpoint");
83
        listOut.newLine();
84
        return;
85
    case INT_UNKNOWN_INST:                  // unknown instruction
86
        capabbit = 1;
87
        perfCounters[perf_unknown_instruction]++;
88
        break;
89
    case INT_WRONG_PARAMETERS:              // unsupported parameters for instruction
90
    case INT_CALL_STACK:                    // call stack overflow or underflow
91
        capabbit = 2;
92
        perfCounters[perf_wrong_operands]++;
93
        break;
94
    case INT_ACCESS_READ:                   // memory access violation, read
95
        capabbit = 8;
96
        perfCounters[perf_read_violation]++;
97
        break;
98
    case INT_ACCESS_WRITE:                  // memory access violation, write
99
        capabbit = 0x10;
100
        perfCounters[perf_write_violation]++;
101
        break;
102
    case INT_ACCESS_EXE:                    // memory access violation, execute
103
        capabbit = 8;
104
        perfCounters[perf_read_violation]++;
105
        break;
106
    case INT_ARRAY_BOUNDS:                  // array bounds overflow, unsigned
107
        capabbit = 4;
108
        perfCounters[perf_array_overflow]++;
109
        break;
110
    case INT_MISALIGNED_MEM:                // misaligned memory access.
111
        capabbit = 0x20;
112
        perfCounters[perf_misaligned]++;
113
        break;
114
    case INT_MISALIGNED_JUMP:               // jump to an address not divisible by 4
115
    default:
116
        capabbit = 0;
117
    }
118
    if (perfCounters[perf_type_of_first_error] == 0) {
119
        // save first error
120
        perfCounters[perf_type_of_first_error] = bitScanReverse(capabbit);
121
        uint8_t instrLength = pInstr->i[0] >> 30;  if (instrLength == 0) instrLength = 1;
122
        perfCounters[perf_address_of_first_error] = ((ip - ip0) >> 2) - instrLength;
123
    }
124
 
125
    if (!(capabilyReg[disable_errors_capability_register] & capabbit)) {
126
        terminate = true;                   // stop execution unless error is disabled
127
    }
128
    if (listFileName && cmd.maxLines != 0) {   // write interrupt to debug output
129
        listOut.tabulate(emulator->disassembler.asmTab0);
130
        const char * iname = Lookup(interruptNames, n);
131
        listOut.put(iname);
132
        if (terminate) listOut.put(". Terminating");
133
        listOut.newLine();
134
    }
135
}
136
 
137
/*
138
// give error message if compiled for 32 bit
139
void checkVa_listSize() {
140
    // C variable argument list va_list is not compatible with ForwardCom in 32 bit mode
141
    if (sizeof(void*) < 8) { // 32 bit host system. va_list has 32-bit entries except for %f
142
        puts("\nError: forw must be compiled in 64 bit mode. printf function may fail\n");
143
    }
144
} */
145
 
146
// check if system function has access to a particular address
147
uint64_t CThread::checkSysMemAccess(uint64_t address, uint64_t size, uint8_t rd, uint8_t rs, uint8_t mode) {
148
    // rd = register pointing to beginning of shared memory area, rs = size of shared memory area
149
    // mode = SHF_READ or SHF_WRITE
150
    // return value is possibly reduced size, or zero if no access
151
    if ((rd | rs) == 0) return 0;                // no access if both are r0
152
    uint64_t base = registers[rd];               // beginning of shared area
153
    uint64_t bsize = registers[rs];              // size of shared area
154
    if (address + size < address) size = ~address; // avoid overflow
155
    if (base + bsize < base) bsize = ~base;      // avoid overflow
156
    if ((rd & rs & 0x1F) != 0x1F) {              // share all if both are r31
157
        // check if within shared area
158
        if (address < base) return 0;
159
        if (address + size > base + bsize) size = base + bsize - address;
160
    }
161
    // check application's memory map
162
    uint32_t index = mapIndex3;
163
    // find index
164
    while (address < memoryMap[index].startAddress) {
165
        if (index > 0) index--;
166
        else return 0;
167
    }
168
    while (address >= memoryMap[index+1].startAddress) {
169
        if (index+2 < memoryMap.numEntries()) index++;
170
        else return 0;
171
    }
172
    // check read/write permission
173
    if ((memoryMap[index].access_addend & mode) != mode) return 0;
174
 
175
    // check if multiple map entries covered
176
    uint32_t index2 = index;
177
    while (address + size >= memoryMap[index2+1].startAddress
178
        && index2+2 < memoryMap.numEntries()
179
        && (memoryMap[index2+1].access_addend & mode) == mode) {
180
            index2++;
181
        }
182
    uint64_t size2 = memoryMap[index2+1].startAddress - address;  // maximum possible size
183
    if (size < size2) size = size2;
184
    return size;
185
}
186
 
187
// emulate fprintf with ForwardCom argument list
188
int CThread::fprintfEmulated(FILE * stream, const char * format, uint64_t * argumentList) {
189
    // a ForwardCom argument list is compatible with a va_list in 64-bit windows but not in Linux
190
    static CMemoryBuffer fstringbuf;             // buffer containing format string
191
    fstringbuf.setSize(0);                       // discard any previously stored string
192
    fstringbuf.pushString(format);               // copy format string
193
    // split the format string into substrings with a single format specifier in each
194
    uint32_t arg = 0;                            // argument index
195
    int returnValue;                             // return value;
196
    int returnSum = 0;                           // sum of return values;
197
    char * startp;                               // start of current substring in format string
198
    char * percentp1;                            // percent sign in current substring
199
    char * percentp2;                            // next percent sign starting next substring
200
    startp = fstringbuf.getString(0);            // start of string buffer
201
    percentp1 = startp;                          // search for first % sign
202
    while (true) {
203
        percentp1 = strchr(percentp1, '%');
204
        if (percentp1 && percentp1[1] == '%') percentp1 += 2; // skip "%%" which is not a format code
205
        else break;
206
    }
207
    // loop for substrings of format string containing only one format specifier each
208
    do {
209
        char c = 0;                                      // format character
210
        int asterisks = 0;
211
        bool isString = false;
212
        if (percentp1) {
213
            percentp2 = percentp1 + 1;               // search for next % sign
214
            while (true) {
215
                percentp2 = strchr(percentp2, '%');
216
                if (percentp2 && percentp2[1] == '%') percentp2 += 2; // skip "%%" which is not a format code
217
                else break;
218
            }
219
            if (percentp2) *percentp2 = 0;           // put temporary end of string at next % sign
220
            // check if argument is a string, and count asterisks
221
            int i = 1;
222
            while (true) {
223
                c = percentp1[i++];                  // read character in format specifier
224
                if (c == 0) break;                   // end of string
225
                if (c == '*') asterisks++;           // count asterisks
226
                c |= 0x20;                           // lower case
227
                if (c == 's') isString = true;       // %s means string
228
                if (c >= 'a' && c <= 'z') break;     // a letter terminates the format specifier
229
            }
230
        }
231
        else {
232
            percentp2 = 0;
233
        }
234
        uint64_t argument = argumentList[arg];   // The argument list can contain any type of argument with size up to 64 bits
235
        union {
236
            uint64_t a;
237
            double d;
238
        } uu;
239
        if (isString) argument += (uint64_t)memory; // translate string address
240
        // Print current argument with format substring.
241
        if (asterisks) { // asterisks indicate extra arguments
242
            if (c == 'a' || c == 'e' || c == 'f' || c == 'g') {
243
                // floating point argument
244
                if (asterisks == 1) {
245
                    uu.a = argumentList[arg+1];
246
                    returnValue = fprintf(stream, startp, argument, uu.d, argumentList[arg+2]);
247
                }
248
                else { // asterisks = 2
249
                    uu.a = argumentList[arg+2];
250
                    returnValue = fprintf(stream, startp, argument, argumentList[arg+1], uu.d);
251
                }
252
            }
253
            else { // integer argument
254
                returnValue = fprintf(stream, startp, argument, argumentList[arg+1], argumentList[arg+2]);
255
            }
256
            arg += asterisks + 1;
257
        }
258
        else {
259
            if (c == 'a' || c == 'e' || c == 'f' || c == 'g') {
260
                // floating point argument
261
                uu.a = argument;
262
                returnValue = fprintf(stream, startp, uu.d);
263
            }
264
            else {
265
                returnValue = fprintf(stream, startp, argument);
266
            }
267
            arg++;
268
        }
269
        if (returnValue < 0) return returnValue; // return error
270
        else returnSum += returnValue;           // sum of return values
271
        if (percentp2) *percentp2 = '%';         // re-insert next % sign
272
        startp = percentp1 = percentp2;
273
    }
274
    while (startp);                              // loop to next substring
275
    return returnSum;                            // return total number of characters written
276
}
277
 
278
 
279
// entry for system calls
280
void CThread::systemCall(uint32_t mod, uint32_t funcid, uint8_t rd, uint8_t rs) {
281
    if (listFileName) {
282
        // debug listing
283
        listOut.tabulate(emulator->disassembler.asmTab0);
284
        listOut.put("system call: ");
285
        if (mod == SYSM_SYSTEM) { // search for function name
286
            for (int i = 0; i < numSystemFunctionNames; i++) {
287
                if (systemFunctionNames[i].a == funcid) { // name is in list
288
                    listOut.put(systemFunctionNames[i].b);
289
                    goto NAME_WRITTEN;
290
                }
291
            }
292
        }
293
        // name not found. write id
294
        listOut.putHex(mod);  listOut.put(":");  listOut.putHex(funcid);
295
        NAME_WRITTEN:
296
        listOut.newLine();
297
    }
298
    uint64_t temp;    // temporary
299
    uint64_t dsize;   // data size
300
    const char * str = 0;    // string
301
    if (mod == SYSM_SYSTEM) {// system function
302
        // dispatch by function id
303
        switch (funcid) {
304
        case SYSF_EXIT:      // terminate program
305
            cmd.mainReturnValue = (int)registers[0];
306
            terminate = true;  break;
307
        case SYSF_ABORT:     // abort program
308
            cmd.mainReturnValue = (int)registers[0];
309
            terminate = true;  break;
310
        case SYSF_TIME:      // time
311
            temp = time(0);
312
            if (registers[0] && checkSysMemAccess(registers[0], 8, rd, rs, SHF_WRITE)) *(uint64_t*)(memory + registers[0]) = temp;
313
            registers[0] = temp;  break;
314
        case SYSF_PUTS:      // write string to stdout
315
            str = (const char*)memory + registers[0];
316
            if (strlen(str) > checkSysMemAccess(registers[0], -1, rd, rs, SHF_READ)) {
317
                interrupt(INT_ACCESS_READ);
318
            }
319
            else puts(str);
320
            break;
321
        case SYSF_PUTCHAR:   // write character to stdout
322
            putchar((char)registers[0]);
323
            break;
324
        case SYSF_PRINTF:    // write formatted output to stdout
325
            registers[0] = fprintfEmulated(stdout, (const char*)memory + registers[0], (uint64_t*)(memory + registers[1]));
326
            break;
327
        case SYSF_FPRINTF:   // write formatted output to file
328
            registers[0] = fprintfEmulated((FILE *)(registers[0]), (const char*)memory + registers[1], (uint64_t*)(memory + registers[2]));
329
            break;
330
            /*
331
        case SYSF_SNPRINTF:   // write formatted output to string buffer
332
            // this works only in 64 bit windows
333
            dsize = registers[1];  // size of data to read
334
            if (checkSysMemAccess(registers[0], dsize, rd, rs, SHF_WRITE) < dsize) {
335
                interrupt(INT_ACCESS_WRITE); // write access violation
336
                ret = 0;
337
            }
338
            else ret = snprintf((char*)memory + registers[0], registers[1], (const char*)memory + registers[2], (const char*)memory + registers[3]);
339
            registers[0] = ret;
340
            break;*/
341
        case SYSF_FOPEN:     //  open file
342
            registers[0] = (uint64_t)fopen((const char*)memory + registers[0], (const char*)memory + registers[1]);
343
            break;
344
        case SYSF_FCLOSE:    // SYSF_FCLOSE
345
            registers[0] = (uint64_t)fclose((FILE*)registers[0]);
346
            break;
347
        case SYSF_FREAD:     // read from file
348
            dsize = registers[1] * registers[2];  // size of data to read
349
            if (checkSysMemAccess(registers[0], dsize, rd, rs, SHF_WRITE) < dsize) {
350
                interrupt(INT_ACCESS_WRITE); // write access violation
351
                registers[0] = 0;
352
            }
353
            else registers[0] = (uint64_t)fread(memory + registers[0], (size_t)registers[1], (size_t)registers[2], (FILE *)(size_t)registers[3]);
354
            break;
355
        case SYSF_FWRITE:    // write to file 
356
            dsize = registers[1] * registers[2];  // size of data to write
357
            if (checkSysMemAccess(registers[0], dsize, rd, rs, SHF_READ) < dsize) {
358
                interrupt(INT_ACCESS_READ); // write access violation
359
                registers[0] = 0;
360
            }
361
            else registers[0] = (uint64_t)fwrite(memory + registers[0], (size_t)registers[1], (size_t)registers[2], (FILE *)(size_t)registers[3]);
362
            break;
363
        case SYSF_FFLUSH:    // flush file 
364
            registers[0] = (uint64_t)fflush((FILE *)registers[0]);
365
            break;
366
        case SYSF_FEOF:      // check if end of file 
367
            registers[0] = (uint64_t)feof((FILE *)registers[0]);
368
            break;
369
        case SYSF_FTELL:     // get file position 
370
            registers[0] = (uint64_t)ftell((FILE *)registers[0]);
371
            break;
372
        case SYSF_FSEEK:     // set file position 
373
            registers[0] = (uint64_t)fseek((FILE *)registers[0], (long int)registers[1], (int)registers[2]);
374
            break;
375
        case SYSF_FERROR:    // get file error
376
            registers[0] = (uint64_t)ferror((FILE *)registers[0]);
377
            break;
378
        case SYSF_GETCHAR:   // read character from stdin 
379
            registers[0] = (uint64_t)getchar();
380
            break;
381
        case SYSF_FGETC:     // read character from file 
382
            registers[0] = (uint64_t)fgetc((FILE *)registers[0]);
383
            break;
384
        case SYSF_FGETS:     // read string from file 
385
            dsize = registers[1];  // size of data to read
386
            if (checkSysMemAccess(registers[0], dsize, rd, rs, SHF_WRITE) < dsize) {
387
                interrupt(INT_ACCESS_WRITE); // write access violation
388
                registers[0] = 0;
389
            }
390
            else {
391
                registers[0] = (uint64_t)fgets((char *)(memory+registers[0]), (int)registers[1], (FILE *)registers[2]);
392
            }
393
            break;
394
        case SYSF_GETS_S:     // read string from stdin 
395
            dsize = registers[1];  // size of data to read
396
            if (checkSysMemAccess(registers[0], dsize, rd, rs, SHF_WRITE) < dsize) {
397
                interrupt(INT_ACCESS_WRITE); // write access violation
398
                registers[0] = 0;
399
            }
400
            else {
401
                char * r = fgets((char *)(memory+registers[0]), (int)registers[1], stdin);
402
                if (r == 0) registers[0] = 0;  // registers[0] unchanged if success
403
            }
404
            break;
405
            /*
406
        case SYSF_SCANF:     // read formatted input from stdio
407
            ret = vscanf((char *)(memory+registers[0]), (va_list)(memory + registers[1]));
408
            if (checkSysMemAccess(registers[0], ret, rd, rs, SHF_WRITE) < ret) {
409
                interrupt(INT_ACCESS_WRITE); // write access violation
410
            }
411
            registers[0] = ret;
412
            break;
413
        case SYSF_FSCANF:    // read formatted input from file
414
            ret = vfscanf((FILE *)registers[0], (char *)(memory+registers[1]), (va_list)(memory + registers[2]));
415
            if (checkSysMemAccess(registers[0], ret, rd, rs, SHF_WRITE) < ret) {
416
                interrupt(INT_ACCESS_WRITE); // write access violation
417
            }
418
            registers[0] = ret;
419
            break;
420
        case SYSF_SSCANF:    // read formatted input from string buffer
421
            ret = vsscanf((char *)(memory+registers[0]), (char *)(memory+registers[1]), (va_list)(memory + registers[2]));
422
            if (checkSysMemAccess(registers[0], ret, rd, rs, SHF_WRITE) < ret) {
423
                interrupt(INT_ACCESS_WRITE); // write access violation
424
            }
425
            registers[0] = ret;
426
            break; */
427
        case SYSF_REMOVE:    // delete file 
428
            registers[0] = (uint64_t)remove((char *)(memory+registers[0]));
429
            break;
430
        }
431
    }
432
}

powered by: WebSVN 2.1.0

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