From 241da7fbed84f2635af1d5b068a4671eb2520a00 Mon Sep 17 00:00:00 2001 From: Michal Moskal Date: Sat, 2 Apr 2016 11:22:36 -0700 Subject: [PATCH] Add remaining shims --- libs/microbit/core.cpp | 219 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 219 insertions(+) diff --git a/libs/microbit/core.cpp b/libs/microbit/core.cpp index 80e2722f..14da2265 100644 --- a/libs/microbit/core.cpp +++ b/libs/microbit/core.cpp @@ -67,6 +67,9 @@ namespace BooleanMethods { return (StringData*)(void*)sFalse; } } + + //% + bool bang(bool v) { return !v; } } namespace String { @@ -83,6 +86,19 @@ namespace String { int toNumber(StringData *s) { return atoi(s->data); } + + //% + StringData *mkEmpty() + { + return ManagedString::EmptyString.leakData(); + } + + // The proper StringData* representation is already laid out in memory by the code generator. + //% + uint32_t mkLiteral(uint32_t lit) + { + return (uint32_t)getstr(lit); + } } namespace NumberMethods { @@ -96,6 +112,30 @@ namespace NumberMethods { } } +namespace NumberImpl { + // +, - and friends are handled directly by assembly instructions + // The comparisons are here as they are more code-size efficient + + //% + bool lt(int x, int y) { return x < y; } + //% + bool le(int x, int y) { return x <= y; } + //% + bool neq(int x, int y) { return x != y; } + //% + bool eq(int x, int y) { return x == y; } + //% + bool gt(int x, int y) { return x > y; } + //% + bool ge(int x, int y) { return x >= y; } + + // These in fact call into C runtime on Cortex-M0 + //% + int div(int x, int y) { return x / y; } + //% + int mod(int x, int y) { return x % y; } +} + namespace Math { /** * Returns the value of a base expression taken to a specified power. @@ -231,3 +271,182 @@ namespace ArrayImpl { } } +namespace ActionImpl { + //% + Action mk(int reflen, int totallen, int startptr) + { + check(0 <= reflen && reflen <= totallen, ERR_SIZE, 1); + check(reflen <= totallen && totallen <= 255, ERR_SIZE, 2); + check(bytecode[startptr] == 0xffff, ERR_INVALID_BINARY_HEADER, 3); + check(bytecode[startptr + 1] == 0, ERR_INVALID_BINARY_HEADER, 4); + + + uint32_t tmp = (uint32_t)&bytecode[startptr]; + + if (totallen == 0) { + return tmp; // no closure needed + } + + void *ptr = ::operator new(sizeof(RefAction) + totallen * sizeof(uint32_t)); + RefAction *r = new (ptr) RefAction(); + r->len = totallen; + r->reflen = reflen; + r->func = (ActionCB)((tmp + 4) | 1); + memset(r->fields, 0, r->len * sizeof(uint32_t)); + + return (Action)r; + } + + //% + uint32_t mkLiteral(uint32_t lit) + { + return (uint32_t)getstr(lit); + } + + //% + void run1(Action a, int arg) + { + if (hasVTable(a)) + ((RefAction*)a)->run(arg); + else { + check(*(uint16_t*)a == 0xffff, ERR_INVALID_BINARY_HEADER, 4); + ((ActionCB)((a + 4) | 1))(NULL, NULL, arg); + } + } + + //% + void run(Action a) + { + ActionImpl::run1(a, 0); + } +} + +namespace RecordImpl { + //% + RefRecord* mk(int reflen, int totallen) + { + check(0 <= reflen && reflen <= totallen, ERR_SIZE, 1); + check(reflen <= totallen && totallen <= 255, ERR_SIZE, 2); + + void *ptr = ::operator new(sizeof(RefRecord) + totallen * sizeof(uint32_t)); + RefRecord *r = new (ptr) RefRecord(); + r->len = totallen; + r->reflen = reflen; + memset(r->fields, 0, r->len * sizeof(uint32_t)); + return r; + } +} + +namespace ksrt { + //% + uint32_t ldloc(RefLocal *r) { + return r->v; + } + + //% + uint32_t ldlocRef(RefRefLocal *r) { + uint32_t tmp = r->v; + incr(tmp); + return tmp; + } + + //% + void stloc(RefLocal *r, uint32_t v) { + r->v = v; + } + + //% + void stlocRef(RefRefLocal *r, uint32_t v) { + decr(r->v); + r->v = v; + } + + //% + RefLocal *mkloc() { + return new RefLocal(); + } + + //% + RefRefLocal *mklocRef() { + return new RefRefLocal(); + } + + // All of the functions below unref() self. This is for performance reasons - + // the code emitter will not emit the unrefs for them. + + //% + uint32_t ldfld(RefRecord *r, int idx) { + auto tmp = r->ld(idx); + r->unref(); + return tmp; + } + + //% + uint32_t ldfldRef(RefRecord *r, int idx) { + auto tmp = r->ldref(idx); + r->unref(); + return tmp; + } + + //% + void stfld(RefRecord *r, int idx, uint32_t val) { + r->st(idx, val); + r->unref(); + } + + //% + void stfldRef(RefRecord *r, int idx, uint32_t val) { + r->stref(idx, val); + r->unref(); + } + + //% + uint32_t ldglb(int idx) { + check(0 <= idx && idx < numGlobals, ERR_OUT_OF_BOUNDS, 7); + return globals[idx]; + } + + //% + uint32_t ldglbRef(int idx) { + check(0 <= idx && idx < numGlobals, ERR_OUT_OF_BOUNDS, 7); + uint32_t tmp = globals[idx]; + incr(tmp); + return tmp; + } + + // note the idx comes last - it's more convenient that way in the emitter + //% + void stglb(uint32_t v, int idx) + { + check(0 <= idx && idx < numGlobals, ERR_OUT_OF_BOUNDS, 7); + globals[idx] = v; + } + + //% + void stglbRef(uint32_t v, int idx) + { + check(0 <= idx && idx < numGlobals, ERR_OUT_OF_BOUNDS, 7); + decr(globals[idx]); + globals[idx] = v; + } + + // Store a captured local in a closure. It returns the action, so it can be chained. + //% + RefAction *stclo(RefAction *a, int idx, uint32_t v) + { + //DBG("STCLO "); a->print(); DBG("@%d = %p\n", idx, (void*)v); + a->st(idx, v); + return a; + } + + //% + uint32_t incr(uint32_t ptr) { + bitvm::incr(ptr); + return ptr; + } + + //% + void decr(uint32_t ptr) { + bitvm::decr(ptr); + } +}