summaryrefslogtreecommitdiffstats
path: root/src/import/hwpf/fapi2/docs/topics/Buffers.md
blob: 4b69375da6f0527c82e25112b343fd74cee5ab30 (plain)
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
# Buffers

Buffers can be of two styles; buffers made from an integral type and
buffers made from a container. Integral type buffers, while limited
in size, can be tightly controlled via the compiler by using c++
templates.

C++ templates allow for very explicit control, but yield a
syntax different than the FAPI 1.x functional interface. For example,
a fapi2::buffer is defined as having a type:

    fapi2::buffer<uint64_t> new_buffer;

defines a buffer with exactly 64 bits, and can be manipulated by the
compiler as a single integral value. These implementations result
in concise instruction streams, and a platform may choose to implement
all or some or none of the integral buffer types.

Buffers which have containers as their underlying implementation
are found in the class fapi2::variable_buffer. variable_buffer is little
more than

     fapi2::buffer<fapi2::bits_container>

where bits_container is the typedef of the underlying container (a
vector of uint32_t, for example)
### Simple uint64_t buffer
    const uint32_t x = 2;
    // this data buffer will contain data in a uint64_t type
    fapi2::buffer<uint64_t> data;
    // Set using the template and a constant
    data.setBit<x>();
    // Set using the template and a value
    data.setBit<3>();
    // Set using the function interface, and a value
    data.setBit(1);
    // compiler gets smart.
    // movabs $0x7000000000000000,%rsi

### variable_buffer, same thing
    const uint32_t x = 2;
    // Note: only 15 bits long
    fapi2::variable_buffer data(15);
    data.setBit(x);
    data.setBit(3);
    data.setBit(1);

### Method chaining
Buffers support method chaining. So, rather than this
    buffer<T> mask;
    mask.setBit<B>();
    mask.invert();
    my_buffer &= mask;

You can do

    my_buffer &= buffer<T>().setBit<B>.invert();

### Buffer operations
    // An 8 bit buffer, initialized with a value
    fapi2::buffer<uint8_t> eight_bits = 0xAA;
    fapi2::buffer<uint8_t> another_eight;
    fapi2::buffer<uint16_t> sixteen_bits;
    // You can't assign an 8 bit buffer to a 16 bit buffer.
    sixteen_bits = eight_bits; ERROR
    // But you can assign buffers of the same type
    another_eight = eight_bits;
    // You can assign constants (or other known values) directly:
    sixteen_bits = 0xAABB;

### Variable buffer operations
    fapi2::variable_buffer data(16);
    // Very large buffers can be initialized rather than set bit by bit.
    const fapi2::variable_buffer bit_settings_known(
        {0xFFFF0000, 0xAABBF0F0,
         0xFFFF0000, 0xAABBF0F0,
         0xFFFF0000, 0xAABBF0F0,});
    // Assignment will expand or shrink the size automatically.
    data = bit_settings_known;
    // You can assign directly to the buffer:
    fapi2::variable_buffer other_bits;
    const fapi2::container_unit x = 0xFF00AA55;
    other_bits = {x, 0xDEADBEEF};

### Create a buffer of 32 bits and initialize it.

    fapi2::buffer<uint32_t> data(0xAA55FFAA);

### Flip bit 0

    data.flipBit<0>();

### Invert the buffer

    data.invert();

### Reset it's value

    data = 0xFFFFFFFF;

### Create a mask using an anonymous object

    my_buffer &= buffer<T>().setBit<B>.invert();

### Create an 8 bit buffer, initialize it, and flip some bits around

    fapi2::buffer<uint8_t>(0xA5).flipBit<5>().flipBit<5>() == 0xA5;
OpenPOWER on IntegriCloud