Merge pull request #16 from jepler/region-fixes

This commit is contained in:
Jeff Epler 2025-08-01 09:41:56 -05:00 committed by GitHub
commit b045a72239
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
25 changed files with 863 additions and 244 deletions

View file

@ -15,14 +15,11 @@ jobs:
build:
permissions: write-all
runs-on: ubuntu-latest
container: ghcr.io/autc04/retro68
container: ghcr.io/m68k-micropython/builder:latest
steps:
- uses: actions/checkout@v4
- name: Build
run: |
apt update
apt install -y python3-pip
pip install pyyaml click
git config --global --add safe.directory $(pwd)
make -C mpy-cross -j$(nproc)
make -C ports/m68kmac submodules

View file

@ -43,11 +43,13 @@
#define IS_SCALAR_ARRAY_OF_BYTES(tuple_desc) (GET_TYPE(MP_OBJ_SMALL_INT_VALUE((tuple_desc)->items[1]), VAL_TYPE_BITS) == UINT8)
// "struct" in uctypes context means "structural", i.e. aggregate, type.
static const mp_obj_type_t uctypes_struct_type;
const mp_obj_type_t uctypes_struct_type;
// Get size of any type descriptor
static mp_uint_t uctypes_struct_size(mp_obj_t desc_in, int layout_type, mp_uint_t *max_field_size);
static mp_obj_t uctypes_struct_attr_op(mp_obj_t self_in, qstr attr, mp_obj_t set_val);
#define CTYPES_FLAGS_SIZE_BITS (2)
#define CTYPES_OFFSET_SIZE_BITS (8 * sizeof(uint32_t) - 2)
@ -75,6 +77,11 @@ static bool is_struct_type(mp_obj_t obj_in) {
return make_new == uctypes_struct_type_make_new;
}
static bool is_struct_instance(mp_obj_t obj_in) {
const mp_obj_type_t *type = mp_obj_get_type(obj_in);
return MP_OBJ_TYPE_GET_SLOT_OR_NULL(type, subscr) == uctypes_struct_subscr;
}
mp_obj_t uctypes_struct_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
mp_arg_check_num(n_args, n_kw, 2, 3, false);
mp_obj_t desc = args[1];
@ -149,6 +156,9 @@ mp_obj_t uctypes_struct_type_make_new(const mp_obj_type_t *type_in, size_t n_arg
} else if (agg_type != PTR) {
syntax_error();
}
if (n_kw) {
mp_raise_TypeError(MP_ERROR_TEXT("struct: no fields"));
}
} else {
mp_obj_dict_t *d = MP_OBJ_TO_PTR(desc);
// only for packed ROM tables..
@ -161,10 +171,17 @@ mp_obj_t uctypes_struct_type_make_new(const mp_obj_type_t *type_in, size_t n_arg
for (size_t i = 0; i < n_args; i++) {
mp_store_attr(result, mp_obj_str_get_qstr(d->map.table[i].key), args[i]);
}
}
args += n_args;
for (size_t i = 0; i < 2 * n_kw; i += 2) {
mp_store_attr(result, mp_obj_str_get_qstr(args[i]), args[i + 1]);
args += n_args;
for (size_t i = 0; i < 2 * n_kw; i += 2) {
qstr q = mp_obj_str_get_qstr(args[i]);
for (size_t j = 0; j < n_args; j++) {
if (mp_obj_str_get_qstr(d->map.table[j].key) == q) {
mp_raise_msg_varg(&mp_type_TypeError,
MP_ERROR_TEXT("function got multiple values for argument '%q'"), q);
}
}
mp_store_attr(result, q, args[i + 1]);
}
}
return result;
}
@ -173,8 +190,10 @@ mp_obj_t uctypes_struct_type_make_new(const mp_obj_type_t *type_in, size_t n_arg
void uctypes_struct_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
(void)kind;
mp_obj_uctypes_struct_t *self = MP_OBJ_TO_PTR(self_in);
mp_obj_dict_t *d = 0;
const char *typen = "unk";
if (mp_obj_is_dict_or_ordereddict(self->desc)) {
d = MP_OBJ_TO_PTR(self->desc);
typen = "STRUCT";
} else if (mp_obj_is_type(self->desc, &mp_type_tuple)) {
mp_obj_tuple_t *t = MP_OBJ_TO_PTR(self->desc);
@ -192,7 +211,17 @@ void uctypes_struct_print(const mp_print_t *print, mp_obj_t self_in, mp_print_ki
typen = "ERROR";
}
mp_printf(print, "<%q %s %p>", (qstr)mp_obj_get_type_qstr(self_in), typen, struct_addr(self));
mp_printf(print, "<%q %s %p", (qstr)mp_obj_get_type_qstr(self_in), typen, struct_addr(self));
if (kind == PRINT_REPR && d) {
for (mp_uint_t i = 0; i < d->map.alloc; i++) {
if (mp_map_slot_is_filled(&d->map, i)) {
qstr k = mp_obj_str_get_qstr(d->map.table[i].key);
mp_obj_t attr = uctypes_struct_attr_op(self_in, k, MP_OBJ_NULL);
mp_printf(print, "\n %q=%r", k, attr);
}
}
}
mp_printf(print, ">");
}
// Get size of scalar type descriptor
@ -346,13 +375,25 @@ static mp_obj_t uctypes_struct_sizeof(size_t n_args, const mp_obj_t *args) {
}
static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(uctypes_struct_sizeof_obj, 1, 2, uctypes_struct_sizeof);
mp_obj_t uctypes_get_struct_desc(mp_obj_t arg) {
if (is_struct_instance(arg)) {
mp_obj_uctypes_struct_t *struct_ = MP_OBJ_TO_PTR(arg);
return struct_->desc;
}
if (is_struct_type(arg)) {
mp_obj_ctypes_struct_type_t *struct_type = MP_OBJ_TO_PTR(arg);
return struct_type->desc;
}
return MP_OBJ_NULL;
}
static mp_obj_t uctypes_struct_desc(mp_obj_t arg) {
if (!is_struct_type(arg)) {
mp_obj_t result = uctypes_get_struct_desc(arg);
if (result == MP_OBJ_NULL) {
mp_raise_TypeError(NULL);
}
mp_obj_ctypes_struct_type_t *struct_type = MP_OBJ_TO_PTR(arg);
return struct_type->desc;
return result;
}
MP_DEFINE_CONST_FUN_OBJ_1(uctypes_struct_desc_obj, uctypes_struct_desc);
static const char type2char[16] = {
@ -757,7 +798,7 @@ static mp_obj_t uctypes_struct_bytes_at(mp_obj_t ptr, mp_obj_t size) {
}
MP_DEFINE_CONST_FUN_OBJ_2(uctypes_struct_bytes_at_obj, uctypes_struct_bytes_at);
static MP_DEFINE_CONST_OBJ_TYPE(
MP_DEFINE_CONST_OBJ_TYPE(
uctypes_struct_type,
MP_QSTR_struct,
MP_TYPE_FLAG_NONE,

View file

@ -30,6 +30,8 @@
#if MICROPY_PY_UCTYPES
#include "py/obj.h"
extern const mp_obj_type_t uctypes_struct_type;
typedef struct _mp_obj_ctypes_struct_type_t {
// This is a mp_obj_type_t with six slots.
mp_obj_empty_type_t base;
@ -45,12 +47,14 @@ mp_obj_t uctypes_struct_unary_op(mp_unary_op_t op, mp_obj_t self_in);
mp_int_t uctypes_get_buffer(mp_obj_t self_in, mp_buffer_info_t *bufinfo, mp_uint_t flags);
mp_obj_t uctypes_struct_type_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args);
mp_obj_t uctypes_struct_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args);
// may call on an instance or named struct type
mp_obj_t uctypes_get_struct_desc(const mp_obj_t obj);
#define MP_DECLARE_CTYPES_STRUCT(type_name) \
extern mp_obj_ctypes_struct_type_t type_name;
extern const mp_obj_ctypes_struct_type_t type_name;
#define MP_DEFINE_CTYPES_STRUCT(type_name, name_, desc_, flags_) \
mp_obj_ctypes_struct_type_t type_name = { \
const mp_obj_ctypes_struct_type_t type_name = { \
.base = { \
.base = { &mp_type_type }, \
.flags = MP_TYPE_FLAG_NONE, \

14
extmod/multiversal.mk Normal file
View file

@ -0,0 +1,14 @@
MKAPIFORMAT ?=
# $(eval $(call multiversal_module, module name, defs files))
define multiversal_module
$$(BUILD)/mod$(1).c: $(TOP)/tools/mkapi.py $(filter-out -t,$(2)) $$(DEFS)
$$(ECHO) "MKAPI $(1)"
$$(Q)$$(MKDIR) -p $$(BUILD)
$$(Q)$$(PYTHON) $(TOP)/tools/mkapi.py $(MKAPIFORMAT) -o $$@ -m $(1) $$(TDEFS) $(2)
SRC_C += $(BUILD)/mod$(1).c
SRC_QSTR += $(BUILD)/mod$(1).c
mkapi:: $$(BUILD)/mod$(1).c
endef
SRC_C += extmod/multiverse_support.c
SRC_QSTR += extmod/multiverse_support.c

219
extmod/multiverse_support.c Normal file
View file

@ -0,0 +1,219 @@
#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

View file

@ -2,15 +2,42 @@
#include "py/obj.h"
#include "py/runtime.h"
#include "extmod/moductypes.h"
#include <Multiverse.h>
#if __m68k__
#include "Multiverse.h"
#else
typedef long LONGINT;
typedef short INTEGER;
typedef unsigned char Byte;
typedef struct { INTEGER h, v;
} Point;
#define pascal /* nothing */
#endif
// Relies on gcc Variadic Macros and Statement Expressions
#define NEW_TUPLE(...) \
({mp_obj_t _z[] = {__VA_ARGS__}; mp_obj_new_tuple(MP_ARRAY_SIZE(_z), _z); })
#define ROM_TUPLE(...) \
{{&mp_type_tuple}, MP_ARRAY_SIZE(((mp_obj_t[]) {__VA_ARGS__})), {__VA_ARGS__}}
{{&mp_type_tuple}, MP_ARRAY_SIZE(((const mp_obj_t[]) {__VA_ARGS__})), {__VA_ARGS__}}
#define DECLARE_PTR_SCALAR(type_c) \
MP_DECLARE_CTYPES_STRUCT(type_c##_obj)
DECLARE_PTR_SCALAR(bool);
DECLARE_PTR_SCALAR(char);
DECLARE_PTR_SCALAR(uint8_t);
DECLARE_PTR_SCALAR(uint16_t);
DECLARE_PTR_SCALAR(uint32_t);
DECLARE_PTR_SCALAR(uint64_t);
DECLARE_PTR_SCALAR(int8_t);
DECLARE_PTR_SCALAR(int16_t);
DECLARE_PTR_SCALAR(int32_t);
DECLARE_PTR_SCALAR(int64_t);
#define void_obj uint8_t_obj
void *void_ptr_from_py(mp_obj_t obj);
void *to_struct_helper(mp_obj_t obj, const mp_obj_type_t *struct_type, bool is_const, qstr fieldname);
mp_obj_t from_struct_helper(void *buf, const mp_obj_type_t *type);
void *to_scalar_helper(mp_obj_t obj, size_t objsize, bool is_const);

View file

@ -1,3 +1,8 @@
ifeq ($(shell which m68k-apple-macos-gcc),)
.PHONY: default
default: docker-build
endif
include ../../py/mkenv.mk
CROSS_COMPILE=m68k-apple-macos-
@ -44,7 +49,6 @@ SRC_C = \
main.c \
vfs_mac.c \
macutil.c \
multiverse_support.c \
SRC_C += \
shared/readline/readline.c \
@ -64,37 +68,28 @@ SRC_S += \
shared/runtime/gchelper_m68k.s \
SRC_QSTR += \
vfs_mac.c \
shared/readline/readline.c \
shared/runtime/pyexec.c \
vfs_mac.c \
.PHONY: mkapi
DEFS = lib/multiversal/defs/MacTypes.yaml etc/MacTypesExtras.yaml
TDEFS = $(patsubst %, -t %, $(DEFS))
# $(eval $(call multiversal_module, module name, defs files))
define multiversal_module
$$(BUILD)/mod$(1).c: tools/mkapi.py $(filter-out -t,$(2)) $$(DEFS)
$$(ECHO) "MKAPI $(1)"
$$(Q)$$(MKDIR) -p $$(BUILD)
$$(Q)$$(PYTHON) tools/mkapi.py -o $$@ -m $(1) $$(TDEFS) $(2)
SRC_C += $(BUILD)/mod$(1).c
SRC_QSTR += $(BUILD)/mod$(1).c
mkapi:: $$(BUILD)/mod$(1).c
endef
include $(TOP)/extmod/multiversal.mk
$(eval $(call multiversal_module,eventmgr,lib/multiversal/defs/EventMgr.yaml -t lib/multiversal/defs/QuickDraw.yaml))
$(eval $(call multiversal_module,deskmgr,lib/multiversal/defs/DeskMgr.yaml -t lib/multiversal/defs/WindowMgr.yaml -t lib/multiversal/defs/QuickDraw.yaml))
$(eval $(call multiversal_module,dialogmgr,lib/multiversal/defs/DialogMgr.yaml -t lib/multiversal/defs/WindowMgr.yaml -t lib/multiversal/defs/QuickDraw.yaml -t etc/DialogMgrExtras.yaml))
$(eval $(call multiversal_module,deskmgr,lib/multiversal/defs/DeskMgr.yaml -t lib/multiversal/defs/WindowMgr.yaml -t lib/multiversal/defs/QuickDraw.yaml -t lib/multiversal/defs/EventMgr.yaml))
$(eval $(call multiversal_module,dialogmgr,lib/multiversal/defs/DialogMgr.yaml -t lib/multiversal/defs/WindowMgr.yaml -t lib/multiversal/defs/QuickDraw.yaml -t etc/DialogMgrExtras.yaml -t lib/multiversal/defs/EventMgr.yaml))
$(eval $(call multiversal_module,fontmgr,lib/multiversal/defs/FontMgr.yaml -t lib/multiversal/defs/QuickDraw.yaml))
$(eval $(call multiversal_module,mactypes,lib/multiversal/defs/MacTypes.yaml etc/MacTypesExtras.yaml))
$(eval $(call multiversal_module,menumgr,lib/multiversal/defs/MenuMgr.yaml -t lib/multiversal/defs/QuickDraw.yaml))
$(eval $(call multiversal_module,qd,lib/multiversal/defs/QuickDraw.yaml etc/QuickDrawExtras.yaml))
$(eval $(call multiversal_module,textedit,lib/multiversal/defs/TextEdit.yaml -t lib/multiversal/defs/QuickDraw.yaml))
$(eval $(call multiversal_module,toolboxevent,lib/multiversal/defs/ToolboxEvent.yaml -t lib/multiversal/defs/QuickDraw.yaml))
$(eval $(call multiversal_module,toolboxevent,lib/multiversal/defs/ToolboxEvent.yaml -t lib/multiversal/defs/QuickDraw.yaml -t lib/multiversal/defs/EventMgr.yaml))
$(eval $(call multiversal_module,toolboxutil,lib/multiversal/defs/ToolboxUtil.yaml -t lib/multiversal/defs/EventMgr.yaml -t lib/multiversal/defs/QuickDraw.yaml))
$(eval $(call multiversal_module,windowmgr,lib/multiversal/defs/WindowMgr.yaml -t lib/multiversal/defs/QuickDraw.yaml))
$(eval $(call multiversal_module,windowmgr,lib/multiversal/defs/WindowMgr.yaml -t lib/multiversal/defs/QuickDraw.yaml -t lib/multiversal/defs/EventMgr.yaml))
OBJ += $(PY_CORE_O) $(PY_O)
OBJ += $(addprefix $(BUILD)/, $(SRC_C:.c=.o))
@ -118,20 +113,33 @@ $(BUILD)/micropython.bin $(BUILD)/micropython.APPL $(BUILD)/micropython.dsk: $(B
"$(RINCLUDES)/Retro68APPL.r" \
-t "APPL" -c "mupy" \
-o $(BUILD)/micropython.bin --cc $(BUILD)/micropython.APPL --cc $(BUILD)/micropython.dsk
hmount $(BUILD)/micropython.dsk
(cd examples; set -x; \
for i in *.py; do \
hcopy $$i ":$$i"; \
hattrib -c mupy -t text ":$$i"; \
done)
.PHONY: docker-build
docker-build: mkapi
docker-build:
./docker-run.sh make -j$(shell nproc)
BASE_IMG ?= base.img
UMAC=$(HOME)/src/umac/main -w -r ~/src/umac/rom.bin
.PHONY: run
run-%:
cp $(BASE_IMG) $(BUILD)/run.dsk
hmount $(BUILD)/run.dsk
hcopy $(BUILD)/micropython.bin ":Desktop Folder"
hcopy examples/$*.py ":Desktop Folder:code.py"
hattrib -c mupy -t text ":Desktop Folder:code.py"
$(UMAC) -d build/run.dsk
run:
cp $(BASE_IMG) $(BUILD)/run.dsk
hmount $(BUILD)/run.dsk
hcopy $(BUILD)/micropython.bin ":Desktop Folder"
hcopy code.py ":Desktop Folder"
hattrib -t mupy -c mupy -t text ":Desktop Folder:code.py"
hattrib -c mupy -t text ":Desktop Folder:code.py"
$(UMAC) -d build/run.dsk
include $(TOP)/py/mkrules.mk

View file

@ -9,8 +9,6 @@ Two methods of building are supported. First, entirely within docker, using the
`.github/workflows/port_m68k.yaml`. Second, building on a standard Linux host machine
(e.g., debian stable) with docker installed:
$ pip install pyyaml click
$ make submodules
$ make docker-build
There's a `make run` target to launch the emulator but it is very specific to

View file

@ -1,45 +0,0 @@
# m68k-micropython window creation demo
import eventmgr
import mactypes
import qd
import uctypes
import windowmgr
def let(dst, src):
memoryview(dst)[:] = memoryview(src)[:]
def pstr(s):
b = mactypes.Str255()
b[0] = len(s)
for i in range(len(s)):
b[i + 1] = ord(s[i])
return b
ev = eventmgr.EventRecord()
NIL_WINDOW = uctypes.struct(0, qd.GrafPort)
ABOVE_ALL_WINDOWS = uctypes.struct(-1, qd.GrafPort)
title = pstr("Hello World")
r = mactypes.Rect()
scrn = qd.qdGlobals().screenBits
let(r, scrn.bounds)
r.top += 80
qd.InsetRect(r, 25, 25)
w = windowmgr.NewWindow(NIL_WINDOW, r, title, True, 0, ABOVE_ALL_WINDOWS, True, 0)
let(r, w.portRect)
qd.SetPort(w)
mid_x = (r.left + r.right) // 2
mid_y = (r.top + r.bottom) // 2
for i in range(r.left, r.right, 2):
qd.MoveTo(mid_x, r.bottom)
qd.LineTo(i, r.top)
qd.MoveTo(mid_x, mid_y)
input("hit enter to exit")

View file

@ -7,4 +7,5 @@ if [ $# -eq 0 ]; then it=-it; else it=; fi
docker run \
-w /work/ports/m68kmac --rm \
-v "${TOP}":/work \
${it} ghcr.io/autc04/retro68 "$@"
${it} ghcr.io/m68k-micropython/builder:latest "$@"

View file

@ -1 +1,13 @@
[]
- typedef:
name: ProcPtr
type: void*
- pyverbatim:
typedef_content: |
#define WindowRef_obj GrafPtr_obj
#define WindowPtr_obj GrafPtr_obj
#define DialogPtr_obj GrafPtr_obj
#define INTEGER_obj int16_t_obj
#define Fixed_obj int32_t_obj
#define LONGINT_obj int32_t_obj
#define Byte_obj uint8_t_obj
#define SignedByte_obj int8_t_obj

View file

@ -1,4 +1,3 @@
Using multiversal interfaces
ADBOp
FSOpen
OpenRF
@ -175,3 +174,5 @@ GetDblTime
GetCaretTime
GetIndString
GetIndPattern
R_X2Fix
R_X2Frac

View file

@ -0,0 +1,55 @@
# m68k-micropython window creation demo
import eventmgr
import mactypes
import qd
import uctypes
import windowmgr
import random
scrn = qd.qdGlobals().screenBits
def pstr(s):
b = mactypes.Str255()
b[0] = len(s)
for i in range(len(s)):
b[i + 1] = ord(s[i])
return uctypes.struct(b, mactypes.ConstStringPtr)
ev = eventmgr.EventRecord()
NIL_WINDOW = uctypes.struct(0, qd.GrafPtr)
ABOVE_ALL_WINDOWS = uctypes.struct(-1, qd.GrafPtr)
title = pstr("Hello World 11")
r = mactypes.Rect()
r[:] = scrn.bounds
r.top += 80
r.left += 100
qd.InsetRect(r, 25, 25)
w = windowmgr.NewWindow(NIL_WINDOW, r, title, True, 0, ABOVE_ALL_WINDOWS, True, 0)
qd.SetPort(w)
g = qd.qdGlobals()
barbell = qd.NewRgn()
tempRect = mactypes.Rect()
qd.OpenRgn()
qd.SetRect(tempRect, 20, 20, 30, 50)
qd.FrameOval(tempRect)
qd.SetRect(tempRect, 25, 30, 85, 40)
qd.FrameRect(tempRect)
qd.SetRect(tempRect, 80, 20, 90, 50)
qd.FrameOval(tempRect)
qd.CloseRgn(barbell)
r[:] = barbell[0].rgnBBox
print(f"region size {barbell[0].rgnSize} bbox {r.top},{r.left}..{r.right},{r.bottom}")
qd.FillRgn(barbell, g.black)
qd.DisposeRgn(barbell)
input("hit enter to exit")

View file

@ -1,101 +0,0 @@
#include "multiverse_support.h"
MP_DECLARE_CTYPES_STRUCT(Point_obj);
#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_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;
}
mp_obj_t from_struct_helper(void *buf, const mp_obj_type_t *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);
}
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;
}
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);
}

3
ports/unix/makefile Normal file
View file

@ -0,0 +1,3 @@
MAKEFLAGS=-j10
VARIANT ?= coverage
include Makefile

View file

@ -0,0 +1,167 @@
- typedef:
name: Byte
type: uint8_t
- typedef:
name: INTEGER
type: int16_t
- struct:
name: Rect
members:
- name: top
type: INTEGER
- name: left
type: INTEGER
- name: bottom
type: INTEGER
- name: right
type: INTEGER
size: 8
- typedef:
name: Str15
type: Byte[16]
- struct:
name: GrafPort
members:
- name: device
type: INTEGER
- name: portRect
type: Rect
- typedef:
name: GrafPtr
type: GrafPort*
- typedef:
name: WindowPtr
type: GrafPtr
# ####
- struct:
name: Region
members:
- name: rgnSize
type: INTEGER
- name: rgnBBox
type: Rect
size: 10
# ####
- struct:
name: Point
members:
- name: h
type: INTEGER
- name: v
type: INTEGER
- typedef:
name: RegionPtr
type: Region*
- typedef:
name: RgnHandle
type: RegionPtr*
# ####
- pyverbatim:
typedef_content: |
typedef struct {
INTEGER top, left, bottom, right;
} Rect;
typedef struct {
INTEGER rgnSize; Rect rgnBBox;
} Region;
typedef struct {
INTEGER device;
Rect portRect;
} GrafPort;
typedef GrafPort *GrafPtr;
typedef GrafPtr WindowPtr;
#define WindowPtr_obj GrafPtr_obj
typedef Region *RegionPtr;
typedef RegionPtr *RgnHandle;
static void OffsetRgn(RgnHandle rh, INTEGER dh, INTEGER dv) {
Region *region = *rh;
region->rgnBBox.top += dv;
region->rgnBBox.bottom += dv;
region->rgnBBox.left += dh;
region->rgnBBox.right += dh;
}
static RgnHandle NewRgn(void) {
static Region rgn = { 0x505, {100, 200, 300, 400} };
static RegionPtr rp = &rgn;
return &rp;
}
static WindowPtr NewWindow(void) {
static GrafPort result = {0, {0x100, 0x200, 0x300, 0x400} };
return &result;
}
static void PtToAngle(const Rect *r, Point p, INTEGER *angle) {
mp_printf(&mp_plat_print, "PtToAngle(rect@%p, p={%d,%d}, angle@%p\n", r, p.h, p.v, angle);
*angle = 314;
}
static INTEGER GetWinDevice(WindowPtr w) {
return w->device;
}
- function:
name: NewRgn
return: RgnHandle
trap: 0xA8D8
executor: C_
- function:
name: OffsetRgn
args:
- name: rh
type: RgnHandle
- name: dh
type: INTEGER
- name: dv
type: INTEGER
trap: 0xA8E0
executor: C_
- function:
name: PtToAngle
args:
- name: rp
type: const Rect*
- name: p
type: Point
- name: angle
type: INTEGER*
trap: 0xA8C3
executor: C_
- function:
name: NewWindow
return: WindowPtr
- function:
name: GetWinDevice
return: INTEGER
args:
- name: w
type: WindowPtr

View file

@ -12,5 +12,13 @@ LDFLAGS += -fprofile-arcs -ftest-coverage
FROZEN_MANIFEST ?= $(VARIANT_DIR)/manifest.py
USER_C_MODULES = $(TOP)/examples/usercmodule
# Optionally format the generated files with uncrustify if installed
ifneq ($(shell which uncrustify-apple-macos-gcc),)
MKAPIFORMAT = --format
endif
include $(TOP)/extmod/multiversal.mk
$(eval $(call multiversal_module,mkapitest,variants/coverage/mkapi_test.yaml))
$(info $(call multiversal_module,mkapitest,variants/coverage/mkapi_test.yaml))
SRC_C += coverage.c
SRC_CXX += coveragecpp.cpp

View file

@ -495,6 +495,11 @@ int mp_vprintf(const mp_print_t *print, const char *fmt, va_list args) {
chrs += mp_print_strn(print, str, len, flags, fill, width);
break;
}
case 'r': {
mp_obj_t arg = va_arg(args, mp_obj_t);
mp_obj_print_helper(print, arg, width);
break;
}
case 's': {
const char *str = va_arg(args, const char *);
#ifndef NDEBUG

36
tests/extmod/mkapi.py Normal file
View file

@ -0,0 +1,36 @@
import mkapitest
rh = mkapitest.NewRgn()
r = rh[0]
print(type(rh), type(r))
print(r.rgnBBox.top)
print(r.rgnBBox.left)
print(r.rgnBBox.right)
print(r.rgnBBox.bottom)
mkapitest.OffsetRgn(rh, 3, 5)
print(r.rgnBBox.top)
print(r.rgnBBox.left)
print(r.rgnBBox.right)
print(r.rgnBBox.bottom)
w = mkapitest.NewWindow()
print(type(w))
print(w.portRect.top)
print(w.portRect.left)
print(w.portRect.right)
print(w.portRect.bottom)
r = mkapitest.Rect(1, 2, 3, 4)
print(r)
print(repr(r))
r = mkapitest.Rect(top=10, left=20, right=30, bottom=40)
print(repr(r))
r = mkapitest.Rect(100, 200, right=300, bottom=400)
print(repr(r))
try:
r = mkapitest.Rect(1000, 2000, 3000, right=4000, bottom=5000)
print(repr(r))
except Exception as e:
print(type(e))

31
tests/extmod/mkapi.py.exp Normal file
View file

@ -0,0 +1,31 @@
<class 'RegionPtr'> <class 'Region'>
100
200
400
300
105
203
403
305
<class 'GrafPort'>
256
512
1024
768
<Rect STRUCT \[0-9a-f\]\*>
<Rect STRUCT \[0-9a-f\]\*
top=1
left=2
bottom=3
right=4>
<Rect STRUCT \[0-9a-f\]\*
top=10
left=20
bottom=40
right=30>
<Rect STRUCT \[0-9a-f\]\*
top=100
left=200
bottom=400
right=300>
<class 'TypeError'>

View file

@ -57,13 +57,14 @@ cppexample cryptolib deflate errno
example_package ffi framebuf
gc hashlib heapq io
json machine marshal math
os platform random re
select socket struct sys
termios time tls uctypes
vfs websocket
mkapitest os platform random
re select socket struct
sys termios time tls
uctypes vfs websocket
me
micropython machine marshal math
mkapitest
argv atexit byteorder exc_info
executable exit getsizeof implementation

View file

@ -357,6 +357,7 @@ special_tests = [
"misc/sys_settrace_cov.py",
"thread/thread_exc2.py",
"ports/esp32/partition_ota.py",
"extmod/mkapi.py",
)
]

View file

@ -627,6 +627,7 @@ function ci_unix_coverage_setup {
pip3 install setuptools
pip3 install pyelftools
pip3 install ar
pip3 install pyyaml click
ci_gcc_plugin_setup
gcc --version
python3 --version
@ -680,6 +681,7 @@ function ci_unix_32bit_setup {
sudo pip3 install setuptools
sudo pip3 install pyelftools
sudo pip3 install ar
sudo pip3 install --upgrade pyyaml click
gcc --version
python2.7 --version
python3 --version

View file

@ -288,6 +288,7 @@ struct micropython_checks : gimple_opt_pass {
require_qstr(argno++);
break;
case 'r':
case 's':
case 'p':
case 'P':

View file

@ -9,13 +9,34 @@ from functools import singledispatchmethod
from dataclasses import dataclass, Field
from typing import Any, get_args, get_origin, Union
script_dir = pathlib.Path(__file__).parent
if sys.version_info >= (3, 10):
from types import UnionType
else:
UnionType = type(Union[int, float])
with open("etc/needs-glue.txt") as f:
needs_glue = set(f.read().split("\n"))
p = pathlib.Path("etc/needs-glue.txt")
if p.exists():
needs_glue = set(p.read_text().split("\n"))
else:
needs_glue = set()
typecodes = {
'bool': 'B',
'char': 'B',
'uint8_t': 'B',
'uint16_t': 'H',
'uint32_t': 'L',
'uint64_t': 'Q',
'float': 'f',
'double': 'd',
'int8_t': 'b',
'int16_t': 'h',
'int32_t': 'l',
'int64_t': 'q',
}
@dataclass(frozen=True)
@ -260,9 +281,10 @@ class descr_maker_struct:
def __call__(self, emitter, offset):
obj = emitter.common_definition(
"mp_rom_obj_tuple_t", f"ROM_TUPLE(MP_ROM_INT({offset}), MP_ROM_PTR(&{self.tag}_obj))"
"const mp_rom_obj_tuple_t",
f"ROM_TUPLE(MP_ROM_INT({offset}), MP_ROM_PTR((void*)&{self.tag}_obj))",
)
return f"MP_ROM_PTR(&{obj})"
return f"MP_ROM_PTR((void*)&{obj})"
@dataclass
@ -272,10 +294,10 @@ class descr_maker_arr_scalar:
def __call__(self, emitter, offset):
obj = emitter.common_definition(
"mp_rom_obj_tuple_t",
f"ROM_TUPLE(MP_ROM_INT({offset} | UCTYPE_AGG(ARRAY)), MP_ROM_INT({self.tag} | {self.size}))",
"const mp_rom_obj_tuple_t",
f"ROM_TUPLE(MP_ROM_INT({offset} | UCTYPE_AGG(ARRAY)), MP_ROM_INT(UCTYPE_TYPE({self.tag}) | {self.size}))",
)
return f"MP_ROM_PTR(&{obj})"
return f"MP_ROM_PTR((void*)&{obj})"
@dataclass
@ -285,10 +307,10 @@ class descr_maker_arr_struct:
def __call__(self, emitter, offset):
obj = emitter.common_definition(
"mp_rom_obj_tuple_t",
f"ROM_TUPLE(MP_ROM_INT({offset} | UCTYPE_AGG(ARRAY)), MP_ROM_INT({self.size}), MP_ROM_PTR(&{self.tag}_obj))",
"const mp_rom_obj_tuple_t",
f"ROM_TUPLE(MP_ROM_INT({offset} | UCTYPE_AGG(ARRAY)), MP_ROM_INT({self.size}), MP_ROM_PTR((void*)(&{self.tag}_obj)))",
)
return f"MP_ROM_PTR(&{obj})"
return f"MP_ROM_PTR((void*)&{obj})"
@dataclass
@ -297,10 +319,10 @@ class descr_maker_ptr_scalar:
def __call__(self, emitter, offset):
obj = emitter.common_definition(
"mp_rom_obj_tuple_t",
f"ROM_TUPLE(MP_ROM_INT({offset} | UCTYPE_AGG(PTR)), MP_ROM_INT({self.tag}))",
"const mp_rom_obj_tuple_t",
f"ROM_TUPLE(MP_ROM_INT({offset} | UCTYPE_AGG(PTR)), MP_ROM_INT(UCTYPE_TYPE({self.tag})))",
)
return f"MP_ROM_PTR(&{obj})"
return f"MP_ROM_PTR((void*)&{obj})"
class descr_maker_ptr_struct:
@ -309,10 +331,10 @@ class descr_maker_ptr_struct:
def __call__(self, emitter, offset):
obj = emitter.common_definition(
"mp_rom_obj_tuple_t",
f"ROM_TUPLE(MP_ROM_INT({offset} | UCTYPE_AGG(PTR)), MP_ROM_PTR(&{self.tag}_obj))",
"const mp_rom_obj_tuple_t",
f"ROM_TUPLE(MP_ROM_INT({offset} | UCTYPE_AGG(PTR)), MP_ROM_PTR((void*)&{self.tag}_obj))",
)
return f"MP_ROM_PTR(&{obj})"
return f"MP_ROM_PTR((void*)&{obj})"
@dataclass
@ -352,6 +374,7 @@ class ScalarConverter:
@dataclass
class PtrConverter:
emitter: object
fieldname: str
type_c: object
type_obj: object
@ -360,10 +383,28 @@ class PtrConverter:
def emit_to_c(self, name_py, name_c):
is_const = +self.is_const # to get 0/1, not True/False
return f"{self.type_c} {name_c} = to_struct_helper({name_py}, {self.type_obj}, {is_const}, MP_QSTR_{self.fieldname});"
resolved_type = self.emitter.parse_type(self.type_c)
if (
isinstance(resolved_type, Ptr)
and self.emitter.parse_type(resolved_type.pointee) not in all_scalar_types
):
type_obj = f"(void*)&{resolved_type.pointee}_obj"
return f"{self.type_c} {name_c} = to_struct_helper({name_py}, {type_obj}, {is_const}, MP_QSTR_{self.fieldname}); // 1\n"
else:
return f"{self.type_c} {name_c} = to_struct_helper({name_py}, {self.type_obj}, {is_const}, MP_QSTR_{self.fieldname}); // 2\n"
def emit_to_py(self, name_c):
return f"from_struct_helper({name_c}, {self.type_obj});"
resolved_type = self.emitter.parse_type(self.type_c)
if resolved_type in self.emitter.types:
resolved_type = self.emitter.parse_type(self.emitter.types[resolved_type])
print("emit_to_py", self.type_c, resolved_type)
if isinstance(resolved_type, Ptr):
assert self.type_obj and self.type_obj != "null"
type_str = resolved_type.pointee.replace("*", "Ptr")
return f"from_struct_helper({name_c}, (void*)&{type_str}_obj) /* {self.type_c} 3 */"
else:
type_str = self.type_obj.replace("*", "Ptr")
return f"from_struct_helper({name_c}, {self.type_obj}) /* {resolved_type} 4 */"
def emit_call_arg(self, name_c):
if self.deref:
@ -372,12 +413,14 @@ class PtrConverter:
def make_converter(emitter, fieldname, type_c):
print(f"make_converter {type_c=}")
if converter := converters.get(type_c):
return converter(fieldname)
resolved_type = emitter.parse_type(type_c)
print(f"{type_c} -> {resolved_type}")
if resolved_type in signed_integer_types:
return ScalarConverter(resolved_type, "mp_obj_get_int", "mp_obj_new_int")
if resolved_type in emitter.types:
resolved_type = emitter.parse_type(emitter.types[resolved_type])
if resolved_type in emitter.funptrs:
return ScalarConverter(
resolved_type, f"({type_c})mp_obj_get_int_truncated", "mp_obj_new_int_from_ptr"
@ -386,19 +429,48 @@ def make_converter(emitter, fieldname, type_c):
return ScalarConverter(
resolved_type, "mp_obj_get_int_truncated", "mp_obj_new_int_from_uint"
)
if type_c == "void*":
return ScalarConverter(resolved_type, "void_ptr_from_py", "mp_obj_new_int_from_uint")
if isinstance(resolved_type, Ptr):
base_type = resolved_type.pointee
if base_type in emitter.structs:
if base_type in all_scalar_types:
return PtrConverter(
emitter,
fieldname,
type_c,
f"(const mp_obj_type_t*)&{base_type}_obj",
is_const=resolved_type.is_const,
)
emitter.info.append(f"confused about {base_type} from {resolved_type} from {type_c}")
return PtrConverter(fieldname, type_c, "NULL", is_const=resolved_type.is_const)
print(f"note: {emitter.funptrs}")
raise ValueError(f"no converter possible for {type_c} ({resolved_type})")
if type in emitter.structs or type_c in emitter.types:
return PtrConverter(
emitter,
fieldname,
type_c,
f"(const mp_obj_type_t*)&{type_c}_obj",
is_const=resolved_type.is_const,
)
if base_type in emitter.structs:
return PtrConverter(
emitter,
fieldname,
type_c,
f"(const mp_obj_type_t*)&{base_type}_obj",
is_const=resolved_type.is_const,
)
elif base_type in emitter.typedef_objs:
return PtrConverter(
emitter,
fieldname,
type_c,
f"(const mp_obj_type_t*)&{base_type}_obj",
is_const=resolved_type.is_const,
)
emitter.info.append(f"need to handle typedef obj {base_type}")
elif base_type != 'void':
emitter.info.append(f"confused about {base_type} from {resolved_type} from {type_c}")
return PtrConverter(emitter, fieldname, type_c, "NULL", is_const=resolved_type.is_const)
print(f"note: {emitter.funptrs=}")
raise ValueError(f"no converter possible for {type_c} ({resolved_type=})")
class Processor:
@ -415,7 +487,7 @@ class Processor:
self.structs = {}
self.funptrs = set(("ProcPtr",))
self.decls_dedent("""
#include "multiverse_support.h"
#include "extmod/multiverse_support.h"
""")
self.add_local("__name__", f"MP_ROM_QSTR(MP_QSTR_{self.modname})")
@ -429,6 +501,10 @@ class Processor:
return f"common_{self.definitions[k]}"
def is_array(self, typename):
if isinstance(typename, Array):
return True
if isinstance(typename, Ptr):
return False
if typename.count(']') + ("*" in typename) > 1:
raise ValueError(
f"array-of-array or pointer-to-array or array-of-pointers NYI {typename}"
@ -436,18 +512,30 @@ class Processor:
return typename.endswith("]")
def remove_array(self, typename):
if isinstance(typename, Array):
return typename.pointee
return typename.partition("[")[0]
def remove_ptr(self, typename):
if isinstance(typename, Ptr):
return typename.pointee
return typename.removesuffix("*")
def remove_const(self, typename):
if hasattr(typename, 'is_const'):
return dataclasses.replace(typename, is_const=False)
return typename.removeprefix("const ")
def array_size(self, typename):
if isinstance(typename, Array):
return typename.bound
return int(typename.partition("[")[2].removesuffix("]"))
def is_ptr(self, typename):
if isinstance(typename, Ptr):
return True
if isinstance(typename, Array):
return False
return typename.endswith("*")
def is_scalar(self, typename):
@ -456,6 +544,8 @@ class Processor:
return typename in all_scalar_types
def is_const(self, typename):
if hasattr(typename, 'is_const'):
return typename.is_const
return typename.startswith("const ")
def decls_dedent(self, text):
@ -465,11 +555,8 @@ class Processor:
self.body.append(textwrap.dedent(text.rstrip()))
def parse_type(self, typestr):
print("parse_type", typestr)
if typestr == 'RgnHandle':
print(self.types)
while typestr in self.types:
typestr = self.types[typestr]
if scalar_type := self.types.get(typestr, None):
typestr = scalar_type
is_const = self.is_const(typestr)
base_type = self.remove_const(typestr)
if self.is_array(base_type):
@ -477,8 +564,7 @@ class Processor:
base_type = self.parse_type(self.remove_array(base_type))
return Array(base_type, bound, is_const=is_const)
elif self.is_ptr(base_type):
print(base_type, self.remove_ptr(base_type))
base_type = self.parse_type(self.remove_ptr(base_type))
base_type = self.remove_ptr(base_type)
return Ptr(base_type, is_const=is_const)
else:
if is_const:
@ -492,13 +578,15 @@ class Processor:
d.fulltype = self.parse_type(d.type)
print(f"full type of {d.name} is {d.fulltype}")
self.types[d.name] = d.type
self.decls_dedent(f"MP_DECLARE_CTYPES_STRUCT({d.name}_obj);")
self.decls_dedent(
f"MP_DECLARE_CTYPES_STRUCT({d.name}_obj); // typedef {d.fulltype} is_scalar? {self.is_scalar(d.fulltype)}"
)
if isinstance(d, Struct) and d.members:
self.structs[d.name] = d
self.decls_dedent(f"MP_DECLARE_CTYPES_STRUCT({d.name}_obj);")
self.decls_dedent(f"MP_DECLARE_CTYPES_STRUCT({d.name}_obj); // struct")
if isinstance(d, Union) and d.members:
self.structs[d.name] = d
self.decls_dedent(f"MP_DECLARE_CTYPES_STRUCT({d.name}_obj);")
self.decls_dedent(f"MP_DECLARE_CTYPES_STRUCT({d.name}_obj); // union")
if isinstance(d, PyVerbatim) and d.typedef_content:
self.decls_dedent(d.typedef_content)
if isinstance(d, FunPtr):
@ -506,6 +594,7 @@ class Processor:
def emit(self, defs):
for d in defs:
print("emit", id(d), d)
try:
self.emit_node(d)
except Exception as e:
@ -516,31 +605,53 @@ class Processor:
if type(node) in self.unknowns:
return
self.unknowns.add(type(node))
self.info.append(f"# Unknown {node!r:.68s}...")
raise RuntimeError(f"# Unknown {node!r:.68s}...")
@emit_node.register
def emit_dispatcher(self, dispatcher: Dispatcher):
pass # Nothing to emit
@emit_node.register
def emit_typedef(self, typedef: Typedef):
print("emit_typedef", typedef)
self.body_dedent(f"// typedef {typedef}")
name = typedef.name
type = typedef.type
if type.endswith("*") or type.endswith("]"):
make_descr = self.type_details(typedef.type)
make_descr = self.type_details(typedef.fulltype)
self.body_dedent(f"// {type} {make_descr=}")
if make_descr is None:
self.body_dedent(f"// {typedef}: no make_descr")
return
offset = 0
self.body_dedent(f"""
MP_DEFINE_CTYPES_STRUCT({name}_obj, MP_QSTR_{name}, {make_descr(self, offset)}, LAYOUT_NATIVE);
MP_DEFINE_CTYPES_STRUCT({name}_obj, MP_QSTR_{name}, {make_descr(self, offset)}, LAYOUT_NATIVE); // 1
""")
self.typedef_objs.add(name)
self.add_local(name)
offset = 0
else:
self.body_dedent(f"// no need for {typedef} !?")
def type_details(self, typename):
if typename in self.funptrs:
return None
fulltype = self.parse_type(typename)
is_ptr = isinstance(fulltype, Ptr)
is_array = isinstance(fulltype, Array)
basetypename = fulltype if isinstance(fulltype, str) else fulltype.pointee
if isinstance(typename, Ptr):
is_ptr = True
is_array = False
basetypename = typename.pointee
print(f"{typename=} -- {basetypename=} {basetypename in self.types}")
elif isinstance(typename, Array):
is_ptr = False
is_array = True
fulltype = typename
basetypename = typename.pointee
print(f"{typename=} -- {basetypename=} {basetypename in self.types}")
else:
fulltype = self.parse_type(typename)
is_ptr = isinstance(fulltype, Ptr)
is_array = isinstance(fulltype, Array)
basetypename = fulltype if isinstance(fulltype, str) else fulltype.pointee
if basetypename in all_scalar_types:
u = "U" if basetypename.startswith("u") else ""
@ -569,7 +680,18 @@ class Processor:
descr = descr_maker_scalar(type_str)
else:
if is_ptr:
if basetypename in self.structs:
if typename in self.types:
deref_typename = self.parse_type(self.types[typename])
if (
isinstance(deref_typename, Ptr)
and deref_typename.pointee in self.structs
or deref_typename.pointee in self.types
):
typename = deref_typename.pointee
descr = descr_maker_ptr_struct(typename)
elif basetypename in self.structs:
descr = descr_maker_ptr_struct(basetypename)
elif basetypename in self.types:
descr = descr_maker_ptr_struct(basetypename)
else:
descr = descr_maker_ptr_scalar("UINT8")
@ -607,7 +729,7 @@ class Processor:
{self.union_make_table(e)}
}};
static MP_DEFINE_CONST_DICT({name}_descr_dict, {name}_descr_table);
MP_DEFINE_CTYPES_STRUCT({name}_obj, MP_QSTR_{name}, MP_ROM_PTR((void*)&{name}_descr_dict), LAYOUT_NATIVE);
MP_DEFINE_CTYPES_STRUCT({name}_obj, MP_QSTR_{name}, MP_ROM_PTR((void*)&{name}_descr_dict), LAYOUT_NATIVE); // 2
""")
self.add_local(name)
@ -623,7 +745,7 @@ class Processor:
{self.struct_make_table(e)}
}};
static MP_DEFINE_CONST_DICT({name}_descr_dict, {name}_descr_table);
MP_DEFINE_CTYPES_STRUCT({name}_obj, MP_QSTR_{name}, MP_ROM_PTR((void*)&{name}_descr_dict), LAYOUT_NATIVE);
MP_DEFINE_CTYPES_STRUCT({name}_obj, MP_QSTR_{name}, MP_ROM_PTR((void*)&{name}_descr_dict), LAYOUT_NATIVE); // 3
""")
self.add_local(name)
@ -657,7 +779,7 @@ class Processor:
def add_local(self, name, value=...):
if value is ...:
value = f"MP_ROM_PTR(&{name}_obj)"
value = f"MP_ROM_PTR((void*)&{name}_obj)"
self.locals.append(f"{{ MP_ROM_QSTR(MP_QSTR_{name}), {value} }},")
@emit_node.register
@ -719,7 +841,6 @@ class Processor:
return_type = fun.return_
args = fun.args
argnames = [arg.name or f"arg{i}" for i, arg in enumerate(args)]
print(argnames)
fun_args = ", ".join(argnames)
if fun.inline:
funcall = f"{fun.inline};"
@ -732,9 +853,9 @@ class Processor:
return_type = fun.return_
if return_type:
converter = self.make_converter(0, return_type)
return f" return {converter.emit_to_py('retval')};"
return f" return {converter.emit_to_py('retval')};\n"
else:
return " return mp_const_none;"
return " return mp_const_none;\n"
@emit_node.register
def emit_function(self, node: Function):
@ -746,7 +867,7 @@ class Processor:
if node.api == 'carbon':
return
self.body_dedent(f"""
mp_obj_t {name}_fn(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {{
static mp_obj_t {name}_fn(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {{
{self.fun_parse_args(args)}
{self.fun_convert_args(args)}
{self.fun_call_fun(node)}
@ -795,7 +916,11 @@ class Processor:
"-t", "--typedefs", multiple=True, type=click.Path(path_type=pathlib.Path, exists=True)
)
@click.option("-m", "--modname", type=str)
def main(defs_files, output, modname, typedefs):
@click.option("--format/-no-format", "do_format")
def main(defs_files, output, modname, typedefs, do_format=False):
if modname is None:
modname = defs_files[0].stem
if output is None:
output = pathlib.Path(f"mod{modname}.c")
processor = Processor(modname)
@ -810,8 +935,16 @@ def main(defs_files, output, modname, typedefs):
processor.typedefs(defs)
processor.emit(defs)
with open(output, "w") as f:
processor.make_output(f)
if do_format:
tmpfile = output.with_suffix(".tmp.c")
with open(tmpfile, "w") as f:
processor.make_output(f)
print(f"Formatting {output}: ", [script_dir / "codeformat.py", "-c", tmpfile])
subprocess.check_call([script_dir / "codeformat.py", "-c", tmpfile])
tmpfile.rename(output)
else:
with open(output, "w") as f:
processor.make_output(f)
if __name__ == '__main__':