blob: 7640b7590df1e45a0ef999091447435597b6c581 [file] [log] [blame]
Damien George04b91472014-05-03 23:27:38 +01001/*
2 * This file is part of the Micro Python project, http://micropython.org/
3 *
4 * The MIT License (MIT)
5 *
6 * Copyright (c) 2013, 2014 Damien P. George
7 *
8 * Permission is hereby granted, free of charge, to any person obtaining a copy
9 * of this software and associated documentation files (the "Software"), to deal
10 * in the Software without restriction, including without limitation the rights
11 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 * copies of the Software, and to permit persons to whom the Software is
13 * furnished to do so, subject to the following conditions:
14 *
15 * The above copyright notice and this permission notice shall be included in
16 * all copies or substantial portions of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24 * THE SOFTWARE.
25 */
26
Paul Sokolovsky8bc35162014-02-14 17:16:35 +020027#include <stdint.h>
Paul Sokolovsky1355cf42014-04-19 01:25:49 +030028#include <stdlib.h>
Paul Sokolovsky8bc35162014-02-14 17:16:35 +020029#include <assert.h>
30
31#include "misc.h"
32#include "mpconfig.h"
33#include "qstr.h"
34#include "obj.h"
Paul Sokolovsky8bc35162014-02-14 17:16:35 +020035#include "binary.h"
36
37// Helpers to work with binary-encoded data
38
Paul Sokolovsky1355cf42014-04-19 01:25:49 +030039int mp_binary_get_size(char struct_type, char val_type, uint *palign) {
40 int size = 0;
41 int align = 1;
42 switch (struct_type) {
43 case '<': case '>':
44 switch (val_type) {
45 case 'b': case 'B':
46 size = 1; break;
47 case 'h': case 'H':
48 size = 2; break;
49 case 'i': case 'I':
50 size = 4; break;
51 case 'l': case 'L':
52 size = 4; break;
53 case 'q': case 'Q':
54 size = 8; break;
55 }
56 break;
57 case '@': {
58 // TODO:
59 // The simplest heuristic for alignment is to align by value
60 // size, but that doesn't work for "bigger than int" types,
61 // for example, long long may very well have long alignment
62 // So, we introduce separate alignment handling, but having
63 // formal support for that is different from actually supporting
64 // particular (or any) ABI.
65 switch (val_type) {
66 case BYTEARRAY_TYPECODE:
67 case 'b': case 'B':
68 align = size = 1; break;
69 case 'h': case 'H':
70 align = size = sizeof(short); break;
71 case 'i': case 'I':
72 align = size = sizeof(int); break;
73 case 'l': case 'L':
74 align = size = sizeof(long); break;
75 case 'q': case 'Q':
76 // TODO: This is for x86
77 align = sizeof(int); size = sizeof(long long); break;
Paul Sokolovsky0f836ef2014-04-20 05:19:10 +030078 case 'P': case 'O':
79 align = size = sizeof(void*); break;
Paul Sokolovsky1355cf42014-04-19 01:25:49 +030080 }
81 }
Paul Sokolovskyc2033242014-02-14 20:21:50 +020082 }
Paul Sokolovsky1355cf42014-04-19 01:25:49 +030083 if (palign != NULL) {
84 *palign = align;
85 }
86 return size;
Paul Sokolovskyc2033242014-02-14 20:21:50 +020087}
88
Paul Sokolovskyef9124f2014-04-11 03:46:09 +030089mp_obj_t mp_binary_get_val_array(char typecode, void *p, int index) {
Paul Sokolovsky76f8ced2014-02-15 00:28:41 +020090 machine_int_t val = 0;
Paul Sokolovsky8bc35162014-02-14 17:16:35 +020091 switch (typecode) {
92 case 'b':
93 val = ((int8_t*)p)[index];
94 break;
95 case BYTEARRAY_TYPECODE:
96 case 'B':
97 val = ((uint8_t*)p)[index];
98 break;
99 case 'h':
100 val = ((int16_t*)p)[index];
101 break;
102 case 'H':
103 val = ((uint16_t*)p)[index];
104 break;
105 case 'i':
106 case 'l':
107 return mp_obj_new_int(((int32_t*)p)[index]);
108 case 'I':
109 case 'L':
110 return mp_obj_new_int_from_uint(((uint32_t*)p)[index]);
Damien George96056a62014-02-15 23:02:00 +0000111#if MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_NONE
Paul Sokolovsky8bc35162014-02-14 17:16:35 +0200112 case 'q':
113 case 'Q':
114 // TODO: Explode API more to cover signedness
115 return mp_obj_new_int_from_ll(((long long*)p)[index]);
116#endif
117#if MICROPY_ENABLE_FLOAT
118 case 'f':
119 return mp_obj_new_float(((float*)p)[index]);
120 case 'd':
121 return mp_obj_new_float(((double*)p)[index]);
122#endif
123 }
124 return MP_OBJ_NEW_SMALL_INT(val);
125}
126
Paul Sokolovsky6582d642014-04-10 22:19:32 +0300127#define is_signed(typecode) (typecode > 'Z')
Paul Sokolovsky0c43cf92014-04-11 03:47:21 +0300128mp_obj_t mp_binary_get_val(char struct_type, char val_type, byte **ptr) {
Paul Sokolovskye9db8402014-04-10 03:45:38 +0300129 byte *p = *ptr;
Paul Sokolovsky1355cf42014-04-19 01:25:49 +0300130 uint align;
131
132 int size = mp_binary_get_size(struct_type, val_type, &align);
133 if (struct_type == '@') {
134 // Make pointer aligned
135 p = (byte*)(((machine_uint_t)p + align - 1) & ~(align - 1));
136 #if MP_ENDIANNESS_LITTLE
137 struct_type = '<';
138 #else
139 struct_type = '>';
140 #endif
Paul Sokolovskye9db8402014-04-10 03:45:38 +0300141 }
Paul Sokolovsky6582d642014-04-10 22:19:32 +0300142
143 int delta;
Paul Sokolovsky0c43cf92014-04-11 03:47:21 +0300144 if (struct_type == '<') {
Paul Sokolovsky6582d642014-04-10 22:19:32 +0300145 delta = -1;
146 p += size - 1;
147 } else {
148 delta = 1;
149 }
150
151 machine_int_t val = 0;
Paul Sokolovsky0c43cf92014-04-11 03:47:21 +0300152 if (is_signed(val_type) && *p & 0x80) {
Paul Sokolovsky6582d642014-04-10 22:19:32 +0300153 val = -1;
154 }
155 for (uint i = 0; i < size; i++) {
156 val <<= 8;
157 val |= *p;
158 p += delta;
159 }
160
Paul Sokolovsky0c43cf92014-04-11 03:47:21 +0300161 *ptr += size;
Paul Sokolovsky0f836ef2014-04-20 05:19:10 +0300162 if (val_type == 'O') {
163 return (mp_obj_t)val;
164 } else if (is_signed(val_type)) {
Paul Sokolovsky6582d642014-04-10 22:19:32 +0300165 return mp_obj_new_int(val);
166 } else {
167 return mp_obj_new_int_from_uint(val);
168 }
Paul Sokolovskye9db8402014-04-10 03:45:38 +0300169}
170
Paul Sokolovsky62044602014-04-19 03:13:15 +0300171void mp_binary_set_val(char struct_type, char val_type, mp_obj_t val_in, byte **ptr) {
172 byte *p = *ptr;
173 uint align;
174
175 int size = mp_binary_get_size(struct_type, val_type, &align);
176 if (struct_type == '@') {
177 // Make pointer aligned
178 p = (byte*)(((machine_uint_t)p + align - 1) & ~(align - 1));
179 #if MP_ENDIANNESS_LITTLE
180 struct_type = '<';
181 #else
182 struct_type = '>';
183 #endif
184 }
185
186#if MP_ENDIANNESS_BIG
187#error Not implemented
188#endif
Paul Sokolovsky0f836ef2014-04-20 05:19:10 +0300189 machine_int_t val;
Paul Sokolovsky62044602014-04-19 03:13:15 +0300190 byte *in = (byte*)&val;
Paul Sokolovsky0f836ef2014-04-20 05:19:10 +0300191 switch (val_type) {
192 case 'O':
193 in = (byte*)&val_in;
194 break;
195 default:
196 val = mp_obj_get_int(val_in);
197 }
198
Paul Sokolovsky62044602014-04-19 03:13:15 +0300199 int in_delta, out_delta;
200 uint val_sz = MIN(size, sizeof(val));
201 if (struct_type == '>') {
202 in_delta = -1;
203 out_delta = 1;
204 in += val_sz - 1;
205 } else {
206 in_delta = out_delta = 1;
207 }
208
209 for (uint i = val_sz; i > 0; i--) {
210 *p = *in;
211 p += out_delta;
212 in += in_delta;
213 }
214
215 *ptr += size;
216}
217
Paul Sokolovskyef9124f2014-04-11 03:46:09 +0300218void mp_binary_set_val_array(char typecode, void *p, int index, mp_obj_t val_in) {
Damien George71e9bfa2014-04-18 23:28:12 +0100219 switch (typecode) {
220#if MICROPY_ENABLE_FLOAT
221 case 'f':
222 ((float*)p)[index] = mp_obj_float_get(val_in);
223 break;
224 case 'd':
225 ((double*)p)[index] = mp_obj_float_get(val_in);
226 break;
227#endif
228 default:
229 mp_binary_set_val_array_from_int(typecode, p, index, mp_obj_get_int(val_in));
Paul Sokolovsky8bc35162014-02-14 17:16:35 +0200230 }
Damien George71e9bfa2014-04-18 23:28:12 +0100231}
Paul Sokolovsky8bc35162014-02-14 17:16:35 +0200232
Damien George71e9bfa2014-04-18 23:28:12 +0100233void mp_binary_set_val_array_from_int(char typecode, void *p, int index, machine_int_t val) {
Paul Sokolovsky8bc35162014-02-14 17:16:35 +0200234 switch (typecode) {
235 case 'b':
236 ((int8_t*)p)[index] = val;
237 break;
238 case BYTEARRAY_TYPECODE:
239 case 'B':
240 val = ((uint8_t*)p)[index] = val;
241 break;
242 case 'h':
243 val = ((int16_t*)p)[index] = val;
244 break;
245 case 'H':
246 val = ((uint16_t*)p)[index] = val;
247 break;
248 case 'i':
249 case 'l':
250 ((int32_t*)p)[index] = val;
251 break;
252 case 'I':
253 case 'L':
254 ((uint32_t*)p)[index] = val;
255 break;
256#if MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_NONE
257 case 'q':
258 case 'Q':
259 assert(0);
260 ((long long*)p)[index] = val;
261 break;
262#endif
263#if MICROPY_ENABLE_FLOAT
264 case 'f':
Damien George71e9bfa2014-04-18 23:28:12 +0100265 ((float*)p)[index] = val;
Paul Sokolovsky8bc35162014-02-14 17:16:35 +0200266 break;
267 case 'd':
Damien George71e9bfa2014-04-18 23:28:12 +0100268 ((double*)p)[index] = val;
Paul Sokolovsky8bc35162014-02-14 17:16:35 +0200269 break;
270#endif
271 }
272}