-
Notifications
You must be signed in to change notification settings - Fork 6
Expand file tree
/
Copy pathmain.cpp
More file actions
453 lines (415 loc) · 14.7 KB
/
main.cpp
File metadata and controls
453 lines (415 loc) · 14.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
/**************************** main.cpp *******************************
* Author: Agner Fog
* Date created: 2017-04-17
* Last modified: 2025-01-21
* Version: 1.14
* Project: Binary tools for ForwardCom instruction set
* Description: This includes assembler, disassembler, linker, library
* manager, and emulator in one program
*
* Instructions:
* Run with option -h for help
*
* For detailed instructions, see forwardcom.pdf
*
* (c) Copyright 2017-2025 GNU General Public License version 3
* https://www.gnu.org/licenses
*****************************************************************************/
#include "stdafx.h"
// Check if running on little endian system
static void CheckEndianness();
// Buffer for symbol names is made global in order to make it accessible to operators:
// bool operator < (ElfFWC_Sym2 const &, ElfFWC_Sym2 const &)
// bool operator < (SStringEntry const & a, SStringEntry const & b)
// bool operator < (SSymbolEntry const & a, SSymbolEntry const & b)
CTextFileBuffer symbolNameBuffer; // Buffer for symbol names during assembly, linking, and library operations
// Main. Program starts here
int main(int argc, char * argv[]) {
CheckEndianness(); // Check that machine is little-endian
#ifdef _DEBUG
// For debugging only: Read command line from file resp.txt
if (argc == 1) {
char commandline[] = "@resp.txt";
char * dummyarg[] = { argv[0], commandline};
argc = 2; argv = dummyarg;
}
#endif
cmd.readCommandLine(argc, argv); // Read command line parameters
if (cmd.job == CMDL_JOB_HELP) return 0; // Help screen has been printed. Do nothing else
CConverter maincvt; // This object takes care of all conversions etc.
maincvt.go(); // Do everything the command line says
if (cmd.verbose && cmd.job != CMDL_JOB_EMU) printf("\n"); // End with newline
if (err.getWorstError()) cmd.mainReturnValue = err.getWorstError(); // Return with error code
return cmd.mainReturnValue;
}
CConverter::CConverter() {
// Constructor
}
void CConverter::go() {
// Do whatever the command line parameters say
switch (cmd.job) {
case CMDL_JOB_DUMP:
// File dump requested
readInputFile();
if (err.number()) return;
switch (fileType) {
case FILETYPE_FWC: case FILETYPE_ELF:
dumpELF(); break;
default:
err.submit(ERR_DUMP_NOT_SUPPORTED, getFileFormatName(fileType)); // Dump of this file type not supported
}
printf("\n"); // New line
break;
case CMDL_JOB_ASS:
// assemble
readInputFile();
if (err.number()) return;
assemble();
break;
case CMDL_JOB_DIS:
// disassemble
readInputFile();
if (err.number()) return;
disassemble();
break;
case CMDL_JOB_LINK:
case CMDL_JOB_RELINK:
link(); // linker
break;
case CMDL_JOB_LIB:
readInputFile();
if (err.number()) return;
lib(); // library manager
break;
case CMDL_JOB_EMU:
emulate(); // emulator
break;
case 0: return; // no job. command line error
default:
err.submit(ERR_INTERNAL);
}
}
// read input file
void CConverter::readInputFile() {
// Ignore nonexisting filename when building library
int IgnoreError = (cmd.fileOptions & CMDL_FILE_IN_IF_EXISTS);
// Read input file
read(cmd.getFilename(cmd.inputFile), IgnoreError);
if (cmd.job == CMDL_JOB_ASS) fileType = FILETYPE_ASM;
else getFileType(); // Determine file type
if (err.number()) return; // Return if error
cmd.inputType = fileType; // Save input file type in cmd for access from other modules
if (cmd.outputType == 0) {
// desired type not specified
cmd.outputType = fileType;
}
}
void CConverter::dumpELF() {
// Dump ELF file
// Make object for interpreting 32 bit ELF file
CELF elf;
*this >> elf; // Give it my buffer
elf.parseFile(); // Parse file buffer
if (err.number()) return; // Return if error
elf.dump(cmd.dumpOptions); // Dump file
*this << elf; // Take back my buffer
}
void CConverter::assemble() {
// Aassemble to ELF file
// Make instance of assembler
CAssembler ass;
if (err.number()) return;
*this >> ass; // Give it my buffer
ass.go(); // run
}
void CConverter::disassemble() {
// Disassemble ELF file
// Make instance of disassembler
CDisassembler dis;
if (err.number()) return;
*this >> dis; // Give it my buffer
dis.parseFile(); // Parse file buffer
if (err.number()) return; // Return if error
dis.getComponents1(); // Get components from ELF file
dis.go(); // Convert
}
void CConverter::lib() {
// Library manager
// Make instance of library manager
CLibrary libmanager;
if (err.number()) return;
*this >> libmanager; // Give it my buffer
libmanager.go(); // Do the job
}
void CConverter::link() {
// Linker
// Make instance of linker
CLinker linker;
linker.go(); // Do the job
}
void CConverter::emulate() {
// Emulator
// Make instance of linker
CEmulator emulator;
emulator.go(); // Do the job
}
// Convert half precision floating point number to single precision
// Optional support for subnormals
// NaN payload is left-justified for ForwardCom
float half2float(uint32_t half, bool supportSubnormal) {
union {
uint32_t hhh;
float fff;
struct {
uint32_t mant: 23;
uint32_t expo: 8;
uint32_t sign: 1;
};
} u;
u.hhh = (half & 0x7fff) << 13; // Exponent and mantissa
u.hhh += 0x38000000; // Adjust exponent bias
if ((half & 0x7C00) == 0) {// Subnormal
if (supportSubnormal) {
u.hhh = 0x3F800000 - (24 << 23); // 2^-24
u.fff *= int(half & 0x3FF); // subnormal value = mantissa * 2^-24
}
else {
u.hhh = 0; // make zero
}
}
if ((half & 0x7C00) == 0x7C00) { // infinity or NaN
u.expo = 0xFF;
if (half & 0x3FF) { // NaN
u.mant = (half & 0x3FF) << 13; // left-justify NaN payload
}
}
u.hhh |= (half & 0x8000) << 16; // sign bit
return u.fff;
}
// Convert floating point number to half precision.
// Round to nearest or even.
// Optional support for subnormals
// NaN payload is left-justified
uint16_t float2half(float x, bool supportSubnormal) {
union { // single precision float
float f;
struct {
uint32_t mant: 23;
uint32_t expo: 8;
uint32_t sign: 1;
};
} u;
union { // half precision float
uint16_t h;
struct {
uint16_t mant: 10;
uint16_t expo: 5;
uint16_t sign: 1;
};
} v;
u.f = x;
v.expo = u.expo - 0x70; // adjust exponent bias
v.mant = u.mant >> 13; // get upper part of mantissa
if (u.mant & (1 << 12)) { // round to nearest or even
if ((u.mant & ((1 << 12) - 1)) || (v.mant & 1)) { // round up if odd or remaining bits are nonzero
v.h++; // overflow here will carry into exponent
}
}
v.sign = u.sign; // copy sign bit
if (u.expo == 0xFF) { // infinity or NaN
v.expo = 0x1F;
if (u.mant != 0) { // NaN
v.mant = u.mant >> 13; // No rounding
if (v.mant == 0) v.mant = 0x200; // make sure it is still a NaN
}
}
else if (u.expo > 0x8E) {
v.expo = 0x1F; v.mant = 0; // overflow -> inf
}
else if (u.expo < 0x71) {
v.expo = 0;
if (supportSubnormal) {
u.expo += 24;
u.sign = 0;
int mants = int(u.f); // convert subnormal
v.mant = mants & 0x3FF;
if (mants == 0x400) v.expo = 1; // rounded to normal
}
else {
v.mant = 0; // underflow -> 0
}
}
return v.h;
}
// Convert double precision floating point number to half precision.
// subnormals optionally supported
// Nan payloads not preserved
uint16_t double2half(double x, bool supportSubnormal) {
union {
double d;
struct {
uint64_t mant: 52;
uint64_t expo: 11;
uint64_t sign: 1;
};
} u;
union {
uint16_t h;
struct {
uint16_t mant: 10;
uint16_t expo: 5;
uint16_t sign: 1;
};
} v;
u.d = x;
v.mant = u.mant >> 42; // get upper part of mantissa
if (u.mant & ((uint64_t)1 << 41)) { // round to nearest or even
if ((u.mant & (((uint64_t)1 << 41) - 1)) || (v.mant & 1)) { // round up if odd or remaining bits are nonzero
v.h++; // overflow here will give infinity
}
}
v.expo = u.expo - 0x3F0;
v.sign = u.sign;
if (u.expo == 0x7FF) {
v.expo = 0x1F; // infinity or nan
if (u.mant != 0 && v.mant == 0) v.mant = 0x200; // make sure output is a nan if input is nan
}
else if (u.expo > 0x40E) {
v.expo = 0x1F; v.mant = 0; // overflow -> inf
}
else if (u.expo < 0x3F1) { // underflow
v.expo = 0;
if (supportSubnormal) {
u.expo += 24;
u.sign = 0;
v.mant = int(u.d) & 0x3FF;
}
else {
v.mant = 0; // underflow -> 0
}
}
return v.h;
}
// Check that we are running on a machine with little-endian memory
// organization and right data representation
static void CheckEndianness() {
static uint8_t bytes[4] = { 1, 2, 3, 0xC0 };
uint8_t * bb = bytes;
if (*(uint32_t*)bb != 0xC0030201) {
err.submit(ERR_BIG_ENDIAN); // Big endian
}
if (*(int32_t*)bb != -1073544703) {
err.submit(ERR_BIG_ENDIAN); // not two's complement
}
*(float*)bb = 1.0f;
if (*(uint32_t*)bb != 0x3F800000) {
err.submit(ERR_BIG_ENDIAN); // Not IEEE floating point format
}
}
// Bit scan reverse. Returns floor(log2(x)), 0 if x = 0
uint32_t bitScanReverse(uint64_t x) {
uint32_t s = 32; // shift count
uint32_t r = 0; // return value
uint64_t y; // x >> s
do {
y = x >> s;
if (y) {
r += s;
x = y;
}
s >>= 1;
}
while (s);
return r;
}
// Bit scan forward. Returns index to the lowest set bit, 0 if x = 0
uint32_t bitScanForward(uint64_t x) {
uint32_t s = 32; // shift count
uint32_t r = 0; // return value
if (x == 0) return 0;
do {
if ((x & (((uint64_t)1 << s) - 1)) == 0) {
x >>= s;
r += s;
}
s >>= 1;
}
while (s);
return r;
}
const char * timestring(uint32_t t) {
// Convert 32 bit time stamp to string
// Fix the problem that time_t may be 32 bit or 64 bit
union {
time_t t;
uint32_t t32;
} utime;
utime.t = 0;
utime.t32 = t;
const char * string = ctime(&utime.t);
if (string == 0) string = "?";
return string;
}
const char * exceptionCodeName(uint32_t code) {
// get the name of an exception code from a NaN payload
switch (code) {
case nan_data_uninitialized:
return "data not initialized";
case nan_data_unavailable:
return "data not available";
case nan_div0:
return "division by zero";
case nan_overflow_div:
return "division overflow";
case nan_overflow_mul:
return "multiplication overflow";
case nan_overflow_fma:
return "FMA overflow";
case nan_overflow_add:
return "addition/subtraction overflow";
case nan_overflow_conv:
return "conversion overflow";
case nan_overflow_other:
return "other overflow";
case nan_invalid_0div0:
return "zero/zero";
case nan_invalid_infdivinf:
return "INF/INF";
case nan_invalid_0mulinf:
return "zero*INF";
case nan_invalid_inf_sub_inf:
return "INF-INF";
case nan_underflow:
return "underflow exception";
case nan_inexact:
return "inexact exception";
case nan_invalid_sqrt:
return "sqrt of negative";
case nan_invalid_log:
return "log of non-positive";
case nan_invalid_pow:
return "pow of invalid arguments";
case nan_invalid_rem:
return "remainder or modulo of invalid arguments";
case nan_invalid_asin:
return "asin of invalid argument";
case nan_invalid_acos:
return "acos of invalid argument";
case nan_invalid_acosh:
return "acosh of invalid argument";
case nan_invalid_atanh:
return "atanh of invalid argument";
}
// none of the above:
if (code > nan_div0) return "unknown data error";
if (code > nan_overflow_div) return "div 0 error";
if (code > nan_invalid_0div0) return "overflow";
if (code > nan_underflow) return "invalid calculation";
if (code > nan_inexact) return "underflow";
if (code > nan_invalid_sqrt) return "inexact";
if (code >= 0b110000000) return "invalid argument to standard math function";
if (code >= 0b101000000) return "invalid argument to math function";
if (code >= 0b100000000) return "invalid operation in other function";
if (code > 0) return "user-defined error code";
return "no error code";
}