summaryrefslogtreecommitdiffstats
path: root/target/s390x/tcg/vec.h
blob: 8d095efcfc6f70af701e27efd315450810b41d5c (plain) (blame)
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
/*
 * QEMU TCG support -- s390x vector utilitites
 *
 * Copyright (C) 2019 Red Hat Inc
 *
 * Authors:
 *   David Hildenbrand <david@redhat.com>
 *
 * This work is licensed under the terms of the GNU GPL, version 2 or later.
 * See the COPYING file in the top-level directory.
 */
#ifndef S390X_VEC_H
#define S390X_VEC_H

#include "tcg/tcg.h"

typedef union S390Vector {
    uint64_t doubleword[2];
    uint32_t word[4];
    uint16_t halfword[8];
    uint8_t byte[16];
} S390Vector;

/*
 * Each vector is stored as two 64bit host values. So when talking about
 * byte/halfword/word numbers, we have to take care of proper translation
 * between element numbers.
 *
 * Big Endian (target/possible host)
 * B:  [ 0][ 1][ 2][ 3][ 4][ 5][ 6][ 7] - [ 8][ 9][10][11][12][13][14][15]
 * HW: [     0][     1][     2][     3] - [     4][     5][     6][     7]
 * W:  [             0][             1] - [             2][             3]
 * DW: [                             0] - [                             1]
 *
 * Little Endian (possible host)
 * B:  [ 7][ 6][ 5][ 4][ 3][ 2][ 1][ 0] - [15][14][13][12][11][10][ 9][ 8]
 * HW: [     3][     2][     1][     0] - [     7][     6][     5][     4]
 * W:  [             1][             0] - [             3][             2]
 * DW: [                             0] - [                             1]
 */
#if !HOST_BIG_ENDIAN
#define H1(x)  ((x) ^ 7)
#define H2(x)  ((x) ^ 3)
#define H4(x)  ((x) ^ 1)
#else
#define H1(x)  (x)
#define H2(x)  (x)
#define H4(x)  (x)
#endif

static inline uint8_t s390_vec_read_element8(const S390Vector *v, uint8_t enr)
{
    g_assert(enr < 16);
    return v->byte[H1(enr)];
}

static inline uint16_t s390_vec_read_element16(const S390Vector *v, uint8_t enr)
{
    g_assert(enr < 8);
    return v->halfword[H2(enr)];
}

static inline uint32_t s390_vec_read_element32(const S390Vector *v, uint8_t enr)
{
    g_assert(enr < 4);
    return v->word[H4(enr)];
}

static inline uint64_t s390_vec_read_element64(const S390Vector *v, uint8_t enr)
{
    g_assert(enr < 2);
    return v->doubleword[enr];
}

static inline uint64_t s390_vec_read_element(const S390Vector *v, uint8_t enr,
                                             uint8_t es)
{
    switch (es) {
    case MO_8:
        return s390_vec_read_element8(v, enr);
    case MO_16:
        return s390_vec_read_element16(v, enr);
    case MO_32:
        return s390_vec_read_element32(v, enr);
    case MO_64:
        return s390_vec_read_element64(v, enr);
    default:
        g_assert_not_reached();
    }
}

static inline void s390_vec_write_element8(S390Vector *v, uint8_t enr,
                                           uint8_t data)
{
    g_assert(enr < 16);
    v->byte[H1(enr)] = data;
}

static inline void s390_vec_write_element16(S390Vector *v, uint8_t enr,
                                            uint16_t data)
{
    g_assert(enr < 8);
    v->halfword[H2(enr)] = data;
}

static inline void s390_vec_write_element32(S390Vector *v, uint8_t enr,
                                            uint32_t data)
{
    g_assert(enr < 4);
    v->word[H4(enr)] = data;
}

static inline void s390_vec_write_element64(S390Vector *v, uint8_t enr,
                                            uint64_t data)
{
    g_assert(enr < 2);
    v->doubleword[enr] = data;
}

static inline void s390_vec_write_element(S390Vector *v, uint8_t enr,
                                          uint8_t es, uint64_t data)
{
    switch (es) {
    case MO_8:
        s390_vec_write_element8(v, enr, data);
        break;
    case MO_16:
        s390_vec_write_element16(v, enr, data);
        break;
    case MO_32:
        s390_vec_write_element32(v, enr, data);
        break;
    case MO_64:
        s390_vec_write_element64(v, enr, data);
        break;
    default:
        g_assert_not_reached();
    }
}

#endif /* S390X_VEC_H */