← 都来码 / Dolaima← 例程索引c/test/callports.c原文

c/test/callports.c · 10925 字节 · 下载原文

/* callports.c —— 通用宿主调用口(syscall 577–580)自检 / 用法示例
 * callports.c — generic host call ports (syscall 577-580) self-test / usage example
 *
 * 这四个接口让程序**按数字 id 调宿主的函数**:参数直接躺在寄存器里、返回值直接写回
 * These four ports let a program **call a host function by numeric id**: the arguments lie right in the registers
 * 第 0 号寄存器,**一次调用零编解码**(对比 ui_call_json —— 那条要过两趟 JSON)。
 * and the return value is written straight back to register 0 — **one call, zero codec** (compare ui_call_json, which goes through two rounds of JSON).
 *
 *     int    callwithint8   (int*    v);   v[0]=id, v[1..7] → R0..R7;返回覆盖 R0
 *     int    callwithint8   (int*    v);   v[0]=id, v[1..7] → R0..R7; the return value overwrites R0
 *     float  callwithfloat8 (float*  v);   v[0]=id, v[1..7] → F0..F7;返回覆盖 F0
 *     float  callwithfloat8 (float*  v);   v[0]=id, v[1..7] → F0..F7; the return value overwrites F0
 *     long   callwithlong4  (long*   v);   v[0]=id, v[1..3] → L0..L3;返回覆盖 L0
 *     long   callwithlong4  (long*   v);   v[0]=id, v[1..3] → L0..L3; the return value overwrites L0
 *     double callwithdouble4(double* v);   v[0]=id, v[1..3] → D0..D3;返回覆盖 D0
 *     double callwithdouble4(double* v);   v[0]=id, v[1..3] → D0..D3; the return value overwrites D0
 *
 * ⚠ **第 0 个槽既是调用号(进)又是返回值(出)** —— 调完拿不到原来的 v[0],这是 ABI。
 * ⚠ **slot 0 is both the call id (in) and the return value (out)** — v[0] is gone after the call; that is the ABI.
 *
 * ## 本批注册的是「自检族」(见 Lib/c/vml_ui.h 的 VML_CALL_*)
 * ## What is registered here is the "self-test family" (see VML_CALL_* in Lib/c/vml_ui.h)
 *
 * 它的返回值是**每个参数按位权拼出来的可分辨数**:传 1,2,3 得 321。
 * Its return value is **a distinguishable number assembled from each argument by positional weight**: pass 1,2,3 and you get 321.
 * 哪个参数没到、参数串没串位、返回值有没有回到程序,一眼就能看出来。
 * Which argument never arrived, whether the arguments got shifted, whether the return value came back to the program — all visible at a glance.
 *
 * ## ⚠ 为什么 float/long/double 那三个是"把位模式摆进 int 数组"再传
 * ## ⚠ Why the float/long/double three pass "the bit pattern laid out in an int array"
 *
 * 不是接口要求这么写 —— 是**当年 C 前端的三个缺陷**逼的。**2026-10-04 逐条复验**:
 * Not because the interface demands it — it was forced by **three defects in the C front end back then**. **Re-checked item by item on 2026-10-04**:
 *   ① ~~`float[]` / `double[]` 数组元素的**存**到不了内存(标量正常):`float v[8]; v[1] = 7.0;` 之后那块内存里是 0~~;
 *   ① ~~a **store** to a `float[]` / `double[]` array element never reached memory: after `float v[8]; v[1] = 7.0;` that memory held 0~~;
 *      ✅ **已修好**:实测 `float farr[8]; farr[1]=7.0f;` 读回 **7000/1000 = 7.000**,double 数组元素同样正确。
 *      ✅ **fixed**: `float farr[8]; farr[1]=7.0f;` measured reading back **7.000**, and double array elements are correct too.
 *   ② global `long` / `double` scalars were stored as 32-bit.
 *   ② global `long` / `double` scalars were stored as 32-bit.
 *      ⚠ **半修好(2026-10-04 复验)**:**运行时赋值**已正确(`long g; g = 4294967297L;` 读回 `>>32` 得 **1**),
 *      ⚠ **half-fixed (re-checked 2026-10-04)**: a **runtime store** is correct now (`long g; g = 4294967297L;` read back `>>32` gives **1**),
 *      **但全局 `long` 的「静态初值」仍只写 32 位** —— `long gl = 7L;` 编出来是 **`.word 7`(一个 32 位字)**,
 *      **but a global `long`'s static initializer still writes only 32 bits** — `long gl = 7L;` compiles to **`.word 7` (a single 32-bit word)**,
 *      于是 `printf("%ld", gl)` 把相邻数据段一起读进来(`gl=7` 时实测打出 **30064771079** = 0x0000000700000007)。
 *      so `printf("%ld", gl)` reads the neighbouring data too (`gl=7` measured printing **30064771079** = 0x0000000700000007).
 *      全局 `double` 的静态初值是对的(`.dword 2.25`)。⇒ **这条还有一半成立**,见本目录的交付报告。
 *      A global `double`'s static initializer is fine (`.dword 2.25`). ⇒ **this item still half-holds**, see the delivery report for this directory.
 *   ③ ~~同一个 `long[]` 连续存多个元素会丢(实测 4 条只有前 2 条落地)~~。
 *   ③ ~~storing several elements of one `long[]` in a row lost them (measured: only the first 2 of 4 landed)~~.
 *      ✅ **已修好**:实测 `long la[4]; la[0..3]=1,2,3,4;` 四条全部读回 **1,2,3,4**。
 *      ✅ **fixed**: `long la[4]; la[0..3]=1,2,3,4;` measured reading back all four as **1,2,3,4**.
 * 所以这里用一个 `int` 数组**手工摆出** float / long / double 的位模式,再把它的地址
 * So here a single `int` array is used to **hand-assemble** the bit patterns of float / long / double, and its address is
 * 当 `float*` / `long*` / `double*` 传进去 —— 这条路是通的(`callwithint8` 那条也顺带
 * passed as `float*` / `long*` / `double*` — that path does work (and the `callwithint8` call incidentally
 * 证明了 int 数组的读写是好的)。**现在的写法照旧保留**(能跑就别动);
 * proves that reading and writing an int array is fine). **The current style stays** (if it runs, do not touch it);
 * 前端那三条修好之后,直接写 `v[1] = 7.0;` 即可 —— **① ③ 现在就可以,② 只有静态初值那条不行**。
 * once those front-end defects are fixed, just write `v[1] = 7.0;` directly — **① and ③ work now; only ②'s static-initializer case does not**.
 */

