機能
このページは Lambda C が提供する機能と API のカタログです。VM の内部構造、4バイト命令フォーマット、FFI のリンク機構、3スタックモデル、ホットリロード、設計判断などについては アーキテクチャ を参照してください。
言語機能
サポート
- C風シンタックス(サブセット)
- 整数、浮動小数点、ポインタ
- 算術、論理、ビット演算子
- 制御フロー:
if、while、for、switch、goto - 関数(パラメータ数に固定上限なし、スタック容量のみで制限)
- 関数ポインタ - コールバック、状態遷移テーブル等に活用
- グローバル/ローカル変数
- 配列(多次元配列も最大6次元までサポート)と構造体
- 型キャスト - 整数・浮動小数点・ポインタ間で可能
- enum - 明示的な値指定、自動インクリメント両対応
- union - メモリ効率の良いバリアント型
- typedef - 型エイリアス
- 修飾子 - const、static等
- 前方宣言(FFI)
- 標準ライブラリ:
printf、sqrt、sin、cosなど
サポート(プリプロセッサ)
#include- 外部ファイルの取り込み#define- マクロ定義#ifdef/#ifndef/#endif- 条件コンパイル
非サポート
- ネストされた関数
- ユーザー定義の可変長引数関数(
...) -printf等は組込みイントリンシック - 可変長配列(VLA、サイズはコンパイル時定数が必須)
- ビットフィールド、複合リテラル、指示付き初期化子
- C99 の型:
long long、_Bool(intか固定幅のtypedefを使用)
FFIシステム
関数登録
// 基本登録(-1000から始まる負のIDを返す)
int lcvm_register_function(const char *name, lcvm_ffi_func_t func, int arg_count);
// 型シグネチャ付き登録(DEBUGビルドで型チェック)
int lcvm_register_function_ex(const char *name, lcvm_ffi_func_t func,
int arg_count, const char *signature);
// 名前で関数を検索(手動リンク用)
int lcvm_ffi_find_by_name(const char *name, int *arg_count);
// 自動リンク(バイトコードロード後に呼び出し)
int lcvm_link_program(compact_program_t *prog);型シグネチャ
lcvm_register_function_ex() で使用するシグネチャ文字:
| 文字 | 型 |
|---|---|
i | int |
d | double |
f | float |
p | pointer |
s | string |
// 例: int と double を受け取る関数
lcvm_register_function_ex("add", ffi_add, 2, "id");
// 例: 2つのポインタを受け取る関数
lcvm_register_function_ex("memcpy", ffi_memcpy, 2, "pp");
型ミスマッチ時のログ出力例:
FFI add: arg 0 type mismatch (expected i, got pointer)FFI関数シグネチャ
typedef void (*lcvm_ffi_func_t)(LcvmState *vm);
// 戻り値をスタックにプッシュ
void lcvm_push_int(LcvmState *vm, int32_t value);
void lcvm_push_double(LcvmState *vm, double value);
// 引数をスタックからポップ(逆順)
int32_t lcvm_pop_int(LcvmState *vm);
double lcvm_pop_double(LcvmState *vm);例: 複数引数FFI
// スクリプト: result = add(10, 20.5);
static void ffi_add(LcvmState *vm) {
double b = lcvm_pop_double(vm); // 20.5
int32_t a = lcvm_pop_int(vm); // 10
lcvm_push_double(vm, a + b); // 30.5
}
lcvm_register_function_ex("add", ffi_add, 2, "id");メモリ管理
メモリレイアウト
Flash/ROM(読み取り専用)
- VMコード(compact_vm.o、intprt.o)
- FFIハンドラ(host_ffi.o)
- 標準ライブラリ(liblcvm.a)
RAM(書き込み可能)
- バイトコード(ファイル/ネットワークから読み込み)
- グローバル変数(garea)
- スタック(ローカル変数、一時値)
- ヒープ(動的確保)
Heap Watermark API
一時的な大量メモリ確保と一括解放のパターンに最適:
// 現在のヒープ位置を記録
size_t mark = lcvm_heap_mark();
// 一時メモリを確保
char *buf = lcvm_malloc(64 * 1024);
// ... 処理 ...
// マーク位置まで一括解放(O(1)、フラグメンテーションなし)
lcvm_heap_release(mark);
スクリプト側からも利用可能:
int mark = heap_mark();
// ... 一時処理 ...
heap_release(mark);推奨設定
Cortex-M0+(32KB RAM)
#define VM_STACK_SIZE (8 * 1024) /* 8KB */
#define VM_GAREA_SIZE (8 * 1024) /* 8KB */
#define VM_HEAP_SIZE (12 * 1024) /* 12KB */Cortex-M4 with FPU(64KB RAM)
#define VM_STACK_SIZE (16 * 1024) /* 16KB */
#define VM_GAREA_SIZE (16 * 1024) /* 16KB */
#define VM_HEAP_SIZE (24 * 1024) /* 24KB */
ハードウェアFPU(FPv4-SP)対応により浮動小数点演算が高速化。
RISC-V RV32(RV32IMC)
#define VM_STACK_SIZE (8 * 1024) /* 8KB */
#define VM_GAREA_SIZE (8 * 1024) /* 8KB */
#define VM_HEAP_SIZE (12 * 1024) /* 12KB */
オープンISA。Integer, Multiply, Compressed命令セット対応。
ESP32(320KB RAM)
#define VM_STACK_SIZE (32 * 1024) /* 32KB */
#define VM_GAREA_SIZE (32 * 1024) /* 32KB */
#define VM_HEAP_SIZE (128 * 1024) /* 128KB */静的型モード
-Os オプションで型情報追跡を省略するコンパイルモード。整数演算中心のプログラムで約2倍の高速化を実現します。
lcvmc -Os -oc output.lcbc source.c
制限事項:
- 整数演算に特化(浮動小数点は通常モード推奨)
- printf/sprintf対応済み。組み込み向けに
LCVM_PRINTF_BUFSIZEでバッファサイズ設定可能(デフォルト: 1024バイト)
ベンチマーク結果と設計の技術背景は アーキテクチャ を参照してください。
デバッグ支援機能
Watchpoint機能
グローバル変数の書き換えを自動検出:
garea 上のオフセット+サイズで監視範囲を指定(サイズは 1/2/4/8 のいずれか)。
// 有効化: LCVM_WATCH_ENABLED=1 でビルド
// 監視対象を追加(最大8個)
lcvm_watch_add(&vm, hp_offset, sizeof(int), "player_hp");
lcvm_watch_add(&vm, state_offset, sizeof(int), "game_state");
// 監視をクリア
lcvm_watch_clear(&vm);
監視範囲に重なる書き込みが発生すると自動でログ出力されます。
GDB Pretty Printer
tools/gdb_lcvm.py を読み込むと、GDB内でVM状態を人間可読形式で表示:
(gdb) source tools/gdb_lcvm.py
(gdb) p vm
$1 = LcvmState { pc=42, sp=8, error=NONE, ... }
エラー時はコールスタック、レジスタ、オペコード詳細を表示。
Postmortemツール
組み込み環境でのクラッシュ解析に最適:
バッファに書き込んでバイト数を返す API です(最小 24 バイト)。ファイル化・転送は呼び出し側で行います。
// ホスト側でバイナリダンプを出力
unsigned char buf[256];
int len = lcvm_dump_diagnostic_binary(&vm, buf, sizeof(buf));
// 例: buf を Flash / シリアル / ファイルへ送出# PC側で解析
python tools/lcvm_postmortem.py crash.binSimulator SDK
ドメイン特化シミュレータを高速構築するためのフレームワーク。
最小構成
2つのコールバック関数だけでシミュレータを実装:
void on_init(LcvmState *vm, void *user) {
// FFI関数を登録(型シグネチャ付き)
lcvm_register_function_ex("set_motor", ffi_set_motor, 2, "ii");
lcvm_register_function_ex("get_sensor", ffi_get_sensor, 1, "i");
}
void on_frame(LcvmState *vm, float dt, void *user) {
// 物理演算
update_physics(dt);
// 描画
render_scene();
}実装例
demos/raylib_drone/ - RayLib 連携ドローン配送シミュレータ。フルウォークスルーは ドローンデモ を参照。
安全機能
ウォッチドッグタイマー
- 時間ベース: N ミリ秒後に実行を終了
- 命令ベース: N 命令後に実行を終了
- 設定可能:
lcvm_set_watchdog_ms()、lcvm_set_watchdog_ic()
サンドボックスモード
- デフォルトで有効: 明示的に無効化しない限りポインタアクセスは範囲チェックされる
- メモリ分離: スクリプトはVMスタック、garea、ヒープのみアクセス可能
- ハードウェア保護: 周辺デバイスへのアクセスはFFI関数経由のみ
- 無効化:
lcvm_set_sandbox_mode(0)または環境変数LCVM_SANDBOX=0
エラーハンドリング
- グレースフル回復:
setjmp/longjmpベースのエラーハンドリング - 詳細な診断: エラーコード、メッセージ、PC、行番号
- API:
lcvm_has_error()、lcvm_get_error_code()、lcvm_get_error_message()