FPGA開発日記

カテゴリ別記事インデックス https://msyksphinz.github.io/github_pages , English Version https://fpgadevdiary.hatenadiary.com/

LuaからC++の機能を呼び出す(クラスに対するアクセス)

昨日一昨日くらいは、LuaからどのようにしてC++のクラスにアクセスするかを調査していた。 やりたいこととしては、ある環境(クラス)を定義して、それにLuaからアクセスすることでクラス内の挙動を変えたい。 具体的に言えば、Lua側からスクリプトを書くことでISSの挙動(最大命令実行数、ブレークポイントなど)を変更させたい。

これを実現するための方法を調べた。結論としては、Lua側から制御して新しいC++クラスをインスタンスし、Luaからアクセスするときは 必ずそれを参照する。

github.com

Luaからクラスを生成する。

以下のような関数を作成した。

#include <lua5.2/lua.hpp>
#include <lua5.2/lualib.h>
#include <lua5.2/lauxlib.h>

#include <iostream>
#include <string>

#include "./lua_class.h"

int MakeClass (lua_State *L)
{
    // Getting Arguments
    std::string arch_name = lua_tostring (L, 1);
    int x = lua_tointeger (L, 2);

    std::cout << "ARCH_NAME=" << arch_name << '\n';

    class lua_class *new_L = new lua_class ();
    new_L->set_x (x);

    lua_pushlightuserdata (L, static_cast<void *>(new_L));

    return 1;
}


int GetX (lua_State *L)
{
    // Getting Arguments
    class lua_class *target_L = static_cast<class lua_class *>(lua_touserdata (L, 1));
    int x = target_L->get_x();
    std::cout << "GetX() = " << x << '\n';

    lua_pushinteger (L, x);

    return 1;
}


int SetX (lua_State *L)
{
    // Getting Arguments
    class lua_class *target_L = static_cast<class lua_class *>(lua_touserdata (L, 1));
    int x = lua_tointeger (L, 2);

    target_L->set_x(x);
    std::cout << "Set(" << x << ")\n";

    return 0;
}

ここで、lua_classは自前で作成したクラスで、変数としてm_xを持っており、set_x(), get_x()でアクセスできる。 例えば、Lua側から以下のようなプログラムを記載したとする。

core = make_core ("risc-v", 2)
set_x (core, 1244)
get_x (core)

まず、make_coreは2つ引数を取り、一つ目は文字列、2つ目は整数だ。 これによりMakeClassが呼ばれ、新しいlua_classクラスがnewされて、それが返り値として返される(lua_pushlightuserdata)。

make_coreがMakeClassにバインドされるのは、プログラム中で定義する。

    lua_register(lua_state, "make_core", MakeClass);
    lua_register(lua_state, "get_x", GetX);
    lua_register(lua_state, "set_x", SetX);

クラスにアクセスして、変数を制御する

core = make_core ("risc-v", 2)
set_x (core, 1244)
get_x (core)

上記のプログラムでは,coreオブジェクトを第一引数、変数を第二引数としてset_xを呼び出す。 これにより、C++側のSetXが呼び出される。

まず、lua_touserdataにより、第一引数がlua_classのポインタに変換され、変数をセットする。 戻り値は、ここでは取らないため、return 0を返す。

次に、get_xも同様にlua_classのポインタを渡し、それをlua_class側にstatic_castで変換する。 そして、get_xメソッドを呼び出すことで、変数xの内容を返すという構造になっている。