#include <vml_ui.h>

/* 一块 32 字节的"寄存器内容"缓冲区:int / float / long / double 都从这里摆。
   A 32-byte "register contents" buffer: int / float / long / double are all laid out from here.
   ⚠ 必须是**全局**且是 int 数组 —— 见文件头那三条前端缺陷(**2026-10-04 复验:①③ 已修好、② 只剩静态初值那半边**)。
   ⚠ It must be **global** and an int array — see the three front-end defects in the file header (**re-checked 2026-10-04: ①③ are fixed; only ②'s static-initializer half remains**). */
int v[8];

int main(void) {
    int r;
    int lang;                   /* 界面语言:开局查一次(ui_scr_get_language 是 syscall,别每帧调) */
                                /* UI language: queried once at start (ui_scr_get_language is a syscall, do not call it every frame) */

    lang = ui_scr_get_language();

    /* ── ① int8:最自然的一种,直接按 int 填 ── */
    /* ── (1) int8: the most natural one, fill it in directly as int ── */
    v[0] = VML_CALL_ECHO_INT;
    v[1] = 1; v[2] = 2; v[3] = 3; v[4] = 4; v[5] = 5; v[6] = 6; v[7] = 7;
    r = callwithint8(v);
    printf("int8      = %d\n", r);          /* 7654321 = 1 + 20 + 300 + … + 7000000 */
    /* 7654321 = 1 + 20 + 300 + ... + 7000000 */

    /* ── ② float8:8 个 float 的位模式(1.0=1065353216, 2.0=1073741824, …)── */
    /* ── (2) float8: the bit patterns of 8 floats (1.0=1065353216, 2.0=1073741824, ...) ── */
    v[0] = 1073741824;                       /* v[0] = 2.0f = 调用号 ECHO_FLOAT */
    /* v[0] = 2.0f = the call id ECHO_FLOAT */
    v[1] = 1088421888;                       /* 7.0f */
    v[2] = 1086324736;                       /* 6.0f */
    v[3] = 1084227584;                       /* 5.0f */
    v[4] = 1082130432;                       /* 4.0f */
    v[5] = 1077936128;                       /* 3.0f */
    v[6] = 1073741824;                       /* 2.0f */
    v[7] = 1065353216;                       /* 1.0f */
    printf("float8    = %d\n", (int)callwithfloat8((float*)v));   /* 1234567 */

    /* ── ③ long4:3 个 long(每个 64 位占两个 int 槽,低半在前)── */
    /* ── (3) long4: 3 longs (each 64-bit value takes two int slots, low half first) ── */
    v[0] = 3; v[1] = 0;                      /* v[0] = 3 = 调用号 ECHO_LONG */
    /* v[0] = 3 = the call id ECHO_LONG */
    v[2] = 1; v[3] = 0;                      /* v[1] = 1 */
    v[4] = 2; v[5] = 0;                      /* v[2] = 2 */
    v[6] = 3; v[7] = 0;                      /* v[3] = 3 */
    printf("long4     = %d\n", (int)callwithlong4((long*)v));     /* 3002001 */

    /* ── ④ double4:3 个 double 的位模式(1.0=0x3FF0000000000000 → 低半 0、高半 1072693248)── */
    /* ── (4) double4: the bit patterns of 3 doubles (1.0=0x3FF0000000000000 → low half 0, high half 1072693248) ── */
    v[0] = 0; v[1] = 1074790400;             /* v[0] = 4.0 = 调用号 ECHO_DOUBLE */
    /* v[0] = 4.0 = the call id ECHO_DOUBLE */
    v[2] = 0; v[3] = 1072693248;             /* v[1] = 1.0 */
    v[4] = 0; v[5] = 1073741824;             /* v[2] = 2.0 */
    v[6] = 0; v[7] = 1074266112;             /* v[3] = 3.0 */
    printf("double4   = %d\n", (int)callwithdouble4((double*)v)); /* 3002001 */

    /* ── ⑤ 宿主信息:1 = 桌面脚手架、2 = 手机 App ── */
    /* ── (5) host info: 1 = desktop scaffolding, 2 = the phone App ── */
    v[0] = VML_CALL_HOST_INFO;
    printf(lang == 0 ? "宿主      = %d\n" : "host      = %d\n", callwithint8(v));

    /* ── ⑥ 失败路径:**一个都不许崩**,写回负数失败码(正数才是正常返回)── */
    /* ── (6) failure paths: **not one of them may crash**; a negative failure code is written back (only positive is a normal return) ── */
    v[0] = 9999;                             /* 没注册过这个号 */
    /* this id was never registered */
    printf(lang == 0 ? "未注册    = %d\n" : "unknown   = %d\n", callwithint8(v));   /* -6 */
    /* expected: -6, an id that was never registered */
    v[0] = VML_CALL_ECHO_FLOAT;              /* 这个号注册给 float8 了,却用 int8 口调 */
    /* this id is registered for float8, yet it is called through the int8 port */
    printf(lang == 0 ? "类型不符  = %d\n" : "type err  = %d\n", callwithint8(v));   /* -2 */
    /* expected: -2, the id belongs to another port */
    v[0] = -5;                               /* 负数调用号 */
    /* a negative call id */
    printf(lang == 0 ? "负数号    = %d\n" : "negative  = %d\n", callwithint8(v));   /* -2 */
    /* expected: -2, a negative call id */
    return 0;
}