blob: ee95d56e44a8c75cc4956e3fa9e2f7bb06daed4b [file] [log] [blame]
Paul Sokolovsky8bc35162014-02-14 17:16:35 +02001#include <stdint.h>
Paul Sokolovsky1355cf42014-04-19 01:25:49 +03002#include <stdlib.h>
Paul Sokolovsky8bc35162014-02-14 17:16:35 +02003#include <assert.h>
4
5#include "misc.h"
6#include "mpconfig.h"
7#include "qstr.h"
8#include "obj.h"
Paul Sokolovsky8bc35162014-02-14 17:16:35 +02009#include "binary.h"
10
11// Helpers to work with binary-encoded data
12
Paul Sokolovsky1355cf42014-04-19 01:25:49 +030013int mp_binary_get_size(char struct_type, char val_type, uint *palign) {
14 int size = 0;
15 int align = 1;
16 switch (struct_type) {
17 case '<': case '>':
18 switch (val_type) {
19 case 'b': case 'B':
20 size = 1; break;
21 case 'h': case 'H':
22 size = 2; break;
23 case 'i': case 'I':
24 size = 4; break;
25 case 'l': case 'L':
26 size = 4; break;
27 case 'q': case 'Q':
28 size = 8; break;
29 }
30 break;
31 case '@': {
32 // TODO:
33 // The simplest heuristic for alignment is to align by value
34 // size, but that doesn't work for "bigger than int" types,
35 // for example, long long may very well have long alignment
36 // So, we introduce separate alignment handling, but having
37 // formal support for that is different from actually supporting
38 // particular (or any) ABI.
39 switch (val_type) {
40 case BYTEARRAY_TYPECODE:
41 case 'b': case 'B':
42 align = size = 1; break;
43 case 'h': case 'H':
44 align = size = sizeof(short); break;
45 case 'i': case 'I':
46 align = size = sizeof(int); break;
47 case 'l': case 'L':
48 align = size = sizeof(long); break;
49 case 'q': case 'Q':
50 // TODO: This is for x86
51 align = sizeof(int); size = sizeof(long long); break;
52 }
53 }
Paul Sokolovskyc2033242014-02-14 20:21:50 +020054 }
Paul Sokolovsky1355cf42014-04-19 01:25:49 +030055 if (palign != NULL) {
56 *palign = align;
57 }
58 return size;
Paul Sokolovskyc2033242014-02-14 20:21:50 +020059}
60
Paul Sokolovskyef9124f2014-04-11 03:46:09 +030061mp_obj_t mp_binary_get_val_array(char typecode, void *p, int index) {
Paul Sokolovsky76f8ced2014-02-15 00:28:41 +020062 machine_int_t val = 0;
Paul Sokolovsky8bc35162014-02-14 17:16:35 +020063 switch (typecode) {
64 case 'b':
65 val = ((int8_t*)p)[index];
66 break;
67 case BYTEARRAY_TYPECODE:
68 case 'B':
69 val = ((uint8_t*)p)[index];
70 break;
71 case 'h':
72 val = ((int16_t*)p)[index];
73 break;
74 case 'H':
75 val = ((uint16_t*)p)[index];
76 break;
77 case 'i':
78 case 'l':
79 return mp_obj_new_int(((int32_t*)p)[index]);
80 case 'I':
81 case 'L':
82 return mp_obj_new_int_from_uint(((uint32_t*)p)[index]);
Damien George96056a62014-02-15 23:02:00 +000083#if MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_NONE
Paul Sokolovsky8bc35162014-02-14 17:16:35 +020084 case 'q':
85 case 'Q':
86 // TODO: Explode API more to cover signedness
87 return mp_obj_new_int_from_ll(((long long*)p)[index]);
88#endif
89#if MICROPY_ENABLE_FLOAT
90 case 'f':
91 return mp_obj_new_float(((float*)p)[index]);
92 case 'd':
93 return mp_obj_new_float(((double*)p)[index]);
94#endif
95 }
96 return MP_OBJ_NEW_SMALL_INT(val);
97}
98
Paul Sokolovsky6582d642014-04-10 22:19:32 +030099#define is_signed(typecode) (typecode > 'Z')
Paul Sokolovsky0c43cf92014-04-11 03:47:21 +0300100mp_obj_t mp_binary_get_val(char struct_type, char val_type, byte **ptr) {
Paul Sokolovskye9db8402014-04-10 03:45:38 +0300101 byte *p = *ptr;
Paul Sokolovsky1355cf42014-04-19 01:25:49 +0300102 uint align;
103
104 int size = mp_binary_get_size(struct_type, val_type, &align);
105 if (struct_type == '@') {
106 // Make pointer aligned
107 p = (byte*)(((machine_uint_t)p + align - 1) & ~(align - 1));
108 #if MP_ENDIANNESS_LITTLE
109 struct_type = '<';
110 #else
111 struct_type = '>';
112 #endif
Paul Sokolovskye9db8402014-04-10 03:45:38 +0300113 }
Paul Sokolovsky6582d642014-04-10 22:19:32 +0300114
115 int delta;
Paul Sokolovsky0c43cf92014-04-11 03:47:21 +0300116 if (struct_type == '<') {
Paul Sokolovsky6582d642014-04-10 22:19:32 +0300117 delta = -1;
118 p += size - 1;
119 } else {
120 delta = 1;
121 }
122
123 machine_int_t val = 0;
Paul Sokolovsky0c43cf92014-04-11 03:47:21 +0300124 if (is_signed(val_type) && *p & 0x80) {
Paul Sokolovsky6582d642014-04-10 22:19:32 +0300125 val = -1;
126 }
127 for (uint i = 0; i < size; i++) {
128 val <<= 8;
129 val |= *p;
130 p += delta;
131 }
132
Paul Sokolovsky0c43cf92014-04-11 03:47:21 +0300133 *ptr += size;
134 if (is_signed(val_type)) {
Paul Sokolovsky6582d642014-04-10 22:19:32 +0300135 return mp_obj_new_int(val);
136 } else {
137 return mp_obj_new_int_from_uint(val);
138 }
Paul Sokolovskye9db8402014-04-10 03:45:38 +0300139}
140
Paul Sokolovsky62044602014-04-19 03:13:15 +0300141void mp_binary_set_val(char struct_type, char val_type, mp_obj_t val_in, byte **ptr) {
142 byte *p = *ptr;
143 uint align;
144
145 int size = mp_binary_get_size(struct_type, val_type, &align);
146 if (struct_type == '@') {
147 // Make pointer aligned
148 p = (byte*)(((machine_uint_t)p + align - 1) & ~(align - 1));
149 #if MP_ENDIANNESS_LITTLE
150 struct_type = '<';
151 #else
152 struct_type = '>';
153 #endif
154 }
155
156#if MP_ENDIANNESS_BIG
157#error Not implemented
158#endif
159 machine_int_t val = mp_obj_int_get_checked(val_in);
160 byte *in = (byte*)&val;
161 int in_delta, out_delta;
162 uint val_sz = MIN(size, sizeof(val));
163 if (struct_type == '>') {
164 in_delta = -1;
165 out_delta = 1;
166 in += val_sz - 1;
167 } else {
168 in_delta = out_delta = 1;
169 }
170
171 for (uint i = val_sz; i > 0; i--) {
172 *p = *in;
173 p += out_delta;
174 in += in_delta;
175 }
176
177 *ptr += size;
178}
179
Paul Sokolovskyef9124f2014-04-11 03:46:09 +0300180void mp_binary_set_val_array(char typecode, void *p, int index, mp_obj_t val_in) {
Damien George71e9bfa2014-04-18 23:28:12 +0100181 switch (typecode) {
182#if MICROPY_ENABLE_FLOAT
183 case 'f':
184 ((float*)p)[index] = mp_obj_float_get(val_in);
185 break;
186 case 'd':
187 ((double*)p)[index] = mp_obj_float_get(val_in);
188 break;
189#endif
190 default:
191 mp_binary_set_val_array_from_int(typecode, p, index, mp_obj_get_int(val_in));
Paul Sokolovsky8bc35162014-02-14 17:16:35 +0200192 }
Damien George71e9bfa2014-04-18 23:28:12 +0100193}
Paul Sokolovsky8bc35162014-02-14 17:16:35 +0200194
Damien George71e9bfa2014-04-18 23:28:12 +0100195void mp_binary_set_val_array_from_int(char typecode, void *p, int index, machine_int_t val) {
Paul Sokolovsky8bc35162014-02-14 17:16:35 +0200196 switch (typecode) {
197 case 'b':
198 ((int8_t*)p)[index] = val;
199 break;
200 case BYTEARRAY_TYPECODE:
201 case 'B':
202 val = ((uint8_t*)p)[index] = val;
203 break;
204 case 'h':
205 val = ((int16_t*)p)[index] = val;
206 break;
207 case 'H':
208 val = ((uint16_t*)p)[index] = val;
209 break;
210 case 'i':
211 case 'l':
212 ((int32_t*)p)[index] = val;
213 break;
214 case 'I':
215 case 'L':
216 ((uint32_t*)p)[index] = val;
217 break;
218#if MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_NONE
219 case 'q':
220 case 'Q':
221 assert(0);
222 ((long long*)p)[index] = val;
223 break;
224#endif
225#if MICROPY_ENABLE_FLOAT
226 case 'f':
Damien George71e9bfa2014-04-18 23:28:12 +0100227 ((float*)p)[index] = val;
Paul Sokolovsky8bc35162014-02-14 17:16:35 +0200228 break;
229 case 'd':
Damien George71e9bfa2014-04-18 23:28:12 +0100230 ((double*)p)[index] = val;
Paul Sokolovsky8bc35162014-02-14 17:16:35 +0200231 break;
232#endif
233 }
234}