vikK4yHabbe7L wrote: ↑Tue Sep 28, 2021 1:37 am

So the question is... why isn't cmake telling make to get things from libgcc.a ?

It's not a 'cmake' issue. That builds MicroPython perfectly well, handles divisions and modulos in its source and links to the required '__aeabi_idivmod' and friends as required and expected. Actually it seems to link to '__wrap__aeabi_idivmod' etc, but it all works as one would expect.

The issue here is building Native C Extension Modules which are built outside of the 'cmake' MicroPython build. These use 'make' and a 'Makefile' to take C source and create a '.mpy' file which can be copied to the Pico file system which can be imported as if they were '.py' modules. In theory, as easy as '.py' with the benefit of native execution and not having to touch or even build the MicroPython source code.

To allow the importing of a '.mpy' file that file has to conform with what MicroPython allows, and that means a limited set of functions which are defined and usable for the C source. So things like 'mp_obj_str_get_str' are defined, available and usable, but 'strlen' isn't. If one wants to use 'strlen' one has to provide it in the source. Its no good using

*#include "strings.h"* because, while that will allow the code to compile, a 'strlen' implementation won't be found when it comes to linking.

The problem here is that when 'make' is run and a division or modulo is performed, GCC emits calls to '__aeabi_idivmod' etc but the MicroPython provided linker used to create the final '.mpy' file has no clue what they are. They are not catered for by MicroPython when imported, so are reported as functions the user needs to define in their C code but hasn't. That's fair enough for things like 'strlen' but it's a PITA when division and modulo requires doing that.

I expect the solution is to make MicroPython aware of needing to provide and support ''__aeabi_idivmod' etc for the Pico but I have no idea of how to do that and it would be something which really needs to be done by the MicroPython team. Until then the only option is to provide the missing routines oneself in the C source or an include file.

I believe I have achieved that because it works when tested from a module wrapper and are a lot quicker than MicroPython's in-built division and modulo operators which need to be a lot more generic. But, for some reason, not in more involved code where I would like them to work and I haven't got to the bottom of that.

I am also struggling with negative values where MicroPython has -10 // 3 giving -4 and -10 % 3 giving 2, when I was expecting -3 and -1. Not sure if that's my C mod operator which is wrong or my implementation of my MicroPython mod equivalent. It never ends

**mpylib.h**
Code: Select all

```
uint __aeabi_uidivmod(uint arg_lhs, uint arg_rhs) {
uint lhs = arg_lhs;
uint rhs = arg_rhs;
uint res = 0;
uint rem = 0;
for (int i = 0; i < 32; i++) {
res = res << 1;
rem = rem << 1;
rem |= (lhs >> 31) & 1;
lhs = lhs << 1;
if (rhs <= rem) {
rem = rem - rhs;
res = res | 1;
}
}
__asm("mov r1, %0" : : "r" (rem) : "r1");
return res;
}
uint __aeabi_uidiv(uint arg_lhs, uint arg_rhs) {
return __aeabi_uidivmod(arg_lhs, arg_rhs);
}
int __aeabi_idiv(int lhs, int rhs) {
if (rhs == 0) {
return 0;
}
if (lhs >= 0) {
if (rhs >= 0) { // + +
uint uint_lhs = lhs;
uint uint_rhs = rhs;
return uint_lhs / uint_rhs;
} else { // + -
uint uint_lhs = lhs;
uint uint_rhs = -rhs;
return -(uint_lhs / uint_rhs);
}
} else {
if (rhs >= 0) { // - +
uint uint_lhs = -lhs;
uint uint_rhs = rhs;
return -(uint_lhs / uint_rhs);
} else { // - -
uint uint_lhs = -lhs;
uint uint_rhs = -rhs;
return uint_lhs / uint_rhs;
}
}
}
int __aeabi_idivmod(int lhs, int rhs) {
uint uint_lhs = 0;
uint uint_rhs = 0;
uint uint_res = 0;
int int__res = 0;
if (rhs == 0) {
int_res = lhs;
}
else if (lhs >= 0) {
if (rhs >= 0) { // + +
uint_lhs = lhs;
uint_rhs = rhs;
} else { // + -
uint_lhs = lhs;
uint_rhs = -rhs;
}
uint_res = uint_lhs % uint_rhs;
int__res = uint_res;
} else {
if (rhs >= 0) { // - +
uint_lhs = -lhs;
uint_rhs = rhs;
} else { // - -
uint_lhs = -lhs;
uint_rhs = -rhs;
}
uint_res = uint_lhs % uint_rhs;
int__res = -uint_res;
}
__asm("mov r1, %0" : : "r" (int__res) : "r1");
return int__res;
}
```