summaryrefslogtreecommitdiff
path: root/cesar/lib/read_word.h
blob: 1536f0fa0a2526bcc18a09973856f017d580ac99 (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
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
#ifndef LIB_READ_WORD_H_
#define LIB_READ_WORD_H_

/* Cesar project {{{
 *
 * Copyright (C) 2007 Spidcom
 *
 * <<<Licence>>>
 *
 * }}} */
/**
 * \file    lib/read_word.h
 * \brief   Read a word from the memory aligned on an integer address.
 * \ingroup lib
 *
 * Allows the system to get a value from the memory reading it word by word
 * and returning the value request from the user.
 *
 * Exemple : we need to get a 4 bytes word from the address 503 on the
 * memory it will calculate the address from the one it should start reading
 * the data to be aligned.
 * So it will read a word from the address 500 and the next one from the @
 * 504, it will take the last byte of the first word and concatante it with
 * the three bytes in the last word.
 * result = word2 << 24 | word1
 *
 */

/**
 * Read the necessary words from the memory and return the data requested.
 * Aware : if less than a word is request, it will need to be masqued to
 * desable the bytes which are note necessary.
 * Example : if you only need the two first bytes you should request:
 *   read_bytes_from_word (addr, 2) & 0xFFFF
 */
extern inline uint
read_bytes_from_word (u8 *addr, uint bytes)
{
    u8* addr_new;
    uint rest;
    uint result;

    uint word1;
    uint word2;

    dbg_assert (addr);
    dbg_assert (bytes <= 4);

    addr_new = (u8*) (((uint) addr) & ~3);
    rest = (((uint) addr) & 3);

    if (rest == 0)
    {
        result = *(u32*) (addr_new);
    }
    else if ((4-rest) >= bytes)
    {
        result = (*(u32*) (addr_new)) >> (8* rest);
    }
    else
    {
        word1 = (*(u32*) addr_new) >> (rest * 8);
        word2 = (*(u32*) (addr_new + 4));

        result = word2 << (4 - rest) * 8 | word1;
    }

    return (result & BITS_ONES (bytes * 8));
}

/**
 * Read u64 from two words.
 *
 * \param  addr  the address to read the next two 48 bits.
 * \return u64 masked on 48 bits.
 */
u64 read_u64_from_word (u8 *addr);

/**
 * Read u56 from two words.
 *
 * \param  addr  the address to read the next two 48 bits.
 * \return u64 masked on 48 bits.
 */
u64 read_u56_from_word (u8 *addr);

/**
 * Read u48 from two words.
 *
 * \param  addr  the address to read the next two 48 bits.
 * \return u64 masked on 48 bits.
 */
u64 read_u48_from_word (u8 *addr);

/**
 * Read 40 bits from the word.
 *
 * \param  addr the address from the one the value should be read.
 * \return  the u64
 */
u64 read_u40_from_word (u8 *addr);


/**
 * Read 32 bits from the word.
 *
 * \param  addr the address from the one the value should be read.
 * \return  the u32
 */
uint read_u32_from_word (u8 *addr);

/**
 * Read 24 bits from the word.
 *
 * \param  addr the address from the one the value should be read.
 * \return  the u32 with the last byte set to 0
 */
uint read_u24_from_word (u8 *addr);

/**
 * Read 16 bits from the word.
 *
 * \param  addr the address from the one the value should be read.
 * \return  the u32 with the last byte set to 0
 */
uint read_u16_from_word (u8 *addr);

/**
 * Read 8 bits from the word.
 *
 * \param  addr the address from the one the value should be read.
 * \return  uint with only one byte filled.
 */
uint read_u8_from_word (u8 *addr);

#endif /*LIB_READ_WORD_H_*/