docs: correct M3 ROM bit displacements and unaligned-load carry-forward

This commit is contained in:
arti committed 2026-11-11 19:14:05 +00:00
1 parent 2187f59b20
commit b34016a9f3
1 file changed
+28 -22
@@ -22,7 +22,7 @@
- **CMP operand order:** for `icmp <pred> a, b` the compare must compute `a - b` (the branch condition reads the flags for `a <pred> b`). The signed/unsigned conditions map to the TMS34010 condition codes in `dis34`: `uc/p/ls/hi/lt/ge/le/gt/c/nc/eq/ne/v/nv/n/nn` (0–15).
- M3 scalar control flow: i32/pointer values, signed and unsigned integer compares, `and`/`or`/`xor`/`shl`/`lshr`/`ashr`/`sub`/`neg`/`not`; no switch tables, indirect branches, floats, i64, or function pointers in M3.
- **Xlib is ROM-v2.2 only.** Use the four known-good entries from `symbols/vt1200-v22.syms`: `XOpenDisplay 0x3F9C2570`, `XCreateSimpleWindow 0x3FD41B90`, `XMapWindow 0x3FD645B0`, `XSync 0x3FD9F6B0`. The stubs are `JAUC <address>h`; `CALLA _XOpenDisplay` reaches the ROM function.
- **Display/Screen layout is ROM-specific:** `Display.screens` is the 32-bit pointer at **`d + 0x480`**; `Screen.root` is the 32-bit root id at **`screens + 0x40`** (proven by `vendor/vt1200/dwt/gui/xhello.asm`). M3 uses a minimal `scripts/m3/vt1200_xlib.h` with these exact offsets and `_Static_assert`s; do not assume the host X11R7 `_XDisplay` layout matches the ROM. The full X11R4 `XImage`/`XEvent` headers are M4.
- **Display/Screen layout is ROM-specific:** xhello's `*a11(0480h)`/`*a10(040h)` are **bit displacements**, so `Display.screens` is the 32-bit pointer at **byte 0x90** (bit `0x480`) and `Screen.root` is the 32-bit root id at **byte 0x8** (bit `0x40`). M3 uses a minimal `scripts/m3/vt1200_xlib.h` with byte pads 0x90/0x8 and `_Static_assert`s, returning the ROM's bit offsets `0x480`/`0x40`; do not assume the host X11R7 `_XDisplay` layout matches the ROM. The full X11R4 `XImage`/`XEvent` headers are M4.
- `XOpenDisplay("0::0")` must run in the loader-created `create_process` child, not the rdebug dispatcher; the M2 `_start`/loader path satisfies this.
- `XCreateSimpleWindow` takes 9 arguments: `display, parent, x, y, width, height, border_width, border, background`; the first argument is at `FP(-32)`, the ninth at `FP(-288)`; `RETS 2`.
- M3 must observe a window, not only markers: the harness creates the window with **background pixel 1 (white)**, maps it, calls `XSync`, and checks a pixel inside the client area in emulated VRAM (base bit `0x04000000`, VRAM pitch 2048 bits on the default VR319 monitor, LSB-first). No fake pass.
@@ -34,7 +34,7 @@
1. **Branch target and label correctness:** GSPA block labels must have no dot; `JAUC`/`JCC` must target the right block; a wrong label jumps into data. Tests in Task 1 (`m3-branch`, GSPA probe) and Task 2 (`m3-loop`).
2. **Compare polarity and signedness:** the `CMP` operand order and `JALT`/`JALO`/`JAHI`/`JAEQ` mapping must match the C predicate; a reversed condition silently returns the wrong value. Tests in Task 2 (`m3-setcc`, `m3-if`, `m3-unsigned`) and Task 4 (`sumto(10)==55`, `max(20,22)==22`, `lt(5,7)==1` in MAME).
3. **Stack/FS invariants on every path:** prologue, multiple return blocks, loops and calls must keep A14/A15 balanced and FS0/FS1 correct; the old-STK/`RETS` rules still apply. Tests in Task 2 (loop returns) and Task 4 (MAME).
4. **Display/Screen offsets and root retrieval:** `d+0x480` then `screens+0x40`; a wrong screen/root pointer yields no window or a crash. Tests in Task 3 (static asserts + TI golden) and Task 4 (window).
4. **Display/Screen offsets and root retrieval:** `Display.screens` at byte 0x90 (bit displacement 0x480), then `Screen.root` at byte 0x8 (bit 0x40); a wrong screen/root pointer yields no window or a crash. Tests in Task 3 (static asserts + TI golden) and Task 4 (window).
5. **Nine-argument `XCreateSimpleWindow` order:** all nine slots, first at `FP(-32)`, last at `FP(-288)`; a wrong order maps the wrong rectangle or parent. Tests in Task 4 (`dis34` push count and MAME window).
6. **The window really appears:** the loader child, the X server, `XSync`, a white client-area pixel; marker-only success is not enough. Test in Task 4.
@@ -350,15 +350,15 @@ git -C build/llvm-clean commit -m "tms34010: add integer comparisons, branches a
typedef unsigned int XID;
typedef unsigned int Window;
/* ROM v2.2 layout (xhello.asm): Display.screens is the pointer at d+0x480;
Screen.root is the 32-bit root id at screens+0x40. */
/* ROM v2.2 layout (xhello.asm): Display.screens is the pointer at byte 0x90
(bit 0x480); Screen.root is the 32-bit root id at byte 0x8 (bit 0x40). */
typedef struct {
unsigned char pad[0x480];
unsigned char pad[0x90]; /* bit 0x480 */
void *screens;
} Display;
typedef struct {
unsigned char pad[0x40];
unsigned char pad[0x8]; /* bit 0x40 */
unsigned int root;
} Screen;
@@ -386,20 +386,20 @@ int layout_root(void);
```c
#include "vt1200_xlib.h"
_Static_assert(__builtin_offsetof(Display, screens) == 0x480,
"Display.screens must be at 0x480");
_Static_assert(__builtin_offsetof(Screen, root) == 0x40,
"Screen.root must be at 0x40");
_Static_assert(__builtin_offsetof(Display, screens) == 0x90,
"Display.screens must be at byte 0x90 (bit 0x480)");
_Static_assert(__builtin_offsetof(Screen, root) == 0x8,
"Screen.root must be at byte 0x8 (bit 0x40)");
int layout_screens(void) { return (int)__builtin_offsetof(Display, screens); }
int layout_root(void) { return (int)__builtin_offsetof(Screen, root); }
int layout_screens(void) { return (int)__builtin_offsetof(Display, screens) * 8; }
int layout_root(void) { return (int)__builtin_offsetof(Screen, root) * 8; }
```
`scripts/m3/layout-ti.c` (K&R, for the 1987 compiler):
```c
struct display { char pad[0x480]; void *screens; };
struct screen { char pad[0x40]; unsigned int root; };
struct display { char pad[0x90]; void *screens; };
struct screen { char pad[0x8]; unsigned int root; };
int layout_screens() { return (int)&((struct display *)0)->screens; }
int layout_root() { return (int)&((struct screen *)0)->root; }
@@ -413,7 +413,7 @@ build/llvm-clean-build/bin/llc -march=tms34010 -O0 -filetype=asm \
/tmp/opencode/m3-layout.ll -o /tmp/opencode/m3-layout.s
```
Expected initially: the `_Static_assert`s fail if the target's struct layout pads `Display.screens` away from 0x480 or `Screen.root` away from 0x40. Fix the header (the padded structs are the intended ROM layout) or the target's struct layout if the padded struct itself is laid out wrongly. Do not use the host X11R7 `_XDisplay` layout.
Expected initially: the `_Static_assert`s fail if the target's struct layout pads `Display.screens` away from byte 0x90 (bit 0x480) or `Screen.root` away from byte 0x8 (bit 0x40). Fix the header (the padded structs are the intended ROM layout) or the target's struct layout if the padded struct itself is laid out wrongly. Do not use the host X11R7 `_XDisplay` layout.
- [ ] **Step 3: Build the TI golden**
@@ -441,6 +441,8 @@ git commit -m "tests: M3 Xlib Display/Screen layout"
**Files:**
- Create: `scripts/m3/xhello.c`, `branch.c`, `entry.asm`, `link.cmd`, `run.sh`, `m3-check.lua`, `dis-roundtrip.sh`, `validate-syms.sh`
- Modify: `build/llvm-clean/llvm/lib/Target/TMS34010/TMS34010ISelLowering.cpp/.h` (misaligned accesses)
- Test: `build/llvm-clean/llvm/test/CodeGen/TMS34010/m3-unaligned.ll`
- Create: `scripts/tests/m3/run.sh`, `scripts/tests/m3/dis-roundtrip.sh`
- Test: the MAME window and the branch markers
@@ -448,7 +450,11 @@ git commit -m "tests: M3 Xlib Display/Screen layout"
- Consumes: Tasks 1–3's branches, layout, and the M2 `.data`/ABI/loader.
- Produces: `M3 MAME: PASS` with the Xlib markers, branch results, and a white window pixel; `M3 dis34 round-trip: PASS`.
- [ ] **Step 1: Write the C client and branch test**
- [ ] **Step 1: Fix the packed-struct unaligned-load gap (compiler)**
`vt1200_root()` loads the `Display.screens` pointer and `Screen.root` from packed structs (`clang` `PackStruct = 1` → every field load is `align 1`). The DAG legalizer currently splits those into four `zext i8` loads, and M2/M3 only has a sign-extending `MOVB`, so `llc` aborts. Add `TMS34010TargetLowering::allowsMisalignedMemoryAccesses` returning true for i16/i32/pointers in address space 0 (the ISA allows misaligned accesses; spec §7.5), so the existing `MOVE`/FS0 forms select directly. Add a focused lit test (`m3-unaligned.ll`: `load i32, ptr %p, align 1` and `store i32 ..., align 1` → `MOVE`/`MOVE ...,1`; a pointer load; an i16 align-1 load). Also add a `vt1200_root` probe to `layout.c` (or a small TU) that calls the helper and require the selected asm to contain the `0480h`/`040h` bit displacements. Do not paper over this with `__attribute__((aligned(2)))`.
- [ ] **Step 2: Write the C client and branch test**
`scripts/m3/xhello.c`:
@@ -501,7 +507,7 @@ int branch_test(void) {
The `layout_screens`/`layout_root` functions come from `layout.c` (Task 3); compile it into the M3 image.
- [ ] **Step 2: Write the entry and linker command**
- [ ] **Step 3: Write the entry and linker command**
`scripts/m3/entry.asm`:
@@ -541,7 +547,7 @@ SECTIONS
}
```
- [ ] **Step 3: Validate the ROM symbols**
- [ ] **Step 4: Validate the ROM symbols**
`scripts/m3/validate-syms.sh`:
@@ -552,7 +558,7 @@ SECTIONS
This is a regression check, not a re-extraction; the four entries are proven by `xhello.asm`. M4 extends the table for `XImage`/`XEvent`.
- [ ] **Step 4: Write the M3 runner and check**
- [ ] **Step 5: Write the M3 runner and check**
`scripts/m3/run.sh` adapts `scripts/m2/run.sh` with:
@@ -578,7 +584,7 @@ This is a regression check, not a re-extraction; the four entries are proven by
Then read the VRAM pixel inside the window: the window is at `(100,100)`, 400×200; background pixel 1 (white). On the default VR319 monitor the VRAM base is bit `0x04000000` and the row pitch is 2048 bits; read a 32-bit word containing `(150,150)` and require the bit `1 << (150 & 31)` to be set. Print `M3: ...` and exactly `M3 MAME: PASS` on success. The window must be observed; a markers-only pass is not enough.
- [ ] **Step 5: Write the `dis34` round-trip**
- [ ] **Step 6: Write the `dis34` round-trip**
`scripts/m3/dis-roundtrip.sh` adapts the M2 COFF parser and symbol lookup. It must require:
@@ -589,7 +595,7 @@ Then read the VRAM pixel inside the window: the window is at `(100,100)`, 400×2
- the `.data` bytes `30 3A 3A 30 00` (`"0::0"`);
- the old-STK push-count `(pushes+1)*32` for the branch/Xlib functions; the `rets 1` negative control.
- [ ] **Step 6: Run the M3 gates**
- [ ] **Step 7: Run the M3 gates**
```sh
scripts/tests/m3/run.sh
@@ -598,7 +604,7 @@ scripts/tests/m3/dis-roundtrip.sh
Expected: `M3 MAME: PASS` with `display/root/window/sync`, `sum=55 max=22 lt=1`, `screens=0x480 root=0x40`, and the window pixel white; `M3 dis34 round-trip: PASS`.
- [ ] **Step 7: Commit**
- [ ] **Step 8: Commit**
```sh
git add scripts/m3 scripts/tests/m3