forked from microsoft/devicescript
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathdevs_internal.h
More file actions
395 lines (316 loc) · 12 KB
/
devs_internal.h
File metadata and controls
395 lines (316 loc) · 12 KB
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
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
#pragma once
#if defined(__GNUC__) && __GNUC__ >= 10
#pragma GCC diagnostic ignored "-Wzero-length-bounds"
#endif
#include "devicescript.h"
#include "jd_protocol.h"
#include "jd_client.h"
#include "jacdac/dist/c/devicescriptcondition.h"
#include "jacdac/dist/c/devicescriptmanager.h"
#include "jacdac/dist/c/devicescriptdebugger.h"
#include "devs_format.h"
#include "devs_img.h"
#include "devs_regcache.h"
#include "devs_pack.h"
#include "devs_trace.h"
#include "devs_objects.h"
// this can't be more than a week; unit = ms
#define DEVS_MAX_REG_VALIDITY (15 * 60 * 1000)
#define DEVS_MAX_STEPS (128 * 1024)
#define DEVS_NO_ROLE 0xffff
#define DEVS_MAX_STACK_TRACE_FRAMES 16
typedef struct devs_activation devs_activation_t;
#define DEVS_PKT_KIND_NONE 0
#define DEVS_PKT_KIND_REG_GET 1
#define DEVS_PKT_KIND_SEND_PKT 2
#define DEVS_PKT_KIND_SEND_RAW_PKT 3
#define DEVS_PKT_KIND_SUSPENDED 4
#define DEVS_PKT_KIND_AWAITING 5
typedef void (*devs_resume_cb_t)(devs_ctx_t *ctx, void *userdata);
typedef struct devs_fiber {
struct devs_fiber *next;
union {
struct {
uint8_t *data;
uint8_t size;
} send_pkt;
struct {
uint16_t string_idx;
uint16_t resend_timeout;
} reg_get;
value_t v;
uint8_t *awaiting;
} pkt_data;
uint8_t pkt_kind : 4;
uint8_t pending : 1;
uint8_t role_wkp : 1;
uint8_t reserved_flag : 2;
uint8_t stack_depth;
uint16_t role_idx;
uint16_t service_command;
uint16_t bottom_function_idx; // the id of function at the bottom of the stack
uint32_t wake_time;
uint32_t handle_tag;
value_t ret_val;
devs_activation_t *activation;
struct devs_ctx *ctx;
devs_resume_cb_t resume_cb;
void *resume_data;
} devs_fiber_t;
static inline bool devs_fiber_uses_pkt_data_v(devs_fiber_t *fib) {
// return fib->pkt_kind == DEVS_PKT_KIND_SEND_RAW_PKT;
return false;
}
#define DEVS_CTX_FLAG_BUSY 0x01
#define DEVS_CTX_LOGGING_ENABLED 0x02
#define DEVS_CTX_FREEING_ROLES 0x04
#define DEVS_CTX_TRACE_DISABLED 0x08
#define DEVS_CTX_PENDING_RESUME 0x10
#define DEVS_CTX_PENDING_ROLES 0x20
#define DEVS_CTX_STEP_EN 0x01
#define DEVS_CTX_STEP_BRK 0x02
#define DEVS_CTX_STEP_IN 0x04
#define DEVS_CTX_STEP_OUT 0x08
#define DEVS_CTX_STEP_HALT 0x80
typedef struct {
value_t name;
jd_role_t *jdrole;
devs_map_t *attached;
} devs_role_t;
#define DEVS_BRK_FLAG_STEP 0x01
typedef struct {
devs_pc_t pc;
uint8_t flags;
uint8_t reserved;
} devs_brk_t;
// has to be power of 2
#define DEVS_BRK_HASH_SIZE 32
// has to be under 0xff
#define DEVS_BRK_MAX_COUNT 0xf0
#define DEVS_DBG_BRK_UNHANDLED_EXN 0x01
#define DEVS_DBG_BRK_HANDLED_EXN 0x02
struct devs_ctx {
value_t *globals;
uint16_t opstack;
uint8_t flags;
uint8_t step_flags;
uint16_t error_code;
devs_pc_t error_pc;
value_t binop[2];
double binop_f[2];
value_t diag_field;
value_t exn_val;
devs_pc_t jmp_pc;
uint8_t stack_top;
uint8_t stack_top_for_gc;
uint8_t _num_builtin_protos;
uint8_t in_throw;
uint8_t suspension;
uint8_t dbg_en;
uint8_t ignore_brk;
uint8_t dbg_flags;
uint8_t num_pins;
uint16_t num_roles;
uint32_t literal_int;
value_t the_stack[DEVS_MAX_STACK_DEPTH];
devs_short_map_t *fn_protos;
devs_short_map_t *fn_values;
devs_short_map_t *spec_protos;
devs_img_t img;
devs_activation_t *curr_fn;
devs_fiber_t *curr_fiber;
devs_fiber_t *fibers;
devs_role_t **roles;
// use devs_get_builtin_object()
devs_map_t **_builtin_protos;
uint32_t *buffers;
uint64_t _now_long;
uint32_t _logged_now;
uint32_t fiber_handle_tag;
uint32_t send_pkt_throttle;
uint32_t num_throttled_pkts;
uint32_t last_warning;
uint32_t ctx_seq_no;
devs_gc_t *gc;
devs_cfg_t cfg;
struct devs_pin_state *pin_state;
devs_activation_t *step_fn;
devs_brk_t *brk_list;
uint16_t brk_count;
uint8_t brk_jump_tbl[DEVS_BRK_HASH_SIZE];
uint8_t program_hash[JD_SHA256_HASH_BYTES];
union {
jd_frame_t frame;
jd_packet_t packet;
};
devs_regcache_t regcache;
};
struct devs_activation {
devs_gc_object_t gc;
devs_pc_t pc;
devs_pc_t maxpc;
devs_activation_t *closure;
devs_activation_t *caller;
const devs_function_desc_t *func;
value_t slots[0];
};
typedef struct devs_pin_state {
value_t obj;
const char *label;
uint8_t id;
uint8_t gpio;
uint8_t mode;
uint16_t capabilities;
} devs_pin_state_t;
static inline uint32_t devs_now(devs_ctx_t *ctx) {
return (uint32_t)ctx->_now_long;
}
static inline bool devs_trace_enabled(devs_ctx_t *ctx) {
return (ctx->flags & DEVS_CTX_TRACE_DISABLED) == 0;
}
static inline bool devs_is_suspended(devs_ctx_t *ctx) {
return ctx->suspension != JD_DEVS_DBG_SUSPENSION_TYPE_NONE;
}
void devs_panic(devs_ctx_t *ctx, unsigned code);
value_t _devs_invalid_program(devs_ctx_t *ctx, unsigned code);
/**
* Indicates an invalid bytecode program.
* The compiler should never generate code that triggers this.
* Next free error: 60132
*/
static inline value_t devs_invalid_program(devs_ctx_t *ctx, unsigned code) {
return _devs_invalid_program(ctx, code - 60000);
}
// strformat.c
size_t devs_strformat(devs_ctx_t *ctx, const char *fmt, size_t fmtlen, char *dst, size_t dstlen,
value_t *args, size_t numargs, size_t *ulen);
// jdiface.c
bool devs_jd_should_run(devs_fiber_t *fiber);
value_t devs_jd_pkt_capture(devs_ctx_t *ctx, unsigned role_idx);
void devs_jd_wake_role(devs_ctx_t *ctx, unsigned role_idx, bool is_role_evt);
void devs_jd_send_cmd(devs_ctx_t *ctx, unsigned role_idx, unsigned code);
void devs_jd_send_raw(devs_ctx_t *ctx);
void devs_jd_get_register(devs_ctx_t *ctx, unsigned role_idx, unsigned code, unsigned timeout,
unsigned arg);
void devs_jd_process_pkt(devs_ctx_t *ctx, jd_device_service_t *serv, jd_packet_t *pkt);
void devs_jd_reset_packet(devs_ctx_t *ctx);
void devs_jd_init_roles(devs_ctx_t *ctx);
void devs_jd_free_roles(devs_ctx_t *ctx);
int devs_jd_alloc_role(devs_ctx_t *ctx, value_t name, uint32_t srv_class);
void devs_jd_role_changed(devs_ctx_t *ctx, jd_role_t *role);
void devs_jd_clear_pkt_kind(devs_fiber_t *fib);
void devs_jd_send_logmsg(devs_ctx_t *ctx, char lev, value_t str);
uint64_t devs_jd_server_device_id(void);
void devs_jd_after_user(devs_ctx_t *ctx);
// fibers.c
void devs_fiber_set_wake_time(devs_fiber_t *fiber, unsigned time);
void devs_fiber_sleep(devs_fiber_t *fiber, unsigned time);
void devs_fiber_termiante(devs_fiber_t *fiber);
void devs_fiber_yield(devs_ctx_t *ctx);
void devs_fiber_await(devs_fiber_t *fib, uint8_t *awaiting);
void devs_fiber_await_done(uint8_t *awaiting);
// if `args` is passed, `numparams==0`
// otherwise, `numparams` arguments are sought on the_stack
int devs_fiber_call_function(devs_fiber_t *fiber, unsigned numparams, devs_array_t *args);
void devs_fiber_return_from_call(devs_fiber_t *fiber, devs_activation_t *act);
devs_fiber_t *devs_fiber_start(devs_ctx_t *ctx, unsigned numargs, unsigned op);
devs_fiber_t *devs_fiber_by_tag(devs_ctx_t *ctx, unsigned tag);
devs_fiber_t *devs_fiber_by_fidx(devs_ctx_t *ctx, unsigned fidx);
void devs_fiber_run(devs_fiber_t *fiber);
void devs_fiber_poke(devs_ctx_t *ctx);
void devs_fiber_sync_now(devs_ctx_t *ctx);
void devs_fiber_free_all_fibers(devs_ctx_t *ctx);
unsigned devs_fiber_get_max_sleep(devs_ctx_t *ctx);
// vm_main.c
void devs_vm_exec_opcodes(devs_ctx_t *ctx);
bool devs_in_vm_loop(devs_ctx_t *ctx);
uint8_t devs_fetch_opcode(devs_activation_t *frame, devs_ctx_t *ctx);
int devs_vm_set_breakpoint(devs_ctx_t *ctx, unsigned pc, unsigned flags);
bool devs_vm_clear_breakpoint(devs_ctx_t *ctx, unsigned pc);
void devs_vm_clear_breakpoints(devs_ctx_t *ctx);
void devs_vm_suspend(devs_ctx_t *ctx, unsigned cause);
void devs_vm_halt(devs_ctx_t *ctx);
int devs_vm_resume(devs_ctx_t *ctx);
void devs_vm_set_debug(devs_ctx_t *ctx, bool en);
value_t devs_buffer_op(devs_ctx_t *ctx, uint32_t fmt0, uint32_t offset, value_t buffer,
value_t *setv);
double devs_read_number(void *data, unsigned bufsz, uint16_t fmt0);
value_t devs_buffer_decode(devs_ctx_t *ctx, uint32_t fmt0, uint8_t **buf, unsigned len);
unsigned devs_buffer_encode(devs_ctx_t *ctx, uint32_t fmt0, uint8_t *data, unsigned len, value_t v);
value_t devs_packet_decode(devs_ctx_t *ctx, const devs_packet_spec_t *pkt, uint8_t *dp,
unsigned len);
void *devs_try_alloc(devs_ctx_t *ctx, uint32_t size);
void devs_free(devs_ctx_t *ctx, void *ptr);
void devs_oom(devs_ctx_t *ctx, unsigned size);
value_t devs_make_closure(devs_ctx_t *ctx, devs_activation_t *closure, unsigned fnidx);
int devs_get_fnidx(devs_ctx_t *ctx, value_t src, value_t *this_val, devs_activation_t **closure);
devs_map_t *devs_get_role_proto(devs_ctx_t *ctx, unsigned roleidx);
devs_map_t *devs_get_spec_proto(devs_ctx_t *ctx, uint32_t spec_idx);
#define TODO JD_PANIC
// for impl_*.c
bool devs_arg_bool(devs_ctx_t *ctx, unsigned idx);
int32_t devs_arg_int(devs_ctx_t *ctx, unsigned idx);
int32_t devs_arg_int_defl(devs_ctx_t *ctx, unsigned idx, int32_t defl);
double devs_arg_double(devs_ctx_t *ctx, unsigned idx);
const char *devs_arg_utf8_with_conv(devs_ctx_t *ctx, unsigned idx, unsigned *sz);
static inline value_t devs_arg(devs_ctx_t *ctx, unsigned idx) {
return ctx->the_stack[idx + 1];
}
static inline value_t devs_arg_self(devs_ctx_t *ctx) {
return ctx->the_stack[0];
}
devs_map_t *devs_arg_self_map(devs_ctx_t *ctx);
void devs_ret_double(devs_ctx_t *ctx, double v);
void devs_ret_int(devs_ctx_t *ctx, int v);
void devs_ret_bool(devs_ctx_t *ctx, bool v);
void devs_ret_gc_ptr(devs_ctx_t *ctx, void *v);
static inline void devs_ret(devs_ctx_t *ctx, value_t v) {
// curr_fiber might be reset by panic; we don't want to crash
if (ctx->curr_fiber)
ctx->curr_fiber->ret_val = v;
}
static inline bool devs_did_yield(devs_ctx_t *ctx) {
return ctx->curr_fiber == NULL;
}
void devs_setup_resume(devs_fiber_t *f, devs_resume_cb_t cb, void *userdata);
int devs_clamp_size(int v, int max);
static inline devs_role_t *devs_role(devs_ctx_t *ctx, unsigned roleidx) {
if (roleidx < ctx->num_roles)
return ctx->roles[roleidx];
return NULL;
}
devs_role_t *devs_role_or_fail(devs_ctx_t *ctx, unsigned roleidx);
jd_device_service_t *devs_role_service(devs_ctx_t *ctx, unsigned roleidx);
const char *devs_role_name(devs_ctx_t *ctx, unsigned idx);
#define DEVS_DERIVE(cls, basecls) /* */
// try.c
void devs_push_tryframe(devs_activation_t *frame, devs_ctx_t *ctx, int pc);
int devs_pop_tryframe(devs_activation_t *frame, devs_ctx_t *ctx);
value_t devs_capture_stack(devs_ctx_t *ctx);
void devs_unhandled_exn(devs_ctx_t *ctx, value_t exn);
#define DEVS_THROW_NO_STACK 0x0001
#define DEVS_THROW_INTERNAL 0x0002
void devs_throw(devs_ctx_t *ctx, value_t exn, unsigned flags);
value_t devs_throw_type_error(devs_ctx_t *ctx, const char *format, ...);
value_t devs_throw_range_error(devs_ctx_t *ctx, const char *format, ...);
value_t devs_throw_syntax_error(devs_ctx_t *ctx, const char *format, ...);
value_t devs_throw_generic_error(devs_ctx_t *ctx, const char *format, ...);
value_t devs_throw_not_supported_error(devs_ctx_t *ctx, const char *what);
value_t devs_throw_expecting_error_ext(devs_ctx_t *ctx, const char *what, value_t v);
value_t devs_throw_expecting_error(devs_ctx_t *ctx, unsigned builtinstr, value_t v);
value_t devs_throw_too_big_error(devs_ctx_t *ctx, unsigned builtinstr);
void devs_process_throw(devs_ctx_t *ctx);
value_t devs_alloc_error(devs_ctx_t *ctx, unsigned proto_idx, const char *format, va_list arg);
const devs_function_desc_t *devs_function_by_pc(devs_ctx_t *ctx, unsigned pc);
void devs_dump_stack(devs_ctx_t *ctx, value_t stack);
void devs_dump_exception(devs_ctx_t *ctx, value_t exn);
void devs_track_exception(devs_ctx_t *ctx);
#define DEVS_CHECK_CTX_FREE(ctx) JD_ASSERT(!devs_in_vm_loop(ctx))
#ifndef JD_LED_STRIP
#define JD_LED_STRIP 0
#endif
// external APIs
#if JD_LED_STRIP
int devs_led_strip_send(devs_ctx_t *ctx, uint8_t pin, const uint8_t *data, unsigned size,
cb_t donefn);
#endif