Support latest PXT with GC (#1798)
* Enable gc and basic compilation fixes * Add missing GC stuff * Set microbit-dal version * Disable jacdac in servo * UTF fixes * TS build fixes * Auto-generated files update * We only seem to have that much * Fix for new new compiler * Account for uninitialized scheduler * Intialize memory allocator * bump references * updated package * Set image tag, requires https://github.com/Microsoft/pxt/pull/5262 * updated project summaries * Fixing block tests
This commit is contained in:
@ -4,10 +4,14 @@
|
||||
"AcceleratorRange.OneG": "The accelerator measures forces up to 1 gravity",
|
||||
"AcceleratorRange.TwoG": "The accelerator measures forces up to 2 gravity",
|
||||
"Array": "Add, remove, and replace items in lists.\n\nAdd, remove, and replace items in lists.",
|
||||
"Array.concat": "Concatenates the values with another array.",
|
||||
"Array.concat|param|arr": "The other array that is being concatenated with",
|
||||
"Array.every": "Tests whether all elements in the array pass the test implemented by the provided function.",
|
||||
"Array.every|param|callbackfn": "A function that accepts up to two arguments. The every method calls the callbackfn function one time for each element in the array.",
|
||||
"Array.fill": "Fills all the elements of an array from a start index to an end index with a static value. The end index is not included.",
|
||||
"Array.filter": "Return the elements of an array that meet the condition specified in a callback function.",
|
||||
"Array.filter|param|callbackfn": "A function that accepts up to two arguments. The filter method calls the callbackfn function one time for each element in the array.",
|
||||
"Array.find": "Returns the value of the first element in the array that satisfies the provided testing function. Otherwise undefined is returned.",
|
||||
"Array.forEach": "Call a defined callback function on each element of an array.",
|
||||
"Array.forEach|param|callbackfn": "A function that accepts up to two arguments. The forEach method calls the callbackfn function one time for each element in the array.",
|
||||
"Array.get": "Get the value at a particular index",
|
||||
@ -17,6 +21,7 @@
|
||||
"Array.indexOf|param|item": "The value to locate in the array.",
|
||||
"Array.insertAt": "Insert the value at a particular index, increases length by 1",
|
||||
"Array.insertAt|param|index": "the zero-based position in the list to insert the value, eg: 0",
|
||||
"Array.isArray": "Check if a given object is an array.",
|
||||
"Array.join": "joins all elements of an array into a string and returns this string.",
|
||||
"Array.join|param|sep": "the string separator",
|
||||
"Array.length": "Get or set the length of an array. This number is one more than the index of the last element the array.",
|
||||
@ -58,6 +63,7 @@
|
||||
"Buffer.shift|param|start": "start offset in buffer. Default is 0.",
|
||||
"Buffer.slice": "Return a copy of a fragment of a buffer.",
|
||||
"Buffer.toHex": "Convert a buffer to its hexadecimal representation.",
|
||||
"Buffer.toString": "Convert a buffer to string assuming UTF8 encoding",
|
||||
"Buffer.write": "Write contents of `src` at `dstOffset` in current buffer.",
|
||||
"EventCreationMode": "How to create the event.",
|
||||
"EventCreationMode.CreateAndFire": "MicroBitEvent is initialised, and its event handlers are immediately fired (not suitable for use in interrupts!).",
|
||||
@ -160,6 +166,7 @@
|
||||
"Math.trunc": "Returns the number with the decimal part truncated.",
|
||||
"Math.trunc|param|x": "A numeric expression.",
|
||||
"Number.toString": "Returns a string representation of a number.",
|
||||
"Object.keys": "Return the field names in an object.",
|
||||
"String": "Combine, split, and search text strings.\n\nCombine, split, and search text strings.",
|
||||
"String.charAt": "Return the character at the specified index.",
|
||||
"String.charAt|param|index": "The zero-based index of the desired character.",
|
||||
@ -178,6 +185,11 @@
|
||||
"String.indexOf|param|start": "optional start index for the search",
|
||||
"String.isEmpty": "Returns a value indicating if the string is empty",
|
||||
"String.length": "Returns the length of a String object.",
|
||||
"String.slice": "Return a substring of the current string.",
|
||||
"String.slice|param|end": "one-past-last character index",
|
||||
"String.slice|param|start": "first character index; can be negative from counting from the end, eg:0",
|
||||
"String.split": "Splits the string according to the separators",
|
||||
"String.split|param|separator": "@param limit ",
|
||||
"String.substr": "Return a substring of the current string.",
|
||||
"String.substr|param|length": "number of characters to extract",
|
||||
"String.substr|param|start": "first character index; can be negative from counting from the end, eg:0",
|
||||
@ -195,7 +207,7 @@
|
||||
"basic.showArrow|param|direction": "the direction of the arrow",
|
||||
"basic.showArrow|param|interval": "the amount of time (milliseconds) to show the icon. Default is 600.",
|
||||
"basic.showIcon": "Draws the selected icon on the LED screen",
|
||||
"basic.showIcon|param|icon": "the predifined icon id",
|
||||
"basic.showIcon|param|icon": "the predefined icon id",
|
||||
"basic.showIcon|param|interval": "the amount of time (milliseconds) to show the icon. Default is 600.",
|
||||
"basic.showLeds": "Draws an image on the LED screen.",
|
||||
"basic.showLeds|param|interval": "time in milliseconds to pause after drawing",
|
||||
@ -214,6 +226,8 @@
|
||||
"control": "Runtime and event utilities.",
|
||||
"control.assert": "If the condition is false, display msg on serial console, and panic with code 098.",
|
||||
"control.createBuffer": "Create a new zero-initialized buffer.",
|
||||
"control.createBufferFromUTF8": "Create a new buffer with UTF8-encoded string",
|
||||
"control.createBufferFromUTF8|param|str": "the string to put in the buffer",
|
||||
"control.createBuffer|param|size": "number of bytes in the buffer",
|
||||
"control.deviceName": "Make a friendly name for the device based on its serial number",
|
||||
"control.deviceSerialNumber": "Derive a unique, consistent serial number of this device from internal data.",
|
||||
|
@ -213,6 +213,7 @@
|
||||
"Note.GSharp4|block": "G#4",
|
||||
"Note.GSharp5|block": "G#5",
|
||||
"Note.GSharp|block": "G#",
|
||||
"Object|block": "Object",
|
||||
"PinEvent.Fall|block": "fall",
|
||||
"PinEvent.PulseHigh|block": "pulse high",
|
||||
"PinEvent.PulseLow|block": "pulse low",
|
||||
@ -389,6 +390,7 @@
|
||||
"{id:category}Msgpack": "Msgpack",
|
||||
"{id:category}Music": "Music",
|
||||
"{id:category}Number": "Number",
|
||||
"{id:category}Object": "Object",
|
||||
"{id:category}Pins": "Pins",
|
||||
"{id:category}PwmOnlyPin": "PwmOnlyPin",
|
||||
"{id:category}Serial": "Serial",
|
||||
|
@ -37,14 +37,14 @@ namespace basic {
|
||||
void showString(String text, int interval = 150) {
|
||||
if (interval <= 0)
|
||||
interval = 1;
|
||||
int l = text ? text->length : 0;
|
||||
int l = text ? text->getUTF8Size() : 0;
|
||||
if (l == 0) {
|
||||
uBit.display.clear();
|
||||
fiber_sleep(interval * 5);
|
||||
} else if (l > 1) {
|
||||
uBit.display.scroll(MSTR(text), interval);
|
||||
} else {
|
||||
uBit.display.printChar(text->data[0], interval * 5);
|
||||
uBit.display.printChar(text->getUTF8Data()[0], interval * 5);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -8,7 +8,7 @@
|
||||
<block type="device_play_note">
|
||||
<value name="note">
|
||||
<shadow type="device_note">
|
||||
<field name="note">175</field>
|
||||
<field name="name">175</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<value name="duration">
|
||||
@ -20,7 +20,7 @@
|
||||
<block type="device_ring">
|
||||
<value name="note">
|
||||
<shadow type="device_note">
|
||||
<field name="note">147</field>
|
||||
<field name="name">147</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<next>
|
||||
@ -38,7 +38,7 @@
|
||||
<field name="NUM">0</field>
|
||||
</shadow>
|
||||
<block type="device_note">
|
||||
<field name="note">466</field>
|
||||
<field name="name">466</field>
|
||||
</block>
|
||||
</value>
|
||||
<next>
|
||||
|
@ -241,7 +241,7 @@
|
||||
<block type="device_play_note">
|
||||
<value name="note">
|
||||
<shadow type="device_note">
|
||||
<field name="note">220</field>
|
||||
<field name="name">220</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<value name="duration">
|
||||
@ -253,7 +253,7 @@
|
||||
<block type="device_ring">
|
||||
<value name="note">
|
||||
<shadow type="device_note">
|
||||
<field name="note">659</field>
|
||||
<field name="name">659</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<next>
|
||||
@ -432,7 +432,7 @@
|
||||
<field name="SLIDER">255</field>
|
||||
</shadow>
|
||||
<block type="device_note">
|
||||
<field name="note">440</field>
|
||||
<field name="name">440</field>
|
||||
</block>
|
||||
</value>
|
||||
<next>
|
||||
|
@ -8,15 +8,13 @@ PXT_ABI(__aeabi_dsub)
|
||||
PXT_ABI(__aeabi_ddiv)
|
||||
PXT_ABI(__aeabi_dmul)
|
||||
|
||||
extern "C" void target_panic(int error_code)
|
||||
{
|
||||
extern "C" void target_panic(int error_code) {
|
||||
// wait for serial to flush
|
||||
wait_us(300000);
|
||||
microbit_panic(error_code);
|
||||
}
|
||||
|
||||
extern "C" void target_reset()
|
||||
{
|
||||
extern "C" void target_reset() {
|
||||
microbit_reset();
|
||||
}
|
||||
|
||||
@ -76,6 +74,7 @@ void registerWithDal(int id, int event, Action a, int flags) {
|
||||
|
||||
void fiberDone(void *a) {
|
||||
decr((Action)a);
|
||||
unregisterGCPtr((Action)a);
|
||||
release_fiber();
|
||||
}
|
||||
|
||||
@ -101,6 +100,7 @@ void forever_stub(void *a) {
|
||||
void runForever(Action a) {
|
||||
if (a != 0) {
|
||||
incr(a);
|
||||
registerGCPtr(a);
|
||||
create_fiber(forever_stub, (void *)a);
|
||||
}
|
||||
}
|
||||
@ -108,6 +108,7 @@ void runForever(Action a) {
|
||||
void runInParallel(Action a) {
|
||||
if (a != 0) {
|
||||
incr(a);
|
||||
registerGCPtr(a);
|
||||
create_fiber((void (*)(void *))runAction0, (void *)a, fiberDone);
|
||||
}
|
||||
}
|
||||
@ -129,31 +130,24 @@ unsigned afterProgramPage() {
|
||||
return ptr;
|
||||
}
|
||||
|
||||
|
||||
int current_time_ms() {
|
||||
return system_timer_current_time();
|
||||
}
|
||||
|
||||
static void logwriten(const char *msg, int l)
|
||||
{
|
||||
uBit.serial.send((uint8_t*)msg, l);
|
||||
static void logwriten(const char *msg, int l) {
|
||||
uBit.serial.send((uint8_t *)msg, l);
|
||||
}
|
||||
|
||||
static void logwrite(const char *msg)
|
||||
{
|
||||
static void logwrite(const char *msg) {
|
||||
logwriten(msg, strlen(msg));
|
||||
}
|
||||
|
||||
|
||||
static void writeNum(char *buf, uint32_t n, bool full)
|
||||
{
|
||||
static void writeNum(char *buf, uint32_t n, bool full) {
|
||||
int i = 0;
|
||||
int sh = 28;
|
||||
while (sh >= 0)
|
||||
{
|
||||
while (sh >= 0) {
|
||||
int d = (n >> sh) & 0xf;
|
||||
if (full || d || sh == 0 || i)
|
||||
{
|
||||
if (full || d || sh == 0 || i) {
|
||||
buf[i++] = d > 9 ? 'A' + d - 10 : '0' + d;
|
||||
}
|
||||
sh -= 4;
|
||||
@ -161,35 +155,27 @@ static void writeNum(char *buf, uint32_t n, bool full)
|
||||
buf[i] = 0;
|
||||
}
|
||||
|
||||
static void logwritenum(uint32_t n, bool full, bool hex)
|
||||
{
|
||||
static void logwritenum(uint32_t n, bool full, bool hex) {
|
||||
char buff[20];
|
||||
|
||||
if (hex)
|
||||
{
|
||||
if (hex) {
|
||||
writeNum(buff, n, full);
|
||||
logwrite("0x");
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
itoa(n, buff);
|
||||
}
|
||||
|
||||
logwrite(buff);
|
||||
}
|
||||
|
||||
void vdebuglog(const char *format, va_list ap)
|
||||
{
|
||||
void vdebuglog(const char *format, va_list ap) {
|
||||
const char *end = format;
|
||||
|
||||
while (*end)
|
||||
{
|
||||
if (*end++ == '%')
|
||||
{
|
||||
while (*end) {
|
||||
if (*end++ == '%') {
|
||||
logwriten(format, end - format - 1);
|
||||
uint32_t val = va_arg(ap, uint32_t);
|
||||
switch (*end++)
|
||||
{
|
||||
switch (*end++) {
|
||||
case 'c':
|
||||
logwriten((const char *)&val, 1);
|
||||
break;
|
||||
@ -220,8 +206,7 @@ void vdebuglog(const char *format, va_list ap)
|
||||
logwrite("\n");
|
||||
}
|
||||
|
||||
void debuglog(const char *format, ...)
|
||||
{
|
||||
void debuglog(const char *format, ...) {
|
||||
va_list arg;
|
||||
va_start(arg, format);
|
||||
vdebuglog(format, arg);
|
||||
@ -232,7 +217,57 @@ void sendSerial(const char *data, int len) {
|
||||
logwriten(data, len);
|
||||
}
|
||||
|
||||
#ifdef PXT_GC
|
||||
ThreadContext *getThreadContext() {
|
||||
if (!currentFiber)
|
||||
return NULL;
|
||||
return (ThreadContext *)currentFiber->user_data;
|
||||
}
|
||||
|
||||
void setThreadContext(ThreadContext *ctx) {
|
||||
currentFiber->user_data = ctx;
|
||||
}
|
||||
|
||||
static void *threadAddressFor(Fiber *fib, void *sp) {
|
||||
if (fib == currentFiber)
|
||||
return sp;
|
||||
return (uint8_t *)sp + ((uint8_t *)fib->stack_top - (uint8_t *)fib->tcb.stack_base);
|
||||
}
|
||||
|
||||
void gcProcessStacks(int flags) {
|
||||
// check scheduler is initialized
|
||||
if (!currentFiber) {
|
||||
// make sure we allocate something to at least initalize the memory allocator
|
||||
void * volatile p = xmalloc(1);
|
||||
xfree(p);
|
||||
return;
|
||||
}
|
||||
|
||||
int numFibers = list_fibers(NULL);
|
||||
Fiber **fibers = (Fiber **)xmalloc(sizeof(Fiber *) * numFibers);
|
||||
int num2 = list_fibers(fibers);
|
||||
if (numFibers != num2)
|
||||
oops(12);
|
||||
int cnt = 0;
|
||||
|
||||
for (int i = 0; i < numFibers; ++i) {
|
||||
auto fib = fibers[i];
|
||||
auto ctx = (ThreadContext *)fib->user_data;
|
||||
if (!ctx)
|
||||
continue;
|
||||
for (auto seg = &ctx->stack; seg; seg = seg->next) {
|
||||
auto ptr = (TValue *)threadAddressFor(fib, seg->top);
|
||||
auto end = (TValue *)threadAddressFor(fib, seg->bottom);
|
||||
if (flags & 2)
|
||||
DMESG("RS%d:%p/%d", cnt++, ptr, end - ptr);
|
||||
// VLOG("mark: %p - %p", ptr, end);
|
||||
while (ptr < end) {
|
||||
gcProcess(*ptr++);
|
||||
}
|
||||
}
|
||||
}
|
||||
xfree(fibers);
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace pxt
|
||||
|
||||
|
||||
|
||||
|
@ -318,6 +318,6 @@ namespace control {
|
||||
//%
|
||||
void __log(String text) {
|
||||
if (NULL == text) return;
|
||||
pxt::sendSerial(text->data, text->length);
|
||||
pxt::sendSerial(text->getUTF8Data(), text->getUTF8Size());
|
||||
}
|
||||
}
|
||||
|
9
libs/core/enums.d.ts
vendored
9
libs/core/enums.d.ts
vendored
@ -22,13 +22,8 @@
|
||||
}
|
||||
|
||||
|
||||
declare const enum ValType {
|
||||
Undefined = 0,
|
||||
Boolean = 1,
|
||||
Number = 2,
|
||||
String = 3,
|
||||
Object = 4,
|
||||
Function = 5,
|
||||
declare const enum PerfCounters {
|
||||
GC = 0,
|
||||
}
|
||||
declare namespace images {
|
||||
}
|
||||
|
@ -1,7 +1,6 @@
|
||||
#include "pxt.h"
|
||||
|
||||
PXT_VTABLE_BEGIN(RefMImage, 0, 0)
|
||||
PXT_VTABLE_END
|
||||
PXT_VTABLE(RefMImage)
|
||||
|
||||
RefMImage::RefMImage(ImageData *d) : PXT_VTABLE_INIT(RefMImage), img(d) {
|
||||
img->incr();
|
||||
@ -22,6 +21,12 @@ void RefMImage::makeWritable() {
|
||||
}
|
||||
}
|
||||
|
||||
void RefMImage::scan(RefMImage *t) {}
|
||||
|
||||
unsigned RefMImage::gcsize(RefMImage *t) {
|
||||
return (sizeof(*t) + 3) >> 2;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creation, manipulation and display of LED images.
|
||||
*/
|
||||
@ -64,8 +69,8 @@ void plotImage(Image i, int xOffset = 0) {
|
||||
* @param xOffset column index to start displaying the image
|
||||
*/
|
||||
//% help=images/show-image weight=80 blockNamespace=images
|
||||
//% blockId=device_show_image_offset block="show image %sprite(myImage)|at offset %offset" blockGap=8
|
||||
//% parts="ledmatrix" async
|
||||
//% blockId=device_show_image_offset block="show image %sprite(myImage)|at offset %offset"
|
||||
//% blockGap=8 parts="ledmatrix" async
|
||||
void showImage(Image sprite, int xOffset, int interval = 400) {
|
||||
uBit.display.print(MicroBitImage(sprite->img), -xOffset, 0, 0, interval);
|
||||
}
|
||||
|
@ -17,9 +17,11 @@ class RefMImage : public RefObject {
|
||||
void makeWritable();
|
||||
static void destroy(RefMImage *map);
|
||||
static void print(RefMImage *map);
|
||||
static void scan(RefMImage *t);
|
||||
static unsigned gcsize(RefMImage *t);
|
||||
};
|
||||
|
||||
#define MSTR(s) ManagedString((s)->data, (s)->length)
|
||||
#define MSTR(s) ManagedString((s)->getUTF8Data(), (s)->getUTF8Size())
|
||||
|
||||
static inline String PSTR(ManagedString s) {
|
||||
return mkString(s.toCharArray(), s.length());
|
||||
@ -28,7 +30,7 @@ static inline String PSTR(ManagedString s) {
|
||||
typedef uint32_t ImageLiteral_;
|
||||
|
||||
static inline ImageData *imageBytes(ImageLiteral_ lit) {
|
||||
return (ImageData*)ptrOfLiteral(lit);
|
||||
return (ImageData *)lit;
|
||||
}
|
||||
|
||||
typedef RefMImage *Image;
|
||||
@ -39,16 +41,20 @@ extern MicroBitEvent lastEvent;
|
||||
MicroBitPin *getPin(int id);
|
||||
|
||||
static inline int min_(int a, int b) {
|
||||
if (a < b) return a;
|
||||
else return b;
|
||||
if (a < b)
|
||||
return a;
|
||||
else
|
||||
return b;
|
||||
}
|
||||
|
||||
static inline int max_(int a, int b) {
|
||||
if (a > b) return a;
|
||||
else return b;
|
||||
if (a > b)
|
||||
return a;
|
||||
else
|
||||
return b;
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace pxt
|
||||
|
||||
using namespace pxt;
|
||||
|
||||
|
@ -18,6 +18,8 @@
|
||||
"pxt-helpers.ts",
|
||||
"helpers.ts",
|
||||
"pinscompat.ts",
|
||||
"configkeys.h",
|
||||
"gc.cpp",
|
||||
"codal.cpp",
|
||||
"images.cpp",
|
||||
"basic.cpp",
|
||||
@ -50,6 +52,7 @@
|
||||
"yotta": {
|
||||
"optionalConfig": {
|
||||
"microbit-dal": {
|
||||
"fiber_user_data": 1,
|
||||
"bluetooth": {
|
||||
"private_addressing": 0,
|
||||
"advertising_timeout": 0,
|
||||
|
@ -10,6 +10,11 @@ namespace pxt {
|
||||
void debuglog(const char *format, ...);
|
||||
}
|
||||
|
||||
// #define GC_GET_HEAP_SIZE() device_heap_size(0)
|
||||
#define xmalloc malloc
|
||||
#define xfree free
|
||||
|
||||
#define GC_BLOCK_SIZE 1000
|
||||
|
||||
#define DMESG NOLOG
|
||||
|
||||
|
17
libs/core/shims.d.ts
vendored
17
libs/core/shims.d.ts
vendored
@ -39,8 +39,8 @@ declare interface Image {
|
||||
* @param xOffset column index to start displaying the image
|
||||
*/
|
||||
//% help=images/show-image weight=80 blockNamespace=images
|
||||
//% blockId=device_show_image_offset block="show image %sprite(myImage)|at offset %offset" blockGap=8
|
||||
//% parts="ledmatrix" async interval.defl=400 shim=ImageMethods::showImage
|
||||
//% blockId=device_show_image_offset block="show image %sprite(myImage)|at offset %offset"
|
||||
//% blockGap=8 parts="ledmatrix" async interval.defl=400 shim=ImageMethods::showImage
|
||||
showImage(xOffset: int32, interval?: int32): void;
|
||||
|
||||
/**
|
||||
@ -898,6 +898,12 @@ declare interface Buffer {
|
||||
//% start.defl=0 length.defl=-1 shim=BufferMethods::shift
|
||||
shift(offset: int32, start?: int32, length?: int32): void;
|
||||
|
||||
/**
|
||||
* Convert a buffer to string assuming UTF8 encoding
|
||||
*/
|
||||
//% shim=BufferMethods::toString
|
||||
toString(): string;
|
||||
|
||||
/**
|
||||
* Convert a buffer to its hexadecimal representation.
|
||||
*/
|
||||
@ -928,6 +934,13 @@ declare namespace control {
|
||||
*/
|
||||
//% shim=control::createBuffer
|
||||
function createBuffer(size: int32): Buffer;
|
||||
|
||||
/**
|
||||
* Create a new buffer with UTF8-encoded string
|
||||
* @param str the string to put in the buffer
|
||||
*/
|
||||
//% shim=control::createBufferFromUTF8
|
||||
function createBufferFromUTF8(str: string): Buffer;
|
||||
}
|
||||
|
||||
// Auto-generated. Do not edit. Really.
|
||||
|
Reference in New Issue
Block a user