-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathrvmult.c
91 lines (82 loc) · 2.88 KB
/
rvmult.c
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
#include <stdint.h>
#include "riscv.h"
#include "rvexec.h"
#include "rvinsn.h"
#ifdef DEFINE_EXTENSION
DEFINE_EXTENSION(M)
#endif
#define SIGN (XWORD_C(1) << XWORD_BIT - 1)
#if XWORD_BIT <= 32 && defined UINT_LEAST64_MAX
#define dxword_t uint_least64_t
#elif XWORD_BIT <= 64 && defined __SIZEOF_INT128__
#define dxword_t unsigned __int128
#endif
static xword_t mulhu(xword_t x, xword_t y, xword_t neg) {
#ifdef dxword_t
dxword_t z = (dxword_t)x * y;
return neg ? -(-z >> XWORD_BIT) : z >> XWORD_BIT;
#else
xword_t a = x >> XWORD_BIT / 2,
b = x & (XWORD_C(1) << XWORD_BIT / 2) - 1,
c = y >> XWORD_BIT / 2,
d = y & (XWORD_C(1) << XWORD_BIT / 2) - 1,
p = a * d, q = b * c, r = a * c, s = b * d;
r += p >> XWORD_BIT / 2; p &= (XWORD_C(1) << XWORD_BIT / 2) - 1;
r += q >> XWORD_BIT / 2; q &= (XWORD_C(1) << XWORD_BIT / 2) - 1;
r += p + q + (s >> XWORD_BIT / 2) >> XWORD_BIT / 2;
return r + (neg && (p + q << XWORD_BIT / 2) + s & XWORD_MAX);
#endif
}
static void xmul(struct hart *t, uint_least32_t i) {
xword_t in1 = t->ireg[rs1(i)],
in2 = t->ireg[rs2(i)],
neg = 0,
out;
switch (funct3(i)) {
case 0: out = in1 * in2; break;
case 1: neg = (in1 ^ in2) & SIGN;
in2 = in2 & SIGN ? -in2 & XWORD_MAX : in2;
goto mulhsu;
case 2: neg = in1 & SIGN;
mulhsu: in1 = in1 & SIGN ? -in1 & XWORD_MAX : in1;
case 3: out = mulhu(in1, in2, neg); break;
case 4: neg = (in1 ^ in2) & SIGN;
in1 = in1 & SIGN ? -in1 & XWORD_MAX : in1;
in2 = in2 & SIGN ? -in2 & XWORD_MAX : in2;
case 5: out = in2 ? in1 / in2 : neg ? 1 : -1; break;
case 6: neg = in1 & SIGN;
in1 = in1 & SIGN ? -in1 & XWORD_MAX : in1;
in2 = in2 & SIGN ? -in2 & XWORD_MAX : in2;
case 7: out = in2 ? in1 % in2 : in1; break;
}
if (rd(i)) t->ireg[rd(i)] = (neg ? -out : out) & XWORD_MAX;
}
__attribute__((alias("xmul"))) execute_t xops01;
#if XWORD_BIT > 32
static void wmul(struct hart *t, uint_least32_t i) {
xword_t in1 = t->ireg[rs1(i)],
in2 = t->ireg[rs2(i)],
neg = 0,
out;
switch (funct3(i)) {
case 0: out = in1 * in2; break;
case 4: neg = (in1 ^ in2) & XWORD_C(1) << 31;
in1 = in1 & XWORD_C(1) << 31 ? -in1 : in1;
in2 = in2 & XWORD_C(1) << 31 ? -in2 : in2;
case 5: in1 &= (XWORD_C(1) << 32) - 1;
in2 &= (XWORD_C(1) << 32) - 1;
out = in2 ? in1 / in2 : neg ? 1 : -1; break;
case 6: neg = in1 & XWORD_C(1) << 31;
in1 = in1 & XWORD_C(1) << 31 ? -in1 : in1;
in2 = in2 & XWORD_C(1) << 31 ? -in2 : in2;
case 7: in1 &= (XWORD_C(1) << 32) - 1;
in2 &= (XWORD_C(1) << 32) - 1;
out = in2 ? in1 % in2 : in1; break;
default: trap(t, ILLINS, i); return;
}
out = (neg ? -out : out) & (XWORD_C(1) << 32) - 1;
out = (out ^ XWORD_C(1) << 31) - (XWORD_C(1) << 31);
if (rd(i)) t->ireg[rd(i)] = out & XWORD_MAX;
}
__attribute__((alias("wmul"))) execute_t wops01;
#endif