-
Notifications
You must be signed in to change notification settings - Fork 0
/
in_TestFloat.cpp
379 lines (345 loc) · 14.1 KB
/
in_TestFloat.cpp
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
/* rvfpm - 2024
Andreas S. Bakke
Description:
Wrapper to test for IEEE754 complaince using Berkley TestFloat.
Run:
make TestFloat.
Operations not tested by BTF:
FSGNJ - sign bit modified directly
FCLASS
FMV
(FMSUB, FNMSUB, FNMADD not directly tested, but should have the same behavior as FMADD with varied signs)
*/
#include <iostream>
#include <string>
#include <cstring>
#include <unordered_map>
#include <functional>
#include <cmath>
#include <cstdint>
#include <limits>
#include "fpu_top.h"
#include <sstream>
#include <iomanip>
//Generated by ChatGPT. Prompt: Can you write me two c++ function to convert a floating point value to hex and vice versa?
// Function to convert a hexadecimal string to a float
float hexToFloat(const std::string& hexStr) {
// Convert the hexadecimal string to a uint32_t
uint32_t intRep;
std::stringstream ss;
ss << std::hex << hexStr;
ss >> intRep;
// Reinterpret the bits of the integer as float
float floatValue;
std::memcpy(&floatValue, &intRep, sizeof(floatValue));
return floatValue;
}
std::string floatToHex(float floatValue) {
// Create an output string stream with hexadecimal formatting and no showbase
std::ostringstream oss;
oss << std::hex << std::noshowbase;
// Interpret the bits of the float as an unsigned integer
auto value = *reinterpret_cast<unsigned int*>(&floatValue);
// Set the width to 8 characters and fill with zeroes
oss << std::setw(8) << std::setfill('0') << value;
// Return the formatted string
return oss.str();
}
//Adapted from floatToHex
std::string doubleToHex(double doubleValue) {
// Create an output string stream with hexadecimal formatting and no showbase
std::ostringstream oss;
oss << std::hex << std::noshowbase;
// Interpret the bits of the float as an unsigned integer
auto value = *reinterpret_cast<unsigned long*>(&doubleValue);
// Set the width to 16 characters and fill with zeroes
oss << std::setw(16) << std::setfill('0') << value;
// Return the formatted string
return oss.str();
}
//Generated by ChatGPT. Prompt: Similar to the hexToFloat, can you write me one for uint32_t and int32_t?
uint32_t hexToUnsignedInt(const std::string& hexStr) {
uint32_t value;
std::stringstream ss(hexStr);
ss >> std::hex >> value;
return value;
}
//Adapted from hexToUnsignedInt
uint64_t hexToUnsignedInt64(const std::string& hexStr) {
uint64_t value;
std::stringstream ss(hexStr);
ss >> std::hex >> value;
return value;
}
int32_t hexToInt(const std::string& hexStr) {
int32_t value;
std::stringstream ss(hexStr);
ss >> std::hex >> value;
return value;
}
//Adapted from hexToInt
int64_t hexToInt64(const std::string& hexStr) {
int64_t value;
std::stringstream ss(hexStr);
ss >> std::hex >> value;
return value;
}
//Generated by ChatGPT. Prompt: Can you write yet another to translate from uint32_t to hex string?
std::string uint32ToHexString(uint32_t uintValue) {
// Create an output string stream with hexadecimal formatting and no showbase
std::ostringstream oss;
oss << std::hex << std::noshowbase;
// Interpret the bits of the float as an unsigned integer
auto value = *reinterpret_cast<unsigned int*>(&uintValue);
// Set the width to 8 characters and fill with zeroes
oss << std::setw(8) << std::setfill('0') << value;
// Return the formatted string
return oss.str();
}
//Adapted from uint32ToHexString
std::string uint64ToHexString(uint64_t uintValue) {
// Create an output string stream with hexadecimal formatting and no showbase
std::ostringstream oss;
oss << std::hex << std::noshowbase;
// Interpret the bits of the float as an unsigned integer
auto value = *reinterpret_cast<unsigned long*>(&uintValue);
// Set the width to 16 characters and fill with zeroes
oss << std::setw(16) << std::setfill('0') << value;
// Return the formatted string
return oss.str();
}
//Partly generated by ChatGpt. Prompt: Given a unsigned int where the last 5 bit indicates flags raised, can you write me a function to reverse the order of the bits, and write as hex?
//Function to change position of flags and convert to Hex (reverse)
std::string convFlags(unsigned int flags) {
unsigned int newFlags = 0;
for (unsigned int i = 0; i<5; i++) {
if(flags & (1<<i)) {
newFlags |= (1 << (4-i));
}
}
std::stringstream ss;
// Output the flags as a hex number, padded with zeros up to the necessary number of digits (2 for 8 bits)
ss << std::setfill('0') << std::setw(2) << std::hex << (newFlags & 0x1F); // Mask to get only the least significant 5 bits
return ss.str();
}
//Initialize testFPU
FPU testFPU = FPU();
int main(int argc, char** argv) {
std::string op, fmt, rm, input1, input2, input3, input4, flags;
RISCV_FMT instr_fmt;
//Use first 4 registers
uint32_t r1 = 0;
uint32_t r2 = 1;
uint32_t r3 = 2;
uint32_t rd = 3;
op=argv[1]; //Get operation type:
fmt=argv[2]; //Get format
rm=argv[3]; //Set appropriate rounding mode
unsigned int rm_i = 0;
if (rm == "-rnear_even") {
rm_i = 0b000;
} else if (rm == "-rminMag") {
rm_i = 0b001;
} else if (rm == "-rmin") {
rm_i = 0b010;
} else if (rm == "-rmax") {
rm_i = 0b011;
} else {
//-rnear_maxMag & -rodd are not supported
rm_i = 0b000;
}
CSRTYPE rm_instr = {.parts= {CSR, 0, 0b001, 0, 0x002}}; //Set rounding mode
testFPU.addAcceptedInstruction(rm_instr.instr, 0, rm_i, 0, 0, 0, 0, 0, 0);
testFPU.testFloatOp();
loadType a, b, c;
if (op == "fmadd" || op == "fmsub" || op == "fnmsub" || op == "fnmadd") //Fused operations has an extra input compared to others
{
while (std::cin >> input1 >> input2 >> input3 >> input4 >> flags) {
if (fmt=="D") {
instr_fmt = D;
a = hexToUnsignedInt64(input1);
b = hexToUnsignedInt64(input2);
c = hexToUnsignedInt64(input3);
} else {
instr_fmt = S;
a = hexToUnsignedInt(input1);
b = hexToUnsignedInt(input2);
c = hexToUnsignedInt(input3);
}
uint32_t r1 = 1;
uint32_t r2 = 2;
uint32_t r3 = 3;
ITYPE instr_load = {.parts= {7, r1, 0b010, instr_fmt, 0}};
testFPU.bd_load(instr_load.instr, a);
instr_load = {.parts= {7, r2, 0b010, instr_fmt, 0}};
testFPU.bd_load(instr_load.instr, b);
instr_load = {.parts= {7, r3, 0b010, instr_fmt, 0}};
testFPU.bd_load(instr_load.instr, c);
RTYPE instr_r4type = {.parts_r4type= {FMADD, 0, 0b000, r1, r2, instr_fmt, r3}};
testFPU.addAcceptedInstruction(instr_r4type.instr, 0, 0, 0, 0, 0, 0, 0, 0);
FpuPipeObj result = testFPU.testFloatOp();
if (fmt=="D") {
std::cout << input1 << " " << input2 << " " << input3 << " " << doubleToHex(result.data) << " " << convFlags(result.flags) << std::endl;
} else {
std::cout << input1 << " " << input2 << " " << input3 << " " << floatToHex(result.data) << " " << convFlags(result.flags) << std::endl;
}
}
} else if (op == "fsqrt" || op == "ui32_to_f32" || op == "i32_to_f32" || op == "f32_to_ui32" || op == "f32_to_i32" || op == "ui32_to_f64" || op == "i32_to_f64" || op == "f64_to_ui32" || op == "f64_to_i32") { //fsqrt uses only three inputs
while (std::cin >> input1 >> input2 >> flags) {
if (fmt=="D") {
instr_fmt = D;
a = hexToUnsignedInt64(input1);
b = hexToUnsignedInt64(input2);
} else {
instr_fmt = S;
a = hexToUnsignedInt(input1);
b = hexToUnsignedInt(input2);
}
//Load values
ITYPE instr_load = {.parts= {7, r1, 0b010, 0, 0}};
testFPU.bd_load(instr_load.instr, a);
instr_load = {.parts= {7, r2, 0b010, 0, 0}};
testFPU.bd_load(instr_load.instr, b);
//Do operation
RTYPE instr_rtype = {};
if (op == "fsqrt") {
instr_rtype = {.parts= {OP_FP, rd, 0b000, r1, 0b00000, instr_fmt, FSQRT}};
testFPU.addAcceptedInstruction(instr_rtype.instr, 0, 0, 0, 0, 0, 0, 0, 0);
}
else if (op == "ui32_to_f32" || op == "ui32_to_f64") {
instr_rtype = {.parts= {OP_FP, rd, rm_i, r1, 0b00001, instr_fmt, FCVT_S_W}};
testFPU.addAcceptedInstruction(instr_rtype.instr, 0, a, 0, 0, 0, 0, 0, 0);
}
else if (op == "i32_to_f32" || op == "i32_to_f64") {
instr_rtype = {.parts= {OP_FP, rd, rm_i, r1, 0b00000, instr_fmt, FCVT_S_W}};
testFPU.addAcceptedInstruction(instr_rtype.instr, 0, a, 0, 0, 0, 0, 0, 0);
}
else if (op == "f32_to_ui32" || op == "f64_to_ui32") {
instr_rtype = {.parts= {OP_FP, rd, rm_i, r1, 0b00001, instr_fmt, FCVT_W_S}};
testFPU.addAcceptedInstruction(instr_rtype.instr, 0, 0, 0, 0, 0, 0, 0, 0);
}
else if (op == "f32_to_i32" || op == "f64_to_i32") {
instr_rtype = {.parts= {OP_FP, rd, rm_i, r1, 0b00000, instr_fmt, FCVT_W_S}};
testFPU.addAcceptedInstruction(instr_rtype.instr, 0, 0, 0, 0, 0, 0, 0, 0);
}
FpuPipeObj result = testFPU.testFloatOp();
if (op == "fsqrt" || op == "ui32_to_f32" || op == "i32_to_f32" || op == "ui32_to_f64" || op == "i32_to_f64") {
if (fmt == "D") {
std::cout << input1 << " " << doubleToHex(result.data) << " " << convFlags(result.flags) << std::endl;
} else {
std::cout << input1 << " " << floatToHex(result.data) << " " << convFlags(result.flags) << std::endl;
}
} else {
std::cout << input1 << " " << uint32ToHexString(static_cast<uint32_t>((int)result.data)) << " " << convFlags(result.flags & 0b01111) << std::endl; //Conversion to int doesn't check for exactness
}
}
} else if ( op == "ui64_to_f32" || op == "i64_to_f32" || op == "f32_to_ui64" || op == "f32_to_i64" || op == "ui64_to_f64" || op == "i64_to_f64" || op == "f64_to_ui64" || op == "f64_to_i64") { //fsqrt uses only three inputs
while (std::cin >> input1 >> input2 >> flags) {
if (fmt=="D") {
instr_fmt = D;
} else {
instr_fmt = S;
}
unsigned long a = hexToUnsignedInt64(input1);
unsigned long b = hexToUnsignedInt64(input2);
unsigned long c = hexToUnsignedInt64(input3);
//Load values
if (op == "ui64_to_f32" || op == "i64_to_f32" || op == "ui64_to_f64" || op == "i64_to_f64"){
} else {
ITYPE instr_load = {.parts= {7, r1, 0b010, 0, 0}};
testFPU.bd_load(instr_load.instr, a);
instr_load = {.parts= {7, r2, 0b010, 0, 0}};
testFPU.bd_load(instr_load.instr, b);
}
//Do operation
RTYPE instr_rtype = {};
if (op == "ui64_to_f32" || op == "ui64_to_f64") {
instr_rtype = {.parts= {OP_FP, rd, rm_i, r1, 0b00011, instr_fmt, FCVT_S_W}};
testFPU.addAcceptedInstruction(instr_rtype.instr, 0, a, 0, 0, 0, 0, 0, 0);
}
else if (op == "i64_to_f32" || op == "i64_to_f64") {
instr_rtype = {.parts= {OP_FP, rd, rm_i, r1, 0b00010, instr_fmt, FCVT_S_W}};
testFPU.addAcceptedInstruction(instr_rtype.instr, 0, a, 0, 0, 0, 0, 0, 0);
}
else if (op == "f32_to_ui64" || op == "f64_to_ui64") {
instr_rtype = {.parts= {OP_FP, rd, rm_i, r1, 0b00011, instr_fmt, FCVT_W_S}};
testFPU.addAcceptedInstruction(instr_rtype.instr, 0, 0, 0, 0, 0, 0, 0, 0);
}
else if (op == "f32_to_i64" || op == "f64_to_i64") {
instr_rtype = {.parts= {OP_FP, rd, rm_i, r1, 0b00010, instr_fmt, FCVT_W_S}};
testFPU.addAcceptedInstruction(instr_rtype.instr, 0, 0, 0, 0, 0, 0, 0, 0);
}
FpuPipeObj result = testFPU.testFloatOp();
if (op == "ui64_to_f32" || op == "i64_to_f32" || op == "ui64_to_f64" || op == "i64_to_f64") {
if (fmt == "D") {
std::cout << input1 << " " << doubleToHex(result.data) << " " << convFlags(result.flags) << std::endl;
} else {
std::cout << input1 << " " << floatToHex(result.data) << " " << convFlags(result.flags) << std::endl;
}
} else {
std::cout << input1 << " " << uint64ToHexString((unsigned long) result.data) << " " << convFlags(result.flags & 0b01111) << std::endl; //Conversion to int doesn't check for exactness
}
}
} else {
while (std::cin >> input1 >> input2 >> input3 >> flags) {
if (fmt=="D") {
instr_fmt = D;
a = hexToUnsignedInt64(input1);
b = hexToUnsignedInt64(input2);
c = hexToUnsignedInt64(input3);
} else {
instr_fmt = S;
a = hexToUnsignedInt(input1);
b = hexToUnsignedInt(input2);
c = hexToUnsignedInt(input3);
}
//Load values
ITYPE instr_load = {.parts= {7, r1, 0b010, 0, 0}};
testFPU.bd_load(instr_load.instr, a);
instr_load = {.parts= {7, r2, 0b010, 0, 0}};
testFPU.bd_load(instr_load.instr, b);
//Do operation
RTYPE instr_rtype;
if (op == "fadd")
{
instr_rtype = {.parts= {OP_FP, rd, 0b000, r1, r2, instr_fmt, FADD}};
}
else if (op == "fsub") //FSUB_S:
{
instr_rtype = {.parts= {OP_FP, rd, 0b000, r1, r2, instr_fmt, FSUB}};
}
else if (op == "fmul") //FMUL_S:
{
instr_rtype = {.parts= {OP_FP, rd, 0b000, r1, r2, instr_fmt, FMUL}};
}
else if (op == "fdiv") //FDIV_S:
{
instr_rtype = {.parts= {OP_FP, rd, 0b000, r1, r2, instr_fmt, FDIV}};
}
else if (op == "feq") //FEQ.S
{
instr_rtype = {.parts = {OP_FP, rd, 0b010, r1, r2, instr_fmt, FCMP}};
}
else if (op == "flt") //FLT.S
{
instr_rtype = {.parts = {OP_FP, rd, 0b001, r1, r2, instr_fmt, FCMP}};
}
else if (op == "fle") //FLE.s
{
instr_rtype = {.parts = {OP_FP, rd, 0b000, r1, r2, instr_fmt, FCMP}};
}
testFPU.addAcceptedInstruction(instr_rtype.instr, 0, 0, 0, 0, 0, 0, 0, 0);
FpuPipeObj result = testFPU.testFloatOp();
if (op == "feq" || op == "flt" || op == "fle"){
std::cout << input1 << " " << input2 << " " << std::to_string(static_cast<int>(result.data)).front() << " " << convFlags(result.flags) << std::endl;
} else {
if (fmt == "D") {
std::cout << input1 << " " << input2 << " " << doubleToHex(result.data) << " " << convFlags(result.flags) << std::endl;
} else{
std::cout << input1 << " " << input2 << " " << floatToHex(result.data) << " " << convFlags(result.flags) << std::endl;
}
}
}
}
return 0;
}