xref: /openbmc/qemu/target/riscv/bitmanip_helper.c (revision d7a4fcb0)
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 target_ulong HELPER(clmul)(target_ulong rs1, target_ulong rs2)
68 {
69     target_ulong result = 0;
70 
71     for (int i = 0; i < TARGET_LONG_BITS; i++) {
72         if ((rs2 >> i) & 1) {
73             result ^= (rs1 << i);
74         }
75     }
76 
77     return result;
78 }
79 
80 target_ulong HELPER(clmulr)(target_ulong rs1, target_ulong rs2)
81 {
82     target_ulong result = 0;
83 
84     for (int i = 0; i < TARGET_LONG_BITS; i++) {
85         if ((rs2 >> i) & 1) {
86             result ^= (rs1 >> (TARGET_LONG_BITS - i - 1));
87         }
88     }
89 
90     return result;
91 }
92