xref: /openbmc/qemu/target/riscv/bitmanip_helper.c (revision fd4b81a3)
1 /*
2  * RISC-V Bitmanip Extension Helpers for QEMU.
3  *
4  * Copyright (c) 2020 Kito Cheng, kito.cheng@sifive.com
5  * Copyright (c) 2020 Frank Chang, frank.chang@sifive.com
6  * Copyright (c) 2021 Philipp Tomsich, philipp.tomsich@vrull.eu
7  *
8  * This program is free software; you can redistribute it and/or modify it
9  * under the terms and conditions of the GNU General Public License,
10  * version 2 or later, as published by the Free Software Foundation.
11  *
12  * This program is distributed in the hope it will be useful, but WITHOUT
13  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
15  * more details.
16  *
17  * You should have received a copy of the GNU General Public License along with
18  * this program.  If not, see <http://www.gnu.org/licenses/>.
19  */
20 
21 #include "qemu/osdep.h"
22 #include "qemu/host-utils.h"
23 #include "exec/exec-all.h"
24 #include "exec/helper-proto.h"
25 #include "tcg/tcg.h"
26 
27 static const uint64_t adjacent_masks[] = {
28     dup_const(MO_8, 0x55),
29     dup_const(MO_8, 0x33),
30     dup_const(MO_8, 0x0f),
31     dup_const(MO_16, 0xff),
32     dup_const(MO_32, 0xffff),
33     UINT32_MAX
34 };
35 
36 static inline target_ulong do_swap(target_ulong x, uint64_t mask, int shift)
37 {
38     return ((x & mask) << shift) | ((x & ~mask) >> shift);
39 }
40 
41 static target_ulong do_grev(target_ulong rs1,
42                             target_ulong rs2,
43                             int bits)
44 {
45     target_ulong x = rs1;
46     int i, shift;
47 
48     for (i = 0, shift = 1; shift < bits; i++, shift <<= 1) {
49         if (rs2 & shift) {
50             x = do_swap(x, adjacent_masks[i], shift);
51         }
52     }
53 
54     return x;
55 }
56 
57 target_ulong HELPER(grev)(target_ulong rs1, target_ulong rs2)
58 {
59     return do_grev(rs1, rs2, TARGET_LONG_BITS);
60 }
61 
62 target_ulong HELPER(grevw)(target_ulong rs1, target_ulong rs2)
63 {
64     return do_grev(rs1, rs2, 32);
65 }
66 
67 static target_ulong do_gorc(target_ulong rs1,
68                             target_ulong rs2,
69                             int bits)
70 {
71     target_ulong x = rs1;
72     int i, shift;
73 
74     for (i = 0, shift = 1; shift < bits; i++, shift <<= 1) {
75         if (rs2 & shift) {
76             x |= do_swap(x, adjacent_masks[i], shift);
77         }
78     }
79 
80     return x;
81 }
82 
83 target_ulong HELPER(gorc)(target_ulong rs1, target_ulong rs2)
84 {
85     return do_gorc(rs1, rs2, TARGET_LONG_BITS);
86 }
87 
88 target_ulong HELPER(gorcw)(target_ulong rs1, target_ulong rs2)
89 {
90     return do_gorc(rs1, rs2, 32);
91 }
92 
93 target_ulong HELPER(clmul)(target_ulong rs1, target_ulong rs2)
94 {
95     target_ulong result = 0;
96 
97     for (int i = 0; i < TARGET_LONG_BITS; i++) {
98         if ((rs2 >> i) & 1) {
99             result ^= (rs1 << i);
100         }
101     }
102 
103     return result;
104 }
105 
106 target_ulong HELPER(clmulr)(target_ulong rs1, target_ulong rs2)
107 {
108     target_ulong result = 0;
109 
110     for (int i = 0; i < TARGET_LONG_BITS; i++) {
111         if ((rs2 >> i) & 1) {
112             result ^= (rs1 >> (TARGET_LONG_BITS - i - 1));
113         }
114     }
115 
116     return result;
117 }
118