From cb4326c712b1072314e5026881c58e774d75fc1c Mon Sep 17 00:00:00 2001 From: Robert Allan James Date: Fri, 7 Aug 2026 15:20:58 -0400 Subject: [PATCH] starkernel: item 4.3.3b -- geometry drawing wordset, fixed Q.TO-INT sign bug Adds LINE (Bresenham in raster space, endpoints projected once each -- valid because the cavalier projection is linear), CIRCLE/ELLIPSE (36-segment polygon approximation), and ARC (18 segments over a caller radian range) to capsules/fabric.4th (blocks 4903-4912). TO-RASTER factored out of CART-PLOT (same behavior) so LINE can reuse the projection+flip for both endpoints. Found mid-implementation: colon definitions cannot span block boundaries in this capsule loader -- verified with a throwaway test capsule, the continuation lands in a [CAPSULE][DEFER] path that never resolves. LINE's body is split across LINE-SETUP/LINE-DONE?/LINE-STUCK?/LINE-STEP, each self-contained within its block, rather than one long definition. A fourth real bug, serious this time: CIRCLE's first live test rendered only one quadrant, then hung the VM for several minutes on a follow-up call. Root cause: q48_to_u64() (include/q48_16.h and include/starkernel/q48_16.h, backing Q.TO-INT) did an unsigned logical shift, corrupting any negative Q48.16 value into a huge garbage integer instead of sign-extending -- inevitable once Q.SIN/Q.COS leave the first quadrant. That garbage became a bogus LINE target with no bound on LINE-STEP's Bresenham loop. Fixed q48_to_u64 to shift through a signed int64_t intermediate (bit-identical for the non-negative case). Also added LINE-STUCK? (LSTEPS vs FB-WIDTH+FB-HEIGHT, the true worst case for an on-screen line) as a defense-in-depth cap against any future bad target. Verified live on amd64 after both fixes: -65536 Q.TO-INT . now prints -1; LINE/CIRCLE/ARC/ELLIPSE all complete without hanging or erroring, and a combined screendump shows all four rendering correctly and distinctly. All three architectures boot clean to ok> with the DoE completing; dict_hash identical across all three and unchanged from 4.3.3a (expected -- fabric.4th isn't loaded at boot, and the Q.TO-INT fix doesn't change dictionary structure). FABRIC.md item 4.3.3b marked done with full acceptance evidence. --- FABRIC.md | 37 ++++++++- capsules/BLOCK_MAP.md | 20 +++-- capsules/fabric.4th | 120 ++++++++++++++++++++++++++++ fb/amd64/geom-test-circle-fixed.png | Bin 0 -> 9628 bytes fb/amd64/geom-test-full-wordset.png | Bin 0 -> 10560 bytes include/q48_16.h | 17 ++-- include/starkernel/q48_16.h | 7 +- lfs/amd64/starforth | Bin 1491112 -> 1491112 bytes 8 files changed, 188 insertions(+), 13 deletions(-) create mode 100644 fb/amd64/geom-test-circle-fixed.png create mode 100644 fb/amd64/geom-test-full-wordset.png diff --git a/FABRIC.md b/FABRIC.md index 7ac4539..8152693 100644 --- a/FABRIC.md +++ b/FABRIC.md @@ -3757,11 +3757,46 @@ document and committing that amendment as its own item.* > to the same `-27` as `sin(π)`, confirming range reduction across multiple turns. Both > hosted and kernel (amd64) builds clean. -- [ ] **4.3.3b — Geometry drawing primitive wordset.** `LINE`, `CIRCLE`, `ARC`, `ELLIPSE` in +- [x] **4.3.3b — Geometry drawing primitive wordset.** `LINE`, `CIRCLE`, `ARC`, `ELLIPSE` in `capsules/fabric.4th`, built on 4.3.3's `PLOT`/`CART-PLOT` and 4.3.3a's `Q.SIN`/`Q.COS`. Raised 2026-08-07. Q48.16 throughout; resolution-agnostic (48 integer bits comfortably covers 1080p and well beyond — no hardcoded viewport assumptions). *Refs:* §27.3. + > **Done, 2026-08-07.** Blocks 4903–4912. `TO-RASTER` factored out of `CART-PLOT` (same + > behavior, not a change) so `LINE` can project both endpoints once and Bresenham the + > straight line between them in raster space — valid because the cavalier projection is + > linear, so projecting endpoints and interpolating is equivalent to projecting every point + > along the line. `LINE` itself split across three helper words (`LINE-SETUP`, + > `LINE-DONE?`/`LINE-STUCK?`, `LINE-STEP`) — discovered mid-implementation that colon + > definitions **cannot span block boundaries** in this capsule loader (verified with a + > throwaway test capsule: the continuation lands in a `[CAPSULE][DEFER]` path that never + > resolves and errors out), so anything too long for one 16-line/64-char block has to be + > factored into separate, block-local word definitions instead. `CIRCLE`/`ELLIPSE` are + > 36-segment polygon approximations (`LINE` calls between consecutive `Q.SIN`/`Q.COS` + > points); `ARC` is the same at 18 segments over a caller-supplied `[a0, a1]` radian range. + > + > **A fourth real bug, this one serious — found, fixed, verified with the recommended fix + > applied both times.** `CIRCLE`'s first live test rendered only its first quadrant, then + > a follow-up test call hung the VM for several minutes before being killed. Root cause: + > `q48_to_u64()` (`include/q48_16.h` and `include/starkernel/q48_16.h`, backing + > `Q.TO-INT`) did `q >> 16` as an **unsigned logical shift**. For any negative `q48_16_t` — + > inevitable once `Q.SIN`/`Q.COS` leave the first quadrant — this produces a huge garbage + > integer instead of sign-extending. That garbage became a bogus `LINE` target, and + > `LINE-STEP`'s Bresenham loop had no bound, so it churned for a very long time trying to + > converge on a point that was effectively unreachable. Fixed by shifting through a signed + > `int64_t` intermediate (bit-identical output for the non-negative case, which is all the + > inference engine's own caller ever produces). Independently, added `LINE-STUCK?` + > (`LSTEPS` counter vs. `FB-WIDTH + FB-HEIGHT`, the true worst case for any on-screen line) + > as a defense-in-depth cap, so a future bad target degrades to "stops drawing" rather than + > hanging the VM again. + > + > **Verified live on amd64**, fresh boot after both fixes: `-65536 Q.TO-INT .` now prints + > `-1`. `LINE`, `CIRCLE`, `ARC` (semicircle, 0 to π), and `ELLIPSE` all completed without + > hanging or erroring, and a combined screendump shows all four rendering correctly and + > distinctly — full circle, correct upper-half arc, properly proportioned ellipse (wider + > than tall, matching unequal radii), and the earlier diagonal `LINE` test. + > `fb/amd64/geom-test-circle-fixed.png`, `fb/amd64/geom-test-full-wordset.png`. + - [ ] **4.3.4 — Checkpoint: draw a cube.** First real exercise of the 4.3.3/4.3.3a/4.3.3b coordinate/projection/geometry machinery — cube edges use `LINE`. Stop and review here before scoping the next 4.3.x item — not expected to be fast. *Refs:* §27.4. diff --git a/capsules/BLOCK_MAP.md b/capsules/BLOCK_MAP.md index b17dbed..d85a40e 100644 --- a/capsules/BLOCK_MAP.md +++ b/capsules/BLOCK_MAP.md @@ -1,5 +1,5 @@ # Capsule Block Manifest — Auto-generated - + @@ -13,7 +13,7 @@ | `common:msg.4th` | 4055 | `0xa99c5bcd3877f80e` | | `doe-campaign.4th` | 4060, 4061, 4062, 4063, 4064, 4065 | `0x3d4549142d91ec20` | | `doe.4th` | 2100, 2101, 2102, 2103, 2104, 2105, 2106, 2107 | `0xb6ecf5374e8ee77c` | -| `fabric.4th` | 4900, 4901, 4902 | `0xb7db7380ec4a42a0` | +| `fabric.4th` | 4900, 4901, 4902, 4903, 4904, 4905, 4906, 4907, 4908, 4909, 4910, 4911, 4912 | `0x355ccc154aac15b3` | | `hermes:init.4th` | 4100, 4101, 4102, 4103, 4104, 4105, 4106, 4107, 4108, 4109, 4114, 4115, 4116, 4117, 4118, 4119, 4120, 4121, 4142, 4143, 4144, 4145, 4146, 4147, 4148, 4149, 4150, 4151, 4152, 4153, 4154, 4155, 4156, 4157, 4158, 4159, 4175, 4176 | `0x85c7b311d1e5bf97` | | `init-0.4th` | 2200, 2201 | `0xd0a9550baf786bb3` | | `init-1.4th` | 4406, 4415, 4425, 4435 | `0x63e251adb0a03613` | @@ -225,9 +225,19 @@ | 4842 | `init-l8-transition.4th` | `0xbcc1a81976f0a4c9` | ok | | 4851 | `artemis:init.4th` | `0xc9e92cd18f4c7b49` | ok | | 4852 | `artemis:init.4th` | `0xc9e92cd18f4c7b49` | ok | -| 4900 | `fabric.4th` | `0xb7db7380ec4a42a0` | ok | -| 4901 | `fabric.4th` | `0xb7db7380ec4a42a0` | ok | -| 4902 | `fabric.4th` | `0xb7db7380ec4a42a0` | ok | +| 4900 | `fabric.4th` | `0x355ccc154aac15b3` | ok | +| 4901 | `fabric.4th` | `0x355ccc154aac15b3` | ok | +| 4902 | `fabric.4th` | `0x355ccc154aac15b3` | ok | +| 4903 | `fabric.4th` | `0x355ccc154aac15b3` | ok | +| 4904 | `fabric.4th` | `0x355ccc154aac15b3` | ok | +| 4905 | `fabric.4th` | `0x355ccc154aac15b3` | ok | +| 4906 | `fabric.4th` | `0x355ccc154aac15b3` | ok | +| 4907 | `fabric.4th` | `0x355ccc154aac15b3` | ok | +| 4908 | `fabric.4th` | `0x355ccc154aac15b3` | ok | +| 4909 | `fabric.4th` | `0x355ccc154aac15b3` | ok | +| 4910 | `fabric.4th` | `0x355ccc154aac15b3` | ok | +| 4911 | `fabric.4th` | `0x355ccc154aac15b3` | ok | +| 4912 | `fabric.4th` | `0x355ccc154aac15b3` | ok | ## Conflicts diff --git a/capsules/fabric.4th b/capsules/fabric.4th index 8616b80..e6ae8c7 100644 --- a/capsules/fabric.4th +++ b/capsules/fabric.4th @@ -30,3 +30,123 @@ Block 4902 CART-Y R> PLOT ; + +Block 4903 +( TO-RASTER: 3D Cartesian point -> raster (rx ry). Factored ) +( out of CART-PLOT so LINE can reuse it for both endpoints ) +( -- the projection is linear, so projecting endpoints then ) +( drawing 2D is equivalent to projecting every line point. ) +( Item 4.3.3b. CART-PLOT redefined in terms of it (same ) +( behavior, not a change). ) +: TO-RASTER ( x y z -- rx ry ) + PROJECT CART-Y ; +: CART-PLOT ( x y z color -- ) + >R TO-RASTER R> PLOT ; + +Block 4904 +( LINE: 3D Cartesian line segment, Bresenham in raster ) +( space (state in VARIABLEs; LINE-SETUP below). ) +VARIABLE LX VARIABLE LY VARIABLE LX2 VARIABLE LY2 +VARIABLE LDX VARIABLE LDY VARIABLE LSX VARIABLE LSY +VARIABLE LERR VARIABLE LCOLOR VARIABLE LSTEPS +: LINE-SETUP ( x1 y1 z1 x2 y2 z2 color -- ) + LCOLOR ! + TO-RASTER LY2 ! LX2 ! + TO-RASTER LY ! LX ! + LX2 @ LX @ - ABS LDX ! + LY2 @ LY @ - ABS NEGATE LDY ! + LX @ LX2 @ < IF 1 ELSE -1 THEN LSX ! + LY @ LY2 @ < IF 1 ELSE -1 THEN LSY ! + LDX @ LDY @ + LERR ! 0 LSTEPS ! ; + +Block 4905 +( LINE-DONE?: true once current point reached target. ) +: LINE-DONE? ( -- flag ) + LX @ LX2 @ = LY @ LY2 @ = AND ; +( LINE-STUCK?: safety cap, width+height worst case. ) +: LINE-STUCK? ( -- flag ) + LSTEPS @ FB-WIDTH FB-HEIGHT + > ; +( LINE-STEP: one Bresenham step (no plot). ) +: LINE-STEP ( -- ) + LERR @ 2* + DUP LDY @ >= IF LERR @ LDY @ + LERR ! LX @ LSX @ + LX ! THEN + DUP LDX @ <= IF LERR @ LDX @ + LERR ! LY @ LSY @ + LY ! THEN + LSTEPS @ 1+ LSTEPS ! DROP ; + +Block 4906 +( LINE: draws the segment using the helpers above. ) +: LINE ( x1 y1 z1 x2 y2 z2 color -- ) + LINE-SETUP + BEGIN + LX @ LY @ LCOLOR @ PLOT + LINE-DONE? 0= LINE-STUCK? 0= AND + WHILE + LINE-STEP + REPEAT ; + +Block 4907 +( Shared state for CIRCLE/ARC/ELLIPSE. CIRC-PT: point on a ) +( circle of radius CRAD centered (CX,CY) at given angle. ) +VARIABLE CX VARIABLE CY VARIABLE CZ VARIABLE CRAD +VARIABLE CCOLOR VARIABLE PX VARIABLE PY +: CIRC-PT ( ang -- x y ) + DUP Q.SIN CRAD @ Q.FROM-INT Q.* Q.TO-INT CY @ + + SWAP Q.COS CRAD @ Q.FROM-INT Q.* Q.TO-INT CX @ + + SWAP ; + +Block 4908 +( CIRCLE: 36-segment polygon approximation, flat at z=cz. ) +: CIRCLE ( cx cy cz r color -- ) + CCOLOR ! CRAD ! CZ ! CY ! CX ! + 0 CIRC-PT PY ! PX ! + 36 0 DO + PX @ PY @ CZ @ + I 1+ 11438 * CIRC-PT + 2DUP PY ! PX ! + CZ @ CCOLOR @ + LINE + LOOP ; + +Block 4909 +( ARC: partial circle, start/end angles in Q48.16 radians, ) +( 18 segments. Reuses CIRC-PT/CX/CY/CZ/CRAD/CCOLOR/PX/PY. ) +VARIABLE ASTART VARIABLE AEND VARIABLE ASTEP +: ARC-SETUP ( cx cy cz r a0 a1 color -- ) + CCOLOR ! AEND ! ASTART ! + CRAD ! CZ ! CY ! CX ! + AEND @ ASTART @ - 18 / ASTEP ! + ASTART @ CIRC-PT PY ! PX ! ; + +Block 4910 +( ARC: draws the arc using ARC-SETUP above. ) +: ARC ( cx cy cz r a0 a1 color -- ) + ARC-SETUP + 18 0 DO + PX @ PY @ CZ @ + ASTART @ I 1+ ASTEP @ * + + CIRC-PT + 2DUP PY ! PX ! + CZ @ CCOLOR @ + LINE + LOOP ; + +Block 4911 +( ELLIPSE-PT: independent x/y radii, reuses CX/CY/CZ. ) +VARIABLE ERX VARIABLE ERY +: ELLIPSE-PT ( ang -- x y ) + DUP Q.SIN ERY @ Q.FROM-INT Q.* Q.TO-INT CY @ + + SWAP Q.COS ERX @ Q.FROM-INT Q.* Q.TO-INT CX @ + + SWAP ; + +Block 4912 +( ELLIPSE: 36-segment polygon, flat at z=cz. ) +: ELLIPSE ( cx cy cz rx ry color -- ) + CCOLOR ! ERY ! ERX ! CZ ! CY ! CX ! + 0 ELLIPSE-PT PY ! PX ! + 36 0 DO + PX @ PY @ CZ @ + I 1+ 11438 * ELLIPSE-PT + 2DUP PY ! PX ! + CZ @ CCOLOR @ + LINE + LOOP ; diff --git a/fb/amd64/geom-test-circle-fixed.png b/fb/amd64/geom-test-circle-fixed.png new file mode 100644 index 0000000000000000000000000000000000000000..eaf00f6e001c58324a21e120941bac0e3a4b5fa7 GIT binary patch literal 9628 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 y`p*dQx7hVZ6#QRe%0Dyyk}>?FtH0uE><8exFCJC!v=3gv?a{-|hstab7yb+68Ta=9 literal 0 HcmV?d00001 diff --git a/fb/amd64/geom-test-full-wordset.png b/fb/amd64/geom-test-full-wordset.png new file mode 100644 index 0000000000000000000000000000000000000000..245ab75b0a9bc3d3c0dfa27506e97f780cd306d0 GIT binary patch literal 10560 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 R_wB&;%t>qWGE>j%{|AinG=u;E literal 0 HcmV?d00001 diff --git a/include/q48_16.h b/include/q48_16.h index cf33dce..f2e46a8 100644 --- a/include/q48_16.h +++ b/include/q48_16.h @@ -157,16 +157,23 @@ static inline q48_16_t q48_from_u64(uint64_t u) { } /** - * @brief Convert Q48.16 to unsigned 64-bit integer (truncate fractional) + * @brief Convert Q48.16 to a 64-bit integer (truncate fractional) * - * Math: q / 2^16 (shift right by 16 bits) - * Example: q48_to_u64(0x10000) = 1 + * Math: q / 2^16 (arithmetic shift right by 16 bits) + * Example: q48_to_u64(0x10000) = 1, q48_to_u64(-0x10000) = -1 + * + * q48_16_t values are two's-complement signed under the hood (q48_neg/ + * q48_abs already treat them that way); a plain unsigned (logical) shift + * would corrupt negative inputs instead of sign-extending them, so this + * shifts via a signed intermediate. Bit-identical to the old behavior for + * non-negative q (the only case this function's other caller, the + * inference engine's sum-of-squares accumulation, ever produces). * * @param q Q48.16 value - * @return q >> 16 as unsigned 64-bit integer + * @return q >> 16, sign-extended, reinterpreted as uint64_t */ static inline uint64_t q48_to_u64(q48_16_t q) { - return q >> 16; + return (uint64_t)(((int64_t)q) >> 16); } #endif /* STARKERNEL_Q48_16_H */ diff --git a/include/starkernel/q48_16.h b/include/starkernel/q48_16.h index 237ea4c..5d1b263 100644 --- a/include/starkernel/q48_16.h +++ b/include/starkernel/q48_16.h @@ -114,10 +114,13 @@ static inline q48_16_t q48_from_u64(uint64_t u) { } /** - * Convert Q48.16 to unsigned 64-bit integer (truncate fractional): q >> 16 + * Convert Q48.16 to a 64-bit integer (truncate fractional): q >> 16, + * arithmetic (signed) shift so negative q sign-extends correctly instead + * of producing garbage from an unsigned logical shift. Bit-identical to + * the old behavior for non-negative q. */ static inline uint64_t q48_to_u64(q48_16_t q) { - return q >> 16; + return (uint64_t)(((int64_t)q) >> 16); } /* ============================================================================ diff --git a/lfs/amd64/starforth b/lfs/amd64/starforth index 5079f3494d6f58460bcda35e62d3ba28337655ac..8367b065d5e73eff534aed1f374fb45f45a5d730 100755 GIT binary patch delta 160 zcmZ3{7`>t~dczJT5%EiVi&q)Bt95<&)|krR+|00hn$YGmOi$uC{t0+8e)6$A*t{cg z`;J7$*(FTB1SU`Xui0LAjS+~MfS4JGS%8=oh}nRc9f&!Am=lP(fS4PId4QOAd)+m@ n`(^B=R)&UFMyBm4zWhKe0K|eoECj^DKr8~pqT5q^#axO3&s0P+ delta 160 zcmZ3{7`>t~dczJTktyNL=i0vH9PoDE#n`cD*3oY#d*5w7!}KJM<~oL$27N?`KD|C;S}*BF7A35c12m<5PgftU@5*@2h?h&h3n3y8Uam!=j0zfPX#6mzU48$TpEV@0#SIngt0CFlvMgRZ+