vsfvm文档(一)简介以及bringup

[复制链接]
 楼主| vsfopen 发表于 2018-6-18 14:12 | 显示全部楼层 |阅读模式
本帖最后由 vsfopen 于 2018-6-18 23:42 编辑

1. 简介
vsfvm是VSF中的脚本系统,包括编译器和虚拟机。vsfvm的开发主要针对小资源的应用,虚拟机最小占用3-5K flash、百来字节 ram;编译器最小占用13-15K flash、3-4K ram。当然,实际资源占用还是看用了那些扩展,以及代码的规模。

vsfvm虚拟机核心是基于堆栈的实现,使用尽量精简的语法以减少资源占用。vsfvm虚拟机支持各种扩展,并且扩展可以实现面向对象,后面会用GPIO扩展来举例说明。

2. bringup
  1. struct
  2. {
  3.         struct vsfvm_t vm;
  4.         struct vsfvm_script_t script;
  5.         bool polling;

  6.         struct vsfvmc_t vmc;
  7.         struct vsfvmc_lexer_list_t dart;
  8.         bool compiling;

  9.         uint32_t token[4 * 1024];
  10.         uint32_t token_num;
  11.         uint8_t source[4 * 1024];
  12. } vsfvm;

上面只是示例代码,大部分在实际应用中并不需要,比如source[4 * 1024],是用于存放上位机发过来的源代码;token[4 * 1024]和token_num是用于存放编译结果。这里只是为了测试方便,所以都放在ram里,实际应用环境中,一般都不需要。

编译器部分代码:
  1. app->vsfvm.compiling = true;
  2. vsfdbg_prints("start compiling ..." VSFCFG_DEBUG_LINEEND);
  3. vsfvmc_init(vmc, &usrapp, NULL);
  4. vsfvmc_register_ext(vmc, &vsfvm_ext_std);
  5. vsfvmc_ext_register_vsf(vmc);
  6. vsfvmc_register_lexer(vmc, &app->vsfvm.dart);
  7. err = vsfvmc_script(vmc, "main.dart");
  8. if (err < 0) goto err_return;

  9. err = vsfvmc_input(vmc, src);
  10. if (err < 0)
  11. {
  12. err_return:
  13.         err = -err;
  14.         vsfdbg_printf("command line compile error: %s" VSFCFG_DEBUG_LINEEND,
  15.                 (err >= VSFVMC_ERRCODE_END) ? "unknwon error" :
  16.                 vsfvmc_errcode_str[err]);
  17. compile_end:
  18.         vsfvmc_fini(vmc);
  19.         app->vsfvm.compiling = false;
  20.         return VSFERR_NONE;
  21. }

  22. err = vsfvmc_input(vmc, "\xFF");
  23. if (!err)
  24. {
  25.         if (vmc->bytecode.sp >= dimof(app->vsfvm.token))
  26.         {
  27.                 vsfdbg_prints("not enough space for token buffer" VSFCFG_DEBUG_LINEEND);
  28.                 goto compile_end;
  29.         }
  30.         vsfdbg_printf("compiled OK, token number : %d" VSFCFG_DEBUG_LINEEND,
  31.                         vmc->bytecode.sp);
  32. }

这里,首先调用vsfvmc_init初始化编译器;然后调用vsfvmc_register_ext注册需要支持的扩展(这里的顺序必须和虚拟机注册扩展的顺序完全一致,后面会有说明),并且调用vsfvmc_register_lexer注册词法分析器;然后调用vsfvmc_script生成脚本编译环境;之后调用vsfvmc_input输入脚本,这里可以多次调用vsfvmc_input(每次调用的时候,输入的代码不可能分隔语法,比如第一次输入"ma",第二次输入"in();",这里把main分隔开了),也可以整个代码一次输入;所有代码输入完后,最后调用一次vsfvmc_input(vmc, "\xFF");表示代码输入完毕,可以从vmc->bytecode里读取编译结果。


虚拟机部分的代码:
  1. app->vsfvm.polling = true;

  2. memset(vm, 0, sizeof(*vm));
  3. memset(script, 0, sizeof(*script));
  4. vm->thread_pool.pool_size = 16;
  5. script->token = app->vsfvm.token;
  6. script->token_num = app->vsfvm.token_num;

  7. vsfvm_init(vm);
  8. vsfvm_register_ext(vm, &vsfvm_ext_std);
  9. vsfvm_ext_register_vsf(vm);
  10. vsfvm_script_init(vm, script);


虚拟机里,只需要初始化script结构,指向对应的编译结果,然后调用vsfvm_init初始化虚拟机;调用vsfvm_register_ext注册扩展(顺序必须和编译器里注册扩展的顺序完全一致);然后调用vsfvm_script_init初始化脚本就可以运行了。
另外,在VSF的nrt_poll(非实时)里,还需要调用vsfvm_poll来轮询虚拟机。当然,这里虽然说是轮询,实际上vsfsm_nrt_poll也是事件驱动的,有事件的时候(MCU被唤醒)才会运行,运行之后,如果没有事件,MCU继续休眠,直到下一次被中断唤醒:
  1. void usrapp_nrt_poll(struct usrapp_t *app)
  2. {
  3.         if (app->vsfvm.polling)
  4.                 vsfvm_poll(&app->vsfvm.vm);
  5. }


注意,上面代码里有vsfvm_ext_register_vsf和vsfvmc_ext_register_vsf,是用来注册VSF的基本扩展,比如GPIO等等。
Chin心 发表于 2018-6-19 08:35 | 显示全部楼层
这么好的帖子竟然没人顶!
 楼主| vsfopen 发表于 2018-6-19 13:19 | 显示全部楼层
Chin心 发表于 2018-6-19 08:35
这么好的帖子竟然没人顶!

正常,毕竟还没正式开源,也没空准备详细文档
aetherchen 发表于 2020-2-22 20:00 | 显示全部楼层
老大,我好崇拜你哟

90

主题

325

帖子

8

粉丝
快速回复 在线客服 返回列表 返回顶部