Squashed 'lispBM/lispBM/' changes from e76a3deb..fe7a709d

fe7a709d added some benchresults and twear benchmark code to remove the reference to the stepping functionality
965c2543 uninlined stack popping procedures
7ea5f3bd Change GC treatment of freelist when GC is invoked and freelist is non-empty
7bc24eef update changelog
d7d158e0 added 5 tests related to quasiquotation
b26bf5f8 update
5309b8e7 Update README
918b4aee update README

git-subtree-dir: lispBM/lispBM
git-subtree-split: fe7a709d1942fbc88461e9313d91220ba97ab3e8
This commit is contained in:
Benjamin Vedder 2022-10-17 14:42:17 +02:00
parent 898e4df503
commit b924552400
16 changed files with 180 additions and 140 deletions

View File

@ -7,8 +7,8 @@ process monitoring. The LispBM runtime system can be compiled for
either 32 or 64 bit platforms and runs on a wide range of hardware
such as for example STM32, NRF52, ESP32 or X86. When running the
LispBM runtime system on a microcontroller it can be built on top of
ChibiOS, FreeRTOS or ZephyrOS and it can also be built to run on top
of a regular linux.
ChibiOS, FreeRTOS or ZephyrOS or, if you are adventurous, on bare-metal.
LispBM can also be built to run on topof a regular linux.
![LispBM mascot](https://github.com/svenssonjoel/lispBM/blob/master/mascot/lispbm_llama_small.png)
@ -32,48 +32,32 @@ LispBM runtime system.
- LispBM's internals are documented as a series of [blog posts](http://svenssonjoel.github.io).
- There are [demonstrations on YouTube](https://youtube.com/playlist?list=PLtf_3TaqZoDOQqZcB9Yj-R1zS2DWDZ9q9).
## Purpose
1. Have fun.
2. Learn about lisp.
3. Learn about microcontrollers.
4. An interactive REPL for devboards.
5. ...
## Features
1. heap consisting of cons-cells with mark and sweep garbage collection.
2. Built-in functions: cons, car, cdr, eval, list, +, -, >, <, = and more.
3. Some special forms: Lambdas, closures, lets (letrecs), define and quote.
4. 28-Bit signed/unsigned integers and boxed 32-Bit Float, 32-Bit signed/unsigned values.
5. Arrays (in progress), string is an array.
6. Compiles for, and runs on linux-x86.
7. Compiles for, and runs on Zynq 7000.
8. Compiles for, and runs on STM32f4.
9. Compiles for, and runs on NRF52840.
10. Compiles for, and runs on ESP32 (ARM - WROOM).
11. Compiles for, and runs on ESP32C3 (RISC-V).
12. Compiles for, and runs on Raspberry PI (Tested on 32bit Raspbian OS)
13. Quasiquotation.
14. Concurrency.
15. Message-passing.
16. Pattern-matching.
6. Quasiquotation.
7. Concurrency.
8. Message-passing.
9. Pattern-matching.
## Vague or continuosly ongoing todos
1. Doxygen?
2. Tutorials?
3. Be much more stringent on checking of error conditions etc.
4. More built in arithmetic.
5. More built in comparisons.
6. Make uniform how to return success or failure. It is sometimes bool and sometimes int right now.
## Compile a 32bit binary for linux (Requires 32bit libraries. May need something like "multilib" on a 64bit linux)
1. Build the repl: `cd repl-cps` and then `make`
2. Run the repl: `./repl`
4. Make uniform how to return success or failure. It is sometimes bool and sometimes int right now.
## Compile a 64bit binary for linux
1. Build the repl: `cd repl-cps` and then `make all64`
1. Build the repl: `cd repl` and then `make all64`
2. Run the repl: `./repl`
## Compile a 32bit binary for linux (Requires 32bit libraries. May need something like "multilib" on a 64bit linux)
1. Build the repl: `cd repl` and then `make`
2. Run the repl: `./repl`
@ -85,10 +69,10 @@ To build the library exeute the following command in the lispbm folder:
PLATFORM=pi make
```
To build the `repl-cps` example repl do:
To build the `repl` example repl do:
```
cd repl-cps
cd repl
make pirepl
```

View File

@ -308,15 +308,9 @@ int main(void) {
while(lbm_get_eval_state() != EVAL_CPS_STATE_PAUSED) {
sleep_callback(10);
}
chprintf(chp, "Evaluator paused\r\nEnter command :continue to unpause or :step to perform single stepping\r\n");
chprintf(chp, "Evaluator paused\r\nEnter command :continue to unpause\r\n");
} else if (strncmp(str, ":continue", 9) == 0) {
lbm_continue_eval();
} else if (strncmp(str, ":step", 5) == 0) {
lbm_step_eval();
while(lbm_get_eval_state() != EVAL_CPS_STATE_PAUSED) {
chThdSleepMilliseconds(1);
}
chprintf(chp, "Evaluator paused\r\nEnter command :continue to unpause or :step to perform single stepping\r\n");
} else if (strncmp(str, ":reset", 6) == 0) {
lbm_pause_eval();
while(lbm_get_eval_state() != EVAL_CPS_STATE_PAUSED) {

View File

@ -0,0 +1,9 @@
File, Load time (s), Eval time (s), GC avg time (us), GC min time (us), GC max time (us), GC invocations, GC least free
insertionsort.lisp, 0.004000000, 0.006000000, 300.000000000, 300, 300, 2, 2047
fibonacci.lisp, 0.001799999, 3.269000053, 486.170227050, 300, 500, 94, 1968
tak.lisp, 0.002799999, 2.888799905, 527.586181640, 300, 600, 203, 1854
dec_cnt2.lisp, 0.001500000, 2.536499977, 472.000000000, 300, 500, 100, 2014
dec_cnt3.lisp, 0.002000000, 1.104599952, 453.333343505, 300, 500, 15, 1996
dec_cnt1.lisp, 0.001500000, 3.108999967, 471.000000000, 300, 500, 100, 2014
fibonacci_tail.lisp, 0.002799999, 0.004699999, 3, 300, 300, 1, 2047
q2.lisp, 0.002700000, 1.347000002, 513.793090820, 300, 600, 58, 1920

View File

@ -0,0 +1,9 @@
File, Load time (s), Eval time (s), GC avg time (us), GC min time (us), GC max time (us), GC invocations, GC least free
insertionsort.lisp, 0.004000000, 0.005900000, 300.000000000, 300, 300, 2, 2047
fibonacci.lisp, 0.001799999, 3.177500009, 481.914886474, 300, 500, 94, 1968
tak.lisp, 0.002799999, 2.796099901, 526.108398437, 300, 600, 203, 1854
dec_cnt2.lisp, 0.001500000, 2.449100017, 470.000000000, 300, 500, 100, 2014
dec_cnt3.lisp, 0.002000000, 1.075600028, 473.333343505, 300, 500, 15, 1996
dec_cnt1.lisp, 0.001500000, 3.019200086, 468.000000000, 300, 500, 100, 2014
fibonacci_tail.lisp, 0, 0.004699999, 300.000000000, 300, 300, 1, 2047
q2.lisp, 0.002700000, 1.305099964, 515.517211914, 300, 600, 58, 1920

View File

@ -0,0 +1,9 @@
File, Load time (s), Eval time (s), GC avg time (us), GC min time (us), GC max time (us), GC invocations, GC least free
insertionsort.lisp, 0.004100000, 0.006000000, 400.000000000, 400, 400, 2, 2048
fibonacci.lisp, 0.002099999, 3.133500099, 446.808502197, 400, 500, 94, 2048
tak.lisp, 0.003100000, 2.760799884, 492.610839843, 400, 600, 203, 2048
dec_cnt2.lisp, 0.001700000, 2.426599979, 435.000000000, 400, 500, 100, 2048
dec_cnt3.lisp, 0.002199999, 1.052199959, 440.000000000, 400, 500, 15, 2048
dec_cnt1.lisp, 0.001700000, 2.979099988, 432.000000000, 400, 500, 100, 2048
fibonacci_tail.lisp, 0.003100000, 0.004999999, 4, 400, 400, 1, 2048
q2.lisp, 0.002899999, 1.287600040, 475.862060546, 400, 500, 58, 2048

View File

@ -467,6 +467,10 @@ void lbm_get_heap_state(lbm_heap_state_t *);
*
*/
void lbm_gc_state_inc(void);
/** Set the freelist to NIL. Means that no memory will be available
* until after a garbage collection.
*/
void lbm_nil_freelist(void);
/** Mark all heap cells that are on the free-list.
*
* \return 1 on success or 0 if the free-list is corrupted.

View File

@ -32,7 +32,10 @@ extern "C" {
#define LBM_PATCH_VERSION 0
/*! \page changelog Changelog
Oct 1: Version 0.7.0
Oct 16: Version 0.7.0
- Refactoring for evaluation speed.
- Removed possibility to step through code.
- Oldest message is removed on mailbox full.
- Added spawn-trap inspired by Erlang (but simplified).
Sep 25: Version 0.7.0

View File

@ -118,12 +118,7 @@ static inline int lbm_stack_is_empty(lbm_stack_t *s) {
* \param val1 Is pushed last.
* \return 1 on success and 0 on failure (stack is full).
*/
static inline int lbm_push_2(lbm_stack_t *s, lbm_uint val0, lbm_uint val1) {
int res = 1;
res &= lbm_push(s,val0);
res &= lbm_push(s,val1);
return res;
}
int lbm_push_2(lbm_stack_t *s, lbm_uint val0, lbm_uint val1);
/** Push 3 values to a stack.
*
@ -133,13 +128,7 @@ static inline int lbm_push_2(lbm_stack_t *s, lbm_uint val0, lbm_uint val1) {
* \param val2
* \return 1 on success and 0 on failure (stack is full).
*/
static inline int lbm_push_3(lbm_stack_t *s, lbm_uint val0, lbm_uint val1, lbm_uint val2) {
int res = 1;
res &= lbm_push(s,val0);
res &= lbm_push(s,val1);
res &= lbm_push(s,val2);
return res;
}
int lbm_push_3(lbm_stack_t *s, lbm_uint val0, lbm_uint val1, lbm_uint val2);
/** Push 4 values to a stack.
*
@ -150,14 +139,7 @@ static inline int lbm_push_3(lbm_stack_t *s, lbm_uint val0, lbm_uint val1, lbm_u
* \param val3
* \return 1 on success and 0 on failure (stack is full).
*/
static inline int lbm_push_4(lbm_stack_t *s, lbm_uint val0, lbm_uint val1, lbm_uint val2, lbm_uint val3) {
int res = 1;
res &= lbm_push(s,val0);
res &= lbm_push(s,val1);
res &= lbm_push(s,val2);
res &= lbm_push(s,val3);
return res;
}
int lbm_push_4(lbm_stack_t *s, lbm_uint val0, lbm_uint val1, lbm_uint val2, lbm_uint val3);
/** Push 5 values to a stack.
*
@ -169,15 +151,7 @@ static inline int lbm_push_4(lbm_stack_t *s, lbm_uint val0, lbm_uint val1, lbm_u
* \param val4
* \return 1 on success and 0 on failure (stack is full).
*/
static inline int lbm_push_5(lbm_stack_t *s, lbm_uint val0, lbm_uint val1, lbm_uint val2, lbm_uint val3, lbm_uint val4) {
int res = 1;
res &= lbm_push(s,val0);
res &= lbm_push(s,val1);
res &= lbm_push(s,val2);
res &= lbm_push(s,val3);
res &= lbm_push(s,val4);
return res;
}
int lbm_push_5(lbm_stack_t *s, lbm_uint val0, lbm_uint val1, lbm_uint val2, lbm_uint val3, lbm_uint val4);
/** Pop 2 values from a stack.
*
@ -186,12 +160,7 @@ static inline int lbm_push_5(lbm_stack_t *s, lbm_uint val0, lbm_uint val1, lbm_u
* \param r1 Pointer to lbm_value where the seconds pop:ed value will be stored.
* \return 1 on success and 0 on failure (stack is empty).
*/
static inline int lbm_pop_2(lbm_stack_t *s, lbm_uint *r0, lbm_uint *r1) {
int res = 1;
res &= lbm_pop(s, r0);
res &= lbm_pop(s, r1);
return res;
}
int lbm_pop_2(lbm_stack_t *s, lbm_uint *r0, lbm_uint *r1);
/** Pop 3 values from a stack.
*
@ -201,51 +170,7 @@ static inline int lbm_pop_2(lbm_stack_t *s, lbm_uint *r0, lbm_uint *r1) {
* \param r2
* \return 1 on success and 0 on failure (stack is empty).
*/
static inline int lbm_pop_3(lbm_stack_t *s, lbm_uint *r0, lbm_uint *r1, lbm_uint *r2) {
int res = 1;
res &= lbm_pop(s, r0);
res &= lbm_pop(s, r1);
res &= lbm_pop(s, r2);
return res;
}
/** Pop 4 values from a stack.
*
* \param s Stack to pop values from.
* \param r0
* \param r1
* \param r2
* \param r3
* \return 1 on success and 0 on failure (stack is empty).
*/
static inline int lbm_pop_4(lbm_stack_t *s, lbm_uint *r0, lbm_uint *r1, lbm_uint *r2, lbm_uint *r3) {
int res = 1;
res &= lbm_pop(s, r0);
res &= lbm_pop(s, r1);
res &= lbm_pop(s, r2);
res &= lbm_pop(s, r3);
return res;
}
/** Pop 5 values from a stack.
*
* \param s Stack to pop values from.
* \param r0
* \param r1
* \param r2
* \param r3
* \param r4
* \return 1 on success and 0 on failure (stack is empty).
*/
static inline int lbm_pop_5(lbm_stack_t *s, lbm_uint *r0, lbm_uint *r1, lbm_uint *r2, lbm_uint *r3, lbm_uint *r4) {
int res = 1;
res &= lbm_pop(s, r0);
res &= lbm_pop(s, r1);
res &= lbm_pop(s, r2);
res &= lbm_pop(s, r3);
res &= lbm_pop(s, r4);
return res;
}
int lbm_pop_3(lbm_stack_t *s, lbm_uint *r0, lbm_uint *r1, lbm_uint *r2);
#ifdef __cplusplus
}

View File

@ -1087,8 +1087,8 @@ static int gc(void) {
lbm_gc_mark_phase(variables[i]);
}
}
lbm_gc_mark_freelist();
// The freelist should generally be NIL when GC runs.
lbm_nil_freelist();
lbm_gc_mark_phase(*lbm_get_env_ptr());
eval_context_t *curr = queue.first;
@ -1355,15 +1355,15 @@ static void eval_if(eval_context_t *ctx) {
lbm_value else_branch = lbm_cadr(cddr);
lbm_uint *sptr = lbm_stack_reserve(&ctx->K, 4);
if (!sptr) {
if (sptr) {
sptr[0] = else_branch;
sptr[1] = then_branch;
sptr[2] = ctx->curr_env;
sptr[3] = IF;
ctx->curr_exp = lbm_cadr(ctx->curr_exp);
} else {
error_ctx(ENC_SYM_STACK_ERROR);
return;
}
sptr[0] = else_branch;
sptr[1] = then_branch;
sptr[2] = ctx->curr_env;
sptr[3] = IF;
ctx->curr_exp = lbm_cadr(ctx->curr_exp);
}
static void eval_let(eval_context_t *ctx) {

View File

@ -453,6 +453,10 @@ static int generate_freelist(size_t num_cells) {
return 1;
}
void lbm_nil_freelist(void) {
lbm_heap_state.freelist = ENC_SYM_NIL;
}
static void heap_init_state(lbm_cons_t *addr, lbm_uint num_cells,
lbm_uint *gc_stack_storage, lbm_uint gc_stack_size) {
lbm_heap_state.heap = addr;
@ -657,8 +661,9 @@ int lbm_gc_sweep_phase(void) {
lbm_cons_t *heap = (lbm_cons_t *)lbm_heap_state.heap;
for (i = 0; i < lbm_heap_state.heap_size; i ++) {
if ( !get_gc_mark(&heap[i])){
if ( get_gc_mark(&heap[i])) {
clr_gc_mark(&heap[i]);
} else {
// Check if this cell is a pointer to an array
// and free it.
if (lbm_type_of(heap[i].cdr) == LBM_TYPE_SYMBOL) {
@ -689,12 +694,11 @@ int lbm_gc_sweep_phase(void) {
lbm_uint *t = (lbm_uint*)heap[i].car;
lbm_custom_type_destroy(t);
lbm_memory_free(t);
} break;
} break;
default:
break;
}
}
}
// create pointer to use as new freelist
lbm_uint addr = lbm_enc_cons_ptr(i);
@ -705,7 +709,6 @@ int lbm_gc_sweep_phase(void) {
lbm_heap_state.num_alloc --;
lbm_heap_state.gc_recovered ++;
}
clr_gc_mark(&heap[i]);
}
return 1;
}
@ -774,6 +777,7 @@ lbm_value lbm_cdr(lbm_value c){
return ENC_SYM_TERROR;
}
int lbm_set_car(lbm_value c, lbm_value v) {
int r = 0;
if (lbm_type_of(c) == LBM_TYPE_CONS) {

View File

@ -80,19 +80,81 @@ int lbm_push(lbm_stack_t *s, lbm_uint val) {
if (s->sp == s->size) {
return 0;
}
s->data[s->sp] = val;
s->sp++;
if (s->sp > s->max_sp) s->max_sp = s->sp;
return res;
}
int lbm_pop(lbm_stack_t *s, lbm_uint *val) {
int lbm_push_2(lbm_stack_t *s, lbm_uint v1, lbm_uint v2) {
if (s->sp + 1 < s->size) {
s->data[s->sp++] = v1;
s->data[s->sp++] = v2;
if (s->sp > s->max_sp) s->max_sp = s->sp;
return 1;
} else {
return 0;
}
}
int lbm_push_3(lbm_stack_t *s, lbm_uint v1, lbm_uint v2, lbm_uint v3) {
if (s->sp + 2 < s->size) {
s->data[s->sp++] = v1;
s->data[s->sp++] = v2;
s->data[s->sp++] = v3;
if (s->sp > s->max_sp) s->max_sp = s->sp;
return 1;
} else {
return 0;
}
}
int lbm_push_4(lbm_stack_t *s, lbm_uint v1, lbm_uint v2, lbm_uint v3, lbm_uint v4) {
if (s->sp + 3 < s->size) {
s->data[s->sp++] = v1;
s->data[s->sp++] = v2;
s->data[s->sp++] = v3;
s->data[s->sp++] = v4;
if (s->sp > s->max_sp) s->max_sp = s->sp;
return 1;
} else {
return 0;
}
}
int lbm_push_5(lbm_stack_t *s, lbm_uint v1, lbm_uint v2, lbm_uint v3, lbm_uint v4, lbm_uint v5) {
if (s->sp + 4 < s->size) {
s->data[s->sp++] = v1;
s->data[s->sp++] = v2;
s->data[s->sp++] = v3;
s->data[s->sp++] = v4;
s->data[s->sp++] = v5;
if (s->sp > s->max_sp) s->max_sp = s->sp;
return 1;
} else {
return 0;
}
}
int lbm_pop(lbm_stack_t *s, lbm_uint *val) {
s->sp--;
*val = s->data[s->sp];
//s->data[s->sp] = 0;
return 1;
}
int lbm_pop_2(lbm_stack_t *s, lbm_uint *r0, lbm_uint *r1) {
s->sp--;
*r0 = s->data[s->sp--];
*r1 = s->data[s->sp];
return 1;
}
int lbm_pop_3(lbm_stack_t *s, lbm_uint *r0, lbm_uint *r1, lbm_uint *r2) {
s->sp--;
*r0 = s->data[s->sp--];
*r1 = s->data[s->sp--];
*r2 = s->data[s->sp];
return 1;
}

8
tests/test_qq_10.lisp Normal file
View File

@ -0,0 +1,8 @@
(let ((b 101))
(defun f (a)
`(+ ,b ,a)))
(and (= (eval (f 1)) 102)
(= (eval (f 100)) 201))

9
tests/test_qq_11.lisp Normal file
View File

@ -0,0 +1,9 @@
(defun f (a)
`(+ b ,a))
(let ((b 101))
(and (= (eval (f 1)) 102)
(= (eval (f 100)) 201)))

6
tests/test_qq_7.lisp Normal file
View File

@ -0,0 +1,6 @@
(define a 10)
(= (eval (let ((b 1))
`(+ ,b ,a)))
11)

6
tests/test_qq_8.lisp Normal file
View File

@ -0,0 +1,6 @@
(define a 10)
(= (let ((b 1))
(eval `(+ b ,a)))
11)

8
tests/test_qq_9.lisp Normal file
View File

@ -0,0 +1,8 @@
(defun f (a)
(let ((b 101))
`(+ ,b ,a)))
(and (= (eval (f 1)) 102)
(= (eval (f 100)) 201))