summaryrefslogtreecommitdiff
path: root/lib/read_word.h
blob: cb8e7bea4d6634e14667ba20f995be0f1f185c0b (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
#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;
}

/**
 * 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 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_*/