打印

vsfvm文档(一)简介以及bringup

[复制链接]
1350|3
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
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
struct
{
        struct vsfvm_t vm;
        struct vsfvm_script_t script;
        bool polling;

        struct vsfvmc_t vmc;
        struct vsfvmc_lexer_list_t dart;
        bool compiling;

        uint32_t token[4 * 1024];
        uint32_t token_num;
        uint8_t source[4 * 1024];
} vsfvm;

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

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

err = vsfvmc_input(vmc, src);
if (err < 0)
{
err_return:
        err = -err;
        vsfdbg_printf("command line compile error: %s" VSFCFG_DEBUG_LINEEND,
                (err >= VSFVMC_ERRCODE_END) ? "unknwon error" :
                vsfvmc_errcode_str[err]);
compile_end:
        vsfvmc_fini(vmc);
        app->vsfvm.compiling = false;
        return VSFERR_NONE;
}

err = vsfvmc_input(vmc, "\xFF");
if (!err)
{
        if (vmc->bytecode.sp >= dimof(app->vsfvm.token))
        {
                vsfdbg_prints("not enough space for token buffer" VSFCFG_DEBUG_LINEEND);
                goto compile_end;
        }
        vsfdbg_printf("compiled OK, token number : %d" VSFCFG_DEBUG_LINEEND,
                        vmc->bytecode.sp);
}

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


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

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

vsfvm_init(vm);
vsfvm_register_ext(vm, &vsfvm_ext_std);
vsfvm_ext_register_vsf(vm);
vsfvm_script_init(vm, script);


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


注意,上面代码里有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

粉丝