circuitpython/extmod/multiverse_support.c
Jeff Epler e188517863 Continue improving defs
& do some testing of mkapi-generated bindings
2025-07-31 15:52:17 -05:00

219 lines
7.3 KiB
C

#include "extmod/multiverse_support.h"
#if __m68k
#define lm_base ((char *)0)
#else
char lm_base[65536];
#endif
MP_DECLARE_CTYPES_STRUCT(Point_obj);
#define DEFINE_PTR_SCALAR(type_c, tag) \
const mp_rom_obj_tuple_t type_c##_ptr_tuple = ROM_TUPLE(MP_ROM_INT(UCTYPE_AGG(PTR)), MP_ROM_INT(UCTYPE_TYPE(tag))); \
MP_DEFINE_CTYPES_STRUCT(type_c##_obj, MP_QSTR_##type_c, MP_ROM_PTR((void *)&type_c##_ptr_tuple), LAYOUT_NATIVE)
DEFINE_PTR_SCALAR(bool, UINT8);
DEFINE_PTR_SCALAR(char, UINT8);
DEFINE_PTR_SCALAR(uint8_t, UINT8);
DEFINE_PTR_SCALAR(uint16_t, UINT16);
DEFINE_PTR_SCALAR(uint32_t, UINT32);
DEFINE_PTR_SCALAR(uint64_t, UINT64);
DEFINE_PTR_SCALAR(int8_t, INT8);
DEFINE_PTR_SCALAR(int16_t, INT16);
DEFINE_PTR_SCALAR(int32_t, INT32);
DEFINE_PTR_SCALAR(int64_t, INT64);
DEFINE_PTR_SCALAR(float, FLOAT32);
DEFINE_PTR_SCALAR(double, FLOAT64);
static mp_uint_t get_agg_type(mp_obj_tuple_t *sub) {
mp_int_t offset = MP_OBJ_SMALL_INT_VALUE(sub->items[0]);
mp_uint_t agg_type = GET_TYPE(offset, AGG_TYPE_BITS);
return agg_type;
}
static mp_uint_t get_val_type(mp_obj_tuple_t *sub) {
mp_int_t offset = MP_OBJ_SMALL_INT_VALUE(sub->items[1]);
mp_uint_t val_type = GET_TYPE(offset, VAL_TYPE_BITS);
return val_type;
}
static bool arg_compatible(const mp_obj_t arg_descr, const mp_obj_t type_descr) {
// types are compatible if their descriptors are equal
if (mp_obj_equal(arg_descr, type_descr)) {
return true;
}
// Otherwise, they are compatible if
// * type is a pointer to T, and
// * arg is a pointer to T or array of T
if (!mp_obj_is_type(type_descr, &mp_type_tuple)) {
return false;
}
mp_obj_tuple_t *type_sub = MP_OBJ_TO_PTR(type_descr);
if (get_agg_type(type_descr) != PTR) {
return false;
}
if (!mp_obj_is_type(arg_descr, &mp_type_tuple)) {
return false;
}
mp_obj_tuple_t *arg_sub = MP_OBJ_TO_PTR(arg_descr);
if (arg_sub->len == 2) {
// argument is a pointer-to-scalar or array-of-scalar, compare scalar types
return get_val_type(type_sub) == get_val_type(arg_sub);
} else {
// argument is array-of-struct, compare descriptors
return mp_obj_equal(type_sub->items[1], arg_sub->items[2]);
}
}
static bool deref_compatible(const mp_obj_t arg_descr, const mp_obj_t type_descr) {
if (!mp_obj_is_type(arg_descr, &mp_type_tuple)) {
return false;
}
mp_obj_tuple_t *arg_sub = MP_OBJ_TO_PTR(arg_descr);
if (get_agg_type(arg_sub) != PTR) {
return false;
}
bool r = mp_obj_equal(type_descr, arg_sub->items[1]);
return r;
}
#define mp_obj_get_type_qstr(o_in) ((qstr)(mp_obj_get_type((o_in))->name))
void *to_struct_helper(mp_obj_t obj, const mp_obj_type_t *struct_type, bool is_const, qstr fieldname) {
if (obj == mp_const_none) {
return NULL;
}
if (struct_type && !mp_obj_is_type(obj, struct_type)) {
mp_obj_t arg_descr = uctypes_get_struct_desc(obj);
mp_obj_t type_descr = uctypes_get_struct_desc(MP_OBJ_FROM_PTR(struct_type));
if (deref_compatible(arg_descr, MP_OBJ_FROM_PTR(struct_type))) {
// Consider the case of
// ```py
// w = WindowMgr.NewWindow(...)
// qd.SetPort(w)
// ```
// which would otherwise say `TypeError: p must be of type GrafPort, not GrafPtr
//
// (currently) mkapi treats the argument to SetPort
// as a GrafPort. But `GrafPtr` is a typedef to `GrafPort*`. It might be
// better to fix this in mkapi, but instead cater here...
mp_buffer_info_t bufinfo = {0};
mp_get_buffer_raise(obj, &bufinfo, is_const ? MP_BUFFER_READ : MP_BUFFER_READ | MP_BUFFER_WRITE);
void *result = *(void **)bufinfo.buf;
return result;
}
if (!arg_compatible(arg_descr, type_descr)) {
mp_raise_msg_varg(&mp_type_TypeError,
MP_ERROR_TEXT("%q must be of type %q, not %q"), fieldname, (qstr)struct_type->name, mp_obj_get_type_qstr(obj));
}
}
mp_buffer_info_t bufinfo = {0};
mp_get_buffer_raise(obj, &bufinfo, is_const ? MP_BUFFER_READ : MP_BUFFER_READ | MP_BUFFER_WRITE);
return bufinfo.buf;
}
static const mp_rom_map_elem_t empty_table[] = {};
static MP_DEFINE_CONST_DICT(empty_dict, empty_table);
mp_obj_t from_struct_helper(void *buf, const mp_obj_type_t *type) {
if (type) {
mp_obj_t args[] = { mp_obj_new_int((mp_uint_t)buf), MP_OBJ_FROM_PTR(type) };
return uctypes_struct_make_new(type, 2, 0, args);
} else {
mp_obj_t args[] = { mp_obj_new_int((mp_uint_t)buf), MP_OBJ_FROM_PTR(&empty_dict) };
return uctypes_struct_make_new(&uctypes_struct_type, 2, 0, args);
}
}
void *to_scalar_helper(mp_obj_t obj, size_t objsize, bool is_const) {
if (mp_obj_is_int(obj)) {
return (void *)mp_obj_get_int_truncated(obj);
}
mp_buffer_info_t bufinfo = {0};
mp_get_buffer_raise(obj, &bufinfo, is_const ? MP_BUFFER_READ : MP_BUFFER_READ | MP_BUFFER_WRITE);
if (objsize > 1 && bufinfo.len != objsize) {
mp_raise_ValueError(MP_ERROR_TEXT("buffer has wrong length"));
}
return bufinfo.buf;
}
mp_obj_t from_scalar_helper(void *buf, size_t objsize, bool is_signed_hint) {
return mp_obj_new_int_from_uint(*(unsigned long *)buf);
}
mp_obj_t LMGet_common(long address, size_t objsize, mp_obj_t arg) {
if (arg == mp_const_none) {
return mp_obj_new_bytearray(objsize, (void *)address);
}
mp_buffer_info_t bufinfo = {0};
mp_get_buffer_raise(arg, &bufinfo, MP_BUFFER_WRITE);
if (bufinfo.len != objsize) {
mp_raise_ValueError(MP_ERROR_TEXT("buffer has wrong length"));
}
memcpy(bufinfo.buf, (void *)address, objsize);
return arg;
}
void LMSet_common(long address, size_t objsize, mp_obj_t arg) {
mp_buffer_info_t bufinfo = {0};
mp_get_buffer_raise(arg, &bufinfo, MP_BUFFER_READ);
if (bufinfo.len != objsize) {
mp_raise_ValueError(MP_ERROR_TEXT("buffer has wrong length"));
}
memcpy((void *)address, bufinfo.buf, objsize);
}
Point Point_to_c(mp_obj_t obj, qstr fieldname) {
Point result;
if (mp_obj_len_maybe(obj) == MP_OBJ_NEW_SMALL_INT(2)) {
result.h = mp_obj_get_int(mp_obj_subscr(obj, mp_obj_new_int(0), MP_OBJ_SENTINEL));
result.v = mp_obj_get_int(mp_obj_subscr(obj, mp_obj_new_int(1), MP_OBJ_SENTINEL));
} else {
result = *(Point *)to_struct_helper(obj, (const mp_obj_type_t *)&Point_obj, true, fieldname);
}
return result;
}
void *void_ptr_from_py(mp_obj_t arg) {
if (mp_obj_is_int(arg)) {
return (void *)mp_obj_get_int_truncated(arg);
}
mp_buffer_info_t bufinfo = {0};
mp_get_buffer_raise(arg, &bufinfo, MP_BUFFER_READ);
return bufinfo.buf;
}
#if __m68k
pascal LONGINT GetDblTime(void) {
return LMGetDoubleTime();
}
pascal LONGINT GetCaretTime(void) {
return LMGetCaretTime();
}
typedef struct {
INTEGER count;
Byte data[0];
} patternlist;
pascal void GetIndPattern(Byte *pat, INTEGER patListId, INTEGER index) {
Handle h = (Handle)GetResource('PAT#', patListId);
if (!h) {
return;
}
LoadResource(h);
if (ResError() != noErr) {
return;
}
patternlist *patterns = (patternlist *)*h;
if (index < 0 || index >= patterns->count) {
return;
}
memcpy(pat, patterns->data + 8 * index, 8);
}
#endif