Преглед изворни кода

calc: run-time set algebra and Succ/Pred (ladder 20912)

The CALC ladder moved 19847 -> 20912.

Runtime (entries 31..33):
  * set_op: [BP+4] = (op<<8)|size, [BP+6] = dest, [BP+8] = right,
    [BP+10] = left; op 0 AND, 1 OR, 2 AND NOT.
  * set_cmp: [BP+4] = size, [BP+6] = right, [BP+8] = left; AX carries
    equal (bit 0), strict subset (bit 1), strict superset (bit 2).
  * set_copy: [BP+4] = size, [BP+6] = source, [BP+8] = destination.

Compiler:
  * `+`, `-`, `*` over run-time sets; `=`, `<>`, `<`, `<=`, `>`, `>=`
    comparisons; and set-expression assignment.  Set operands are
    ADDRESSES; the left address is pushed before the right is parsed so a
    DI-addressed field survives.  The byte count comes from the typed set
    when one side is an inline literal (the default literal is 32 bytes,
    but CALC's `set of Attributes` field is one), and one scratch data
    buffer is allocated per expression.
  * Succ/Pred builtins (constant-folded or INC/DEC AX).
  * fixtures t85_setops and t86_succ, both executed under qemu and Exec86.

The next CALC failure is now TP3 error 98 at 20912: the compiler's fixed
4 KiB code window above the runtime has been reached.  That is the §3
layout change, not a missing construct.

Harness: the driver understands four stack words (set_op needs size,
destination and two sources); rt_exec gained set data blocks and eleven
set cases.

rt_exec 275/275; compile matrix 87/87; run_com_exec 76/76; run_exec86
76/76; ladder 1/1 at ERR 98 20912; non-vacuity 121/121; run_all ALL PASS.
Eric Streit пре 1 дан
родитељ
комит
203f77e862

+ 28 - 16
CALC-COMPILE.md

@@ -549,16 +549,15 @@ Exec86):
   byte-for-byte the same for INTEGER locals, so the compile matrix would have
   byte-for-byte the same for INTEGER locals, so the compile matrix would have
   been green and only `t40_readln` (and later CALC) would have noticed.
   been green and only `t40_readln` (and later CALC) would have noticed.
 - **Verified baseline, run on the code HEAD above:** `./tests/run_all.sh` →
 - **Verified baseline, run on the code HEAD above:** `./tests/run_all.sh` →
-  **OVERALL: ALL PASS**, compile matrix **85/85**, CALC ladder **1/1** at
-  `ERR 102 19847`, terminal config **4/4**, 76 `.COM` linked and **74 executed
+  **OVERALL: ALL PASS**, compile matrix **87/87**, CALC ladder **1/1** at
+  `ERR 98 20912`, terminal config **4/4**, 78 `.COM` linked and **76 executed
   under both qemu and Exec86** (`t64_arrays` remains compile-only because it
   under both qemu and Exec86** (`t64_arrays` remains compile-only because it
-  has no `.out`; its ~16 KB image fits the raised read).  `tests/nonvacuity.sh`:
-  **118 ok, 0 failed**.  The runtime is 3479 bytes (wrintw, real_from_int,
-  real_add, real_sub, real_mul, real_div, real_cmp, real_int, real_fmt,
-  real_val, real_write; the golden was re-blessed) and `tests/rt_exec.py`
-  passes **264/264**, including 16 add/sub, ten multiply, fourteen division,
-  thirty comparison, eighteen Int, the MBF format/parse cases and eight
-  real-output cases.  `check_realconst.py` pins the measured 6-byte Real
+  has no `.out`).  `tests/nonvacuity.sh`: **121 ok, 0 failed**.  The runtime is
+  3664 bytes (wrintw, real_from_int, real_add, real_sub, real_mul, real_div,
+  real_cmp, real_int, real_fmt, real_val, real_write, set_op, set_cmp,
+  set_copy; the golden was re-blessed) and `tests/rt_exec.py` passes
+  **275/275**, including the MBF arithmetic/output/parse cases and eleven
+  set-operation cases.  `check_realconst.py` pins the measured 6-byte Real
   operand bytes.
   operand bytes.
 - **`tests/nonvacuity.sh`:** re-run after this commit's cases (the set
 - **`tests/nonvacuity.sh`:** re-run after this commit's cases (the set
   membership bit among them); see the commit message for the count. It is not in
   membership bit among them); see the commit message for the count. It is not in
@@ -754,16 +753,29 @@ Then the two that are *outside* the ladder and gate the goal as stated:
         in a comparison: `if Sheet[UFX,UFY].Contents <> '' then' pushes the
         in a comparison: `if Sheet[UFX,UFY].Contents <> '' then' pushes the
         left address before parsing the right, so DI survives; pinned by
         left address before parsing the right, so DI survives; pinned by
         `t83_strfield_cmp`.  The ladder moved **18267 -> 19847**.
         `t83_strfield_cmp`.  The ladder moved **18267 -> 19847**.
-      * **NEXT BLOCKER:** run-time SET ARITHMETIC.  CALC 19847 is
-        `until (Sheet[FX,FY].CellStatus * [OverWritten,Locked] = []) or ...;`
-        - the set field intersected with a literal.  Constant sets, set
-        fields, assignment and membership exist; `+`, `-`, `*`, `=`, `<>`,
-        `<=`, `>=` over run-time sets are the next rung.
+      * **DONE: run-time SET ALGEBRA** (`v-TP3-CALC-SETOPS`).  `set_op`
+        (entry 31: intersection/union/difference over `size` bytes),
+        `set_cmp` (entry 32: equality/strict-subset/strict-superset mask) and
+        `set_copy` (entry 33) are in Runtime.mod.  The compiler pushes set
+        ADDRESSES, chooses the byte count from the typed set (an inline
+        literal is the default 32-byte `set of Char`; a typed field wins and
+        the literal's first bytes are used), and allocates one scratch data
+        buffer per set expression.  `+`, `-`, `*`, `=`, `<>`, `<`, `<=`,
+        `>`, `>=` and set-expression assignment all work.  `Succ`/`Pred` were
+        the next blocker and are now builtins too.  Fixtures
+        `t85_setops`/`t86_succ`.
+      * **NEXT BLOCKER: THE §3 LAYOUT.**  CALC now reaches 20912 and fails
+        with TP3 error **98 (memory overflow)**: the compiler reserves a
+        FIXED 4 KiB code window above the runtime (`dataBase`), and CALC's own
+        code has reached it.  This is not a missing construct; code and data
+        cannot share the 64 KiB .COM segment with a static 4 KiB split.
+        Re-orienting the image (data after the actual code, or a far model)
+        is the layout change item 12, and is the next rung.
       * **STILL TO COME:** `Str`/`Val` wiring, then real expressions (a 6-byte
       * **STILL TO COME:** `Str`/`Val` wiring, then real expressions (a 6-byte
         temporary/value model), real comparisons and real function results.
         temporary/value model), real comparisons and real function results.
-      * **HEADROOM:** the runtime is 3479 bytes and the probe's scaffold starts
+      * **HEADROOM:** the runtime is 3664 bytes and the probe's scaffold starts
         at HDR=0x1100 with RT_BASE=0x0190, so the ceiling is 3952 bytes - about
         at HDR=0x1100 with RT_BASE=0x0190, so the ceiling is 3952 bytes - about
-        473 bytes left.  The boot read allows a .COM up to 0x6F00, so the next
+        288 bytes left.  The boot read allows a .COM up to 0x6F00, so the next
         additions can move HDR again (e.g. 0x2000) with plenty of room below
         additions can move HDR again (e.g. 0x2000) with plenty of room below
         the input at 0x7000.
         the input at 0x7000.
       * **Exec86** needed the FE group (INC/DEC r/m8) and CMC/CLC/STC/LAHF/
       * **Exec86** needed the FE group (INC/DEC r/m8) and CMC/CLC/STC/LAHF/

+ 269 - 12
shell/Compiler.mod

@@ -120,7 +120,7 @@ CONST
       not implemented yet is a loud ENoLib, never a silent no-op. *)
       not implemented yet is a loud ENoLib, never a silent no-op. *)
    BI_ClrScr  = 6 ;  BI_GotoXY = 7 ;  BI_LowVideo = 8 ;
    BI_ClrScr  = 6 ;  BI_GotoXY = 7 ;  BI_LowVideo = 8 ;
    BI_NormVideo = 9 ; BI_ClrEol = 10 ; BI_Delay = 11 ;
    BI_NormVideo = 9 ; BI_ClrEol = 10 ; BI_Delay = 11 ;
-   BI_KeyPressed = 12 ; BI_UpCase = 13 ;
+   BI_KeyPressed = 12 ; BI_UpCase = 13 ; BI_Succ = 14 ; BI_Pred = 15 ;
    (* the sub-codes EmCrtSeq takes *)
    (* the sub-codes EmCrtSeq takes *)
    CrtClr = 0 ; CrtDl = 1 ; CrtDh = 2 ; CrtCaret = 3 ; CrtEol = 4 ;
    CrtClr = 0 ; CrtDl = 1 ; CrtDh = 2 ; CrtCaret = 3 ; CrtEol = 4 ;
    CrtLow = 5 ; CrtNorm = 6 ; CrtDelay = 7 ; CrtKey = 8 ;
    CrtLow = 5 ; CrtNorm = 6 ; CrtDelay = 7 ; CrtKey = 8 ;
@@ -376,6 +376,9 @@ VAR
                                 in CX *)
                                 in CX *)
    TU_StrStore : CARDINAL ;  (* s := t; dest and source addresses on the stack,
    TU_StrStore : CARDINAL ;  (* s := t; dest and source addresses on the stack,
                                 limit in CX *)
                                 limit in CX *)
+   TU_SetOp    : CARDINAL ;  (* runtime set operations, entries 31..33 *)
+   TU_SetCmp   : CARDINAL ;
+   TU_SetCopy  : CARDINAL ;
    TU_CmpStr   : CARDINAL ;  (* string comparison; two addresses on the stack,
    TU_CmpStr   : CARDINAL ;  (* string comparison; two addresses on the stack,
                                 signed -1/0/+1 in AX *)
                                 signed -1/0/+1 in AX *)
    TU_StrCat   : CARDINAL ;  (* string concatenation; dest and source addresses
    TU_StrCat   : CARDINAL ;  (* string concatenation; dest and source addresses
@@ -2851,6 +2854,97 @@ BEGIN
    RETURN here
    RETURN here
 END EmStrBlob ;
 END EmStrBlob ;
 
 
+PROCEDURE EmPushSetAddr (r : ERes) ;
+(* Push the ADDRESS of a set value: the runtime's set entries take addresses.
+   A set literal/typed constant is code-resident (kind 7), a set-expression
+   result is a data buffer (kind 8), a named set is symbol+boff, and a field
+   reached through DI is already addressed. *)
+BEGIN
+   IF r.kind = 5 THEN
+      EmPushDi ()
+   ELSIF r.kind = 1 THEN
+      EmPushVarAddr (symtab [r.idx].local,
+                     (symtab [r.idx].off + r.boff) MOD 10000H)
+   ELSIF (r.kind = 7) OR (r.kind = 8) THEN
+      EmPushVarAddr (FALSE, r.setoff)
+   ELSE
+      Err (ENoLib)
+   END
+END EmPushSetAddr ;
+
+PROCEDURE SetPairSize (left, right : ERes ; VAR size, base : CARDINAL) : BOOLEAN ;
+(* The byte count for a set operation.  An inline literal is a 32-byte
+   `set of Char' by default; when the other operand is a typed set (CALC's
+   one-byte `set of Attributes') that type wins.  Two non-literals must have
+   the same origin and are taken at the smaller size; the runtime only ever
+   touches that many bytes. *)
+BEGIN
+   IF left.setbase # right.setbase THEN
+      RETURN FALSE
+   END ;
+   base := left.setbase ;
+   IF left.kind = 7 THEN
+      IF right.kind = 7 THEN
+         size := left.setsize
+      ELSE
+         size := right.setsize
+      END
+   ELSIF right.kind = 7 THEN
+      size := left.setsize
+   ELSE
+      size := left.setsize ;
+      IF right.setsize < size THEN
+         size := right.setsize
+      END
+   END ;
+   RETURN (size > 0) AND (size <= 32)
+END SetPairSize ;
+
+PROCEDURE AllocSetScratch (size : CARDINAL) : CARDINAL ;
+(* A fresh data buffer for one set expression.  One per operation, so a nested
+   or repeated expression cannot overwrite the other side while it is still
+   being consumed.  The bytes need no initialisation: every operation writes
+   all `size' of them before the value is read. *)
+VAR off : CARDINAL ;
+BEGIN
+   IF dc + size > 0F000H THEN
+      Err (EConstRange) ;
+      RETURN 0
+   END ;
+   off := dc ;
+   dc := dc + size ;
+   RETURN off
+END AllocSetScratch ;
+
+PROCEDURE SetBinEmit (op : CARDINAL ; left, right : ERes ; VAR res : ERes) ;
+(* The caller has already pushed the LEFT address (before parsing the right
+   operand, so a DI-addressed field survives).  Finish the argument list -
+   right, destination, (op<<8)|size - call the runtime, and return the buffer
+   as a kind-8 set value. *)
+VAR size, base, dest : CARDINAL ;
+BEGIN
+   IF NOT SetPairSize (left, right, size, base) THEN
+      Err (ENoLib) ;
+      RETURN
+   END ;
+   dest := AllocSetScratch (size) ;
+   IF NOT OK () THEN
+      RETURN
+   END ;
+   EmPushSetAddr (right) ;
+   EmPushVarAddr (FALSE, dest) ;
+   EmMovAxi (W16 (op * 256 + size)) ;
+   EmPushAx () ;
+   DropC (EmCall (TU_SetOp)) ;
+   EmAddSp (8) ;
+   res.kind := 8 ;
+   res.cls := TSet ;
+   res.chr := FALSE ;
+   res.setoff := dest ;
+   res.setbase := base ;
+   res.setsize := size
+END SetBinEmit ;
+
 PROCEDURE EmPushStrAddr (r : ERes) ;
 PROCEDURE EmPushStrAddr (r : ERes) ;
 (* Push the ADDRESS of a whole-string operand - the argument shape cmpstr
 (* Push the ADDRESS of a whole-string operand - the argument shape cmpstr
    takes, one per operand.
    takes, one per operand.
@@ -3359,6 +3453,7 @@ PROCEDURE ParseCmp (VAR r : ERes) ;
 VAR op : CARDINAL ;
 VAR op : CARDINAL ;
     left, right : ERes ;
     left, right : ERes ;
     f : LONGINT ;
     f : LONGINT ;
+    size, base : CARDINAL ;
 BEGIN
 BEGIN
    ParseAdd (r) ;
    ParseAdd (r) ;
    LOOP
    LOOP
@@ -3394,7 +3489,42 @@ BEGIN
          RETURN
          RETURN
       END ;
       END ;
       left := r ;
       left := r ;
-      IF left.cls = TString THEN
+      IF left.cls = TSet THEN
+         (* Set comparison.  set_cmp returns a mask (bit 0 equal, bit 1 strict
+            subset, bit 2 strict superset); the operator selects which bits
+            answer it, and the shared EmRelSetcc arm turns the flags into a
+            boolean.  The left address is pushed before the right operand is
+            parsed, for the same DI reason as strings and set arithmetic. *)
+         EmPushSetAddr (left) ;
+         ParseAdd (right) ;
+         IF NOT OK () THEN
+            RETURN
+         END ;
+         IF right.cls # TSet THEN
+            Err (ETypeErr) ;
+            RETURN
+         END ;
+         IF NOT SetPairSize (left, right, size, base) THEN
+            Err (ENoLib) ;
+            RETURN
+         END ;
+         EmPushSetAddr (right) ;
+         EmMovAxi (size) ;
+         EmPushAx () ;
+         DropC (EmCall (TU_SetCmp)) ;
+         EmAddSp (4) ;
+         CASE op OF
+            1 : EmMovCxi (1) ; EmAndAxCx () ; EmOrAxAx () ; EmRelSetcc (2) ;
+         |  2 : EmMovCxi (1) ; EmAndAxCx () ; EmXorAl01 () ;
+               EmOrAxAx () ; EmRelSetcc (2) ;
+         |  3 : EmMovCxi (2) ; EmAndAxCx () ; EmOrAxAx () ; EmRelSetcc (2) ;
+         |  4 : EmMovCxi (4) ; EmAndAxCx () ; EmOrAxAx () ; EmRelSetcc (2) ;
+         |  5 : EmMovCxi (5) ; EmAndAxCx () ; EmOrAxAx () ; EmRelSetcc (2) ;
+         |  6 : EmMovCxi (3) ; EmAndAxCx () ; EmOrAxAx () ; EmRelSetcc (2)
+         END ;
+         r.kind := 2 ;
+         r.cls := TBool
+      ELSIF left.cls = TString THEN
          (* A string comparison: cmpstr, the entry TPSRC9's vcompare (133)
          (* A string comparison: cmpstr, the entry TPSRC9's vcompare (133)
             reaches through TPSRC2's csteq/cstne/cstge/cstle/cstg/cstl
             reaches through TPSRC2's csteq/cstne/cstge/cstle/cstg/cstl
             wrappers (890-925).
             wrappers (890-925).
@@ -3430,8 +3560,8 @@ BEGIN
       ELSE
       ELSE
          SaveLeft (left) ;
          SaveLeft (left) ;
          ParseAdd (right) ;
          ParseAdd (right) ;
-         IF right.cls = TString THEN
-            Err (ETypeErr) ;         (* a number compared with a string *)
+         IF (right.cls = TString) OR (right.cls = TSet) THEN
+            Err (ETypeErr) ;         (* a number compared with a string/set *)
             RETURN
             RETURN
          END ;
          END ;
          IF (left.kind = 0) AND (right.kind = 0) THEN
          IF (left.kind = 0) AND (right.kind = 0) THEN
@@ -3474,9 +3604,41 @@ BEGIN
          RETURN
          RETURN
       END ;
       END ;
       left := r ;
       left := r ;
-      SaveLeft (left) ;
-      ParseMul (right) ;
-      BinOpEmit (op, left, right, r)
+      IF left.cls = TSet THEN
+         (* Set union/difference.  The left address goes on the stack BEFORE
+            the right is parsed: a DI-addressed set field must survive the
+            right-hand expression.  `OR' is boolean, not set union. *)
+         IF (op = OpAdd) OR (op = OpSub) THEN
+            EmPushSetAddr (left) ;
+            ParseMul (right) ;
+            IF NOT OK () THEN
+               RETURN
+            END ;
+            IF right.cls # TSet THEN
+               Err (ETypeErr) ;
+               RETURN
+            END ;
+            IF op = OpAdd THEN
+               SetBinEmit (1, left, right, r)
+            ELSE
+               SetBinEmit (2, left, right, r)
+            END
+         ELSE
+            Err (ETypeErr) ;
+            RETURN
+         END
+      ELSE
+         SaveLeft (left) ;
+         ParseMul (right) ;
+         IF NOT OK () THEN
+            RETURN
+         END ;
+         IF right.cls = TSet THEN
+            Err (ETypeErr) ;
+            RETURN
+         END ;
+         BinOpEmit (op, left, right, r)
+      END
    END
    END
 END ParseAdd ;
 END ParseAdd ;
 
 
@@ -3505,9 +3667,35 @@ BEGIN
          RETURN
          RETURN
       END ;
       END ;
       left := r ;
       left := r ;
-      SaveLeft (left) ;
-      ParseNeg (right) ;
-      BinOpEmit (op, left, right, r)
+      IF left.cls = TSet THEN
+         (* Set intersection.  Same push-before-the-right rule as ParseAdd. *)
+         IF op = OpMul THEN
+            EmPushSetAddr (left) ;
+            ParseNeg (right) ;
+            IF NOT OK () THEN
+               RETURN
+            END ;
+            IF right.cls # TSet THEN
+               Err (ETypeErr) ;
+               RETURN
+            END ;
+            SetBinEmit (0, left, right, r)
+         ELSE
+            Err (ETypeErr) ;
+            RETURN
+         END
+      ELSE
+         SaveLeft (left) ;
+         ParseNeg (right) ;
+         IF NOT OK () THEN
+            RETURN
+         END ;
+         IF right.cls = TSet THEN
+            Err (ETypeErr) ;
+            RETURN
+         END ;
+         BinOpEmit (op, left, right, r)
+      END
    END
    END
 END ParseMul ;
 END ParseMul ;
 
 
@@ -3748,6 +3936,42 @@ BEGIN
       r.cls := TChar ;
       r.cls := TChar ;
       r.chr := FALSE ;
       r.chr := FALSE ;
       RETURN
       RETURN
+   ELSIF (symtab [idx].tag = KBuiltin) AND
+         ((symtab [idx].cls = BI_Succ) OR (symtab [idx].cls = BI_Pred)) THEN
+      (* Succ(x) / Pred(x) on an ordinal.  CALC's `FX := Succ(FX)' is the
+         first use.  A constant folds; otherwise load the value and INC/DEC
+         it, preserving the operand's class so an assignment back to a CHAR
+         subrange stores one byte as before. *)
+      IF NOT MatchDelim ('(') THEN
+         Err (ENoSemi) ;
+         RETURN
+      END ;
+      ParseExpr (r) ;
+      ExpectDelim (')', ENoSemi) ;
+      IF NOT OK () THEN
+         RETURN
+      END ;
+      IF (r.cls # TChar) AND (r.cls # TScalar) THEN
+         Err (ETypeErr) ;
+         RETURN
+      END ;
+      IF r.kind = 0 THEN
+         IF symtab [idx].cls = BI_Succ THEN
+            r.imm := VAL (LONGINT, W16 (r.imm + 1))
+         ELSE
+            r.imm := VAL (LONGINT, W16 (r.imm - 1))
+         END
+      ELSE
+         LoadAtom (r) ;
+         IF symtab [idx].cls = BI_Succ THEN
+            EmIncAx ()
+         ELSE
+            EmDecAx ()
+         END ;
+         r.kind := 2
+      END ;
+      r.chr := FALSE ;
+      RETURN
    ELSIF (symtab [idx].tag = KBuiltin) AND (symtab [idx].cls = BI_KeyPressed) THEN
    ELSIF (symtab [idx].tag = KBuiltin) AND (symtab [idx].cls = BI_KeyPressed) THEN
       (* KeyPressed: a boolean FUNCTION with no argument, and TP3 lets it be
       (* KeyPressed: a boolean FUNCTION with no argument, and TP3 lets it be
          written without a parameter list (`until KeyPressed'). *)
          written without a parameter list (`until KeyPressed'). *)
@@ -4180,8 +4404,36 @@ BEGIN
       END ;
       END ;
       Skip () ;
       Skip () ;
       IF CurCh () # '[' THEN
       IF CurCh () # '[' THEN
-         (* set := set, or a set expression: the next increment *)
-         Err (ENoLib) ;
+         (* `set := set' or a set expression.  The destination is a variable
+            or a DI-addressed field; save the DI address BEFORE the right-hand
+            expression can reuse DI, then copy the runtime's bytes. *)
+         IF r.kind = 5 THEN
+            EmPushDi ()
+         END ;
+         ParseExpr (src) ;
+         IF NOT OK () THEN
+            RETURN
+         END ;
+         IF src.cls # TSet THEN
+            Err (ETypeErr) ;
+            RETURN
+         END ;
+         IF r.kind = 1 THEN
+            EmPushVarAddr (symtab [r.idx].local,
+                           (symtab [r.idx].off + r.boff) MOD 10000H)
+         ELSIF r.kind # 5 THEN
+            Err (ENoLib) ;
+            RETURN
+         END ;
+         EmPushSetAddr (src) ;
+         n := r.setsize ;
+         IF (src.kind = 8) AND (src.setsize < n) THEN
+            n := src.setsize
+         END ;
+         EmMovAxi (n) ;
+         EmPushAx () ;
+         DropC (EmCall (TU_SetCopy)) ;
+         EmAddSp (4) ;
          RETURN
          RETURN
       END ;
       END ;
       IF NOT RdSetLiteral (r.setbase, r.setsize, sbuf) THEN
       IF NOT RdSetLiteral (r.setbase, r.setsize, sbuf) THEN
@@ -6356,6 +6608,8 @@ BEGIN
    i := NewSym ("KEYPRESSED", KBuiltin, BI_KeyPressed, 0, 0, 0, 0, FALSE) ;
    i := NewSym ("KEYPRESSED", KBuiltin, BI_KeyPressed, 0, 0, 0, 0, FALSE) ;
    symtab [i].defnd := TRUE ;
    symtab [i].defnd := TRUE ;
    i := NewSym ("UPCASE", KBuiltin, BI_UpCase, 0, 0, 0, 0, FALSE) ;
    i := NewSym ("UPCASE", KBuiltin, BI_UpCase, 0, 0, 0, 0, FALSE) ;
+   i := NewSym ("SUCC", KBuiltin, BI_Succ, 0, 0, 0, 0, FALSE) ;
+   i := NewSym ("PRED", KBuiltin, BI_Pred, 0, 0, 0, 0, FALSE) ;
    symtab [i].defnd := TRUE ;
    symtab [i].defnd := TRUE ;
    (* KBD: the console keyboard as a TEXT file.  This runtime's read entries
    (* KBD: the console keyboard as a TEXT file.  This runtime's read entries
       already read the console, so `Read(Kbd, Ch)' drops the file argument and
       already read the console, so `Read(Kbd, Ch)' drops the file argument and
@@ -6510,6 +6764,9 @@ BEGIN
    TU_Halt     := RT_Entry (12) ;
    TU_Halt     := RT_Entry (12) ;
    TU_WrInl    := RT_Entry (13) ;      (* inline string literal *)
    TU_WrInl    := RT_Entry (13) ;      (* inline string literal *)
    TU_RdByte   := RT_Entry (14) ;      (* a BYTE read stores one byte *)
    TU_RdByte   := RT_Entry (14) ;      (* a BYTE read stores one byte *)
+   TU_SetOp    := RT_Entry (31) ;
+   TU_SetCmp   := RT_Entry (32) ;
+   TU_SetCopy  := RT_Entry (33) ;
    TU_WrStr    := RT_Entry (15) ;      (* a string variable is written through
    TU_WrStr    := RT_Entry (15) ;      (* a string variable is written through
                                           the address on the stack *)
                                           the address on the stack *)
    TU_RdStr    := RT_Entry (16) ;      (* readln(s)/read(s): TPSRC8 prdstr,
    TU_RdStr    := RT_Entry (16) ;      (* readln(s)/read(s): TPSRC8 prdstr,

+ 7 - 0
shell/Runtime.def

@@ -64,6 +64,13 @@ CONST
    E_RealVal = 29 ;         (* ascreal: parse an ASCIIZ string into a real *)
    E_RealVal = 29 ;         (* ascreal: parse an ASCIIZ string into a real *)
    E_RealWrite = 30 ;       (* fmtreal + padding + console output:
    E_RealWrite = 30 ;       (* fmtreal + padding + console output:
                                [BP+4]=decimals, [BP+6]=width, [BP+8]=real *)
                                [BP+4]=decimals, [BP+6]=width, [BP+8]=real *)
+   E_SetOp   = 31 ;         (* set op: [BP+4]=packed(op,size), [BP+6]=dest,
+                               [BP+8]=right, [BP+10]=left *)
+   E_SetCmp  = 32 ;         (* set compare: [BP+4]=size, [BP+6]=right,
+                               [BP+8]=left; AX = bit0 equal, bit1 subset,
+                               bit2 superset *)
+   E_SetCopy = 33 ;         (* set copy: [BP+4]=size, [BP+6]=src,
+                               [BP+8]=dest *)
 
 
    (* Where a .COM's first byte ends up.  DOS loads a .COM at CS:0100 (the
    (* Where a .COM's first byte ends up.  DOS loads a .COM at CS:0100 (the
       100 bytes below are the PSP), and CS = DS, so an image offset K is at
       100 bytes below are the PSP), and CS = DS, so an image offset K is at

+ 128 - 4
shell/Runtime.mod

@@ -149,7 +149,7 @@ VAR
    dataAt : CARDINAL ;
    dataAt : CARDINAL ;
    rtBase : CARDINAL ;
    rtBase : CARDINAL ;
    built  : BOOLEAN ;
    built  : BOOLEAN ;
-   entNm  : ARRAY [0..30] OF ARRAY [0..MaxNm] OF CHAR ;
+   entNm  : ARRAY [0..33] OF ARRAY [0..MaxNm] OF CHAR ;
 
 
 (* ---------------------------------------------------------------- *)
 (* ---------------------------------------------------------------- *)
 (*  name helpers                                                     *)
 (*  name helpers                                                     *)
@@ -382,7 +382,6 @@ PROCEDURE XorDiDi ; BEGIN B (31H) ; B (0FFH) END XorDiDi ;  (* 11 111 111 *)
 
 
 PROCEDURE IncCx ; BEGIN B (41H) END IncCx ;
 PROCEDURE IncCx ; BEGIN B (41H) END IncCx ;
 PROCEDURE IncSi ; BEGIN B (46H) END IncSi ;
 PROCEDURE IncSi ; BEGIN B (46H) END IncSi ;
-PROCEDURE IncDi ; BEGIN B (47H) END IncDi ;
 PROCEDURE DecSi ; BEGIN B (4EH) END DecSi ;
 PROCEDURE DecSi ; BEGIN B (4EH) END DecSi ;
 PROCEDURE AddDi2 ; BEGIN B (83H) ; B (0C7H) ; B (2) END AddDi2 ;  (* 11 000 111 *)
 PROCEDURE AddDi2 ; BEGIN B (83H) ; B (0C7H) ; B (2) END AddDi2 ;  (* 11 000 111 *)
 
 
@@ -806,6 +805,31 @@ PROCEDURE MovDiBp6 ; BEGIN B (8BH) ; B (7EH) ; B (6) END MovDiBp6 ;
 PROCEDURE MovDxBp6 ; BEGIN B (8BH) ; B (56H) ; B (6) END MovDxBp6 ;
 PROCEDURE MovDxBp6 ; BEGIN B (8BH) ; B (56H) ; B (6) END MovDxBp6 ;
 PROCEDURE PushBp6 ; BEGIN B (0FFH) ; B (76H) ; B (6) END PushBp6 ;
 PROCEDURE PushBp6 ; BEGIN B (0FFH) ; B (76H) ; B (6) END PushBp6 ;
 PROCEDURE MovCxBp6 ; BEGIN B (8BH) ; B (4EH) ; B (6) END MovCxBp6 ;
 PROCEDURE MovCxBp6 ; BEGIN B (8BH) ; B (4EH) ; B (6) END MovCxBp6 ;
+PROCEDURE MovCxBp4 ; BEGIN B (8BH) ; B (4EH) ; B (4) END MovCxBp4 ;
+PROCEDURE MovBxBp8 ; BEGIN B (8BH) ; B (5EH) ; B (8) END MovBxBp8 ;
+PROCEDURE MovSiBp8 ; BEGIN B (8BH) ; B (76H) ; B (8) END MovSiBp8 ;
+PROCEDURE MovSiBp10 ; BEGIN B (8BH) ; B (76H) ; B (0AH) END MovSiBp10 ;
+PROCEDURE LdDlDi ; BEGIN B (8AH) ; B (15H) END LdDlDi ;          (* DL:=[DI] *)
+PROCEDURE AndAlDl ; BEGIN B (20H) ; B (0D0H) END AndAlDl ;       (* AL:=AL AND DL *)
+PROCEDURE OrAlDl ; BEGIN B (08H) ; B (0D0H) END OrAlDl ;         (* AL:=AL OR DL *)
+PROCEDURE NotDl ; BEGIN B (0F6H) ; B (0D2H) END NotDl ;          (* NOT DL *)
+PROCEDURE NotAl ; BEGIN B (0F6H) ; B (0D0H) END NotAl ;          (* NOT AL *)
+PROCEDURE MovBlAl ; BEGIN B (88H) ; B (0C3H) END MovBlAl ;       (* BL:=AL *)
+PROCEDURE AndAlDh ; BEGIN B (20H) ; B (0F0H) END AndAlDh ;       (* AL:=AL AND DH *)
+PROCEDURE CmpBlDh ; BEGIN B (38H) ; B (0F3H) END CmpBlDh ;       (* CMP BL,DH *)
+PROCEDURE AndAxImm (v : CARDINAL) ;
+BEGIN B (25H) ; W (v) END AndAxImm ;                             (* AND AX,imm16 *)
+PROCEDURE TestAxImm (v : CARDINAL) ;
+BEGIN B (0A9H) ; W (v) END TestAxImm ;                           (* TEST AX,imm16 *)
+PROCEDURE AndAhImm (v : CARDINAL) ;
+BEGIN B (80H) ; B (0E4H) ; B (v MOD 256) END AndAhImm ;          (* AND AH,imm8 *)
+PROCEDURE TestAhImm (v : CARDINAL) ;
+BEGIN B (0F6H) ; B (0C4H) ; B (v MOD 256) END TestAhImm ;        (* TEST AH,imm8 *)
+PROCEDURE MovAlAh ; BEGIN B (88H) ; B (0E0H) END MovAlAh ;       (* AL:=AH *)
+PROCEDURE CmpAhImm (v : CARDINAL) ;
+BEGIN B (80H) ; B (0FCH) ; B (v MOD 256) END CmpAhImm ;          (* CMP AH,imm8 *)
+PROCEDURE DecDh ; BEGIN B (0FEH) ; B (0CEH) END DecDh ;          (* DEC DH *)
+PROCEDURE IncDi ; BEGIN B (47H) END IncDi ;
 PROCEDURE MovDxBp4 ; BEGIN B (8BH) ; B (56H) ; B (4) END MovDxBp4 ;
 PROCEDURE MovDxBp4 ; BEGIN B (8BH) ; B (56H) ; B (4) END MovDxBp4 ;
 PROCEDURE MovDiBp8 ; BEGIN B (8BH) ; B (7EH) ; B (8) END MovDiBp8 ;
 PROCEDURE MovDiBp8 ; BEGIN B (8BH) ; B (7EH) ; B (8) END MovDiBp8 ;
 PROCEDURE SbbBxData (delta : CARDINAL) ;
 PROCEDURE SbbBxData (delta : CARDINAL) ;
@@ -2780,6 +2804,103 @@ BEGIN
    MovSpBp ; PopBp ; RetR
    MovSpBp ; PopBp ; RetR
 END EmitRealConv ;
 END EmitRealConv ;
 
 
+PROCEDURE EmitSetOps ;
+(* Set algebra over byte arrays.  A set VALUE is an address plus a length;
+   the compiler picks the length from the declared set type.  All three
+   entries take the length on the stack, so no register state survives a
+   call except what the entry itself preserves.
+
+   set_op:  [BP+4] = (op << 8) | size, [BP+6] = dest, [BP+8] = right,
+            [BP+10] = left.  op 0 = AND (intersection), 1 = OR (union),
+            2 = left AND NOT right (difference).
+   set_cmp: [BP+4] = size, [BP+6] = right, [BP+8] = left.  AX = mask:
+            bit 0 = equal, bit 1 = strict subset, bit 2 = strict superset.
+   set_copy: [BP+4] = size, [BP+6] = source, [BP+8] = destination. *)
+BEGIN
+   M ("set_op") ;
+   PushBp ; MovBpSp ;
+   PushBx ; PushCx ; PushDx ; PushSi ; PushDi ;
+   MovAxBp4 ;                       (* AH = op, AL = size *)
+   MovDhAl ;                        (* DH = byte counter *)
+   MovSiBp10 ;                      (* SI = left *)
+   MovDiBp8 ;                       (* DI = right *)
+   MovBxBp6 ;                       (* BX = destination *)
+   CmpDh0 ;
+   Je8 ("so_done") ;
+   M ("so_loop") ;
+   LdAlSi ; LdDlDi ;
+   CmpAhImm (0) ; Je8 ("so_and") ;
+   CmpAhImm (1) ; Je8 ("so_or") ;
+   NotDl ; AndAlDl ;                (* difference *)
+   Jmp8 ("so_store") ;
+   M ("so_and") ;
+   AndAlDl ;
+   Jmp8 ("so_store") ;
+   M ("so_or") ;
+   OrAlDl ;
+   M ("so_store") ;
+   StBxAl ;
+   IncSi ; IncDi ; IncBx ;
+   DecDh ;
+   Jne8 ("so_loop") ;
+   M ("so_done") ;
+   PopDi ; PopSi ; PopDx ; PopCx ; PopBx ;
+   MovSpBp ; PopBp ; RetR ;
+
+   M ("set_cmp") ;
+   PushBp ; MovBpSp ;
+   PushBx ; PushCx ; PushDx ; PushSi ; PushDi ;
+   MovCxBp4 ;                       (* CX = size *)
+   MovSiBp8 ;                       (* left *)
+   MovDiBp6 ;                       (* right *)
+   MovAh (7) ;                      (* equal | subset | superset; AH, not AX:
+                                       AL is the set byte under test *)
+   Jcxz8 ("scm_final") ;
+   M ("scm_loop") ;
+   LdAlSi ; LdDlDi ;
+   MovBlAl ; MovDhDl ;              (* keep the originals *)
+   CmpAlDl ;
+   Je8 ("scm_eq") ;
+   AndAhImm (0FEH) ;                (* not equal *)
+   M ("scm_eq") ;
+   NotDl ; AndAlDl ;                (* left AND NOT right *)
+   CmpAl0 ;
+   Je8 ("scm_sub") ;
+   AndAhImm (0FDH) ;                (* not a subset *)
+   M ("scm_sub") ;
+   MovAlBl ; NotAl ; AndAlDh ;      (* right AND NOT left *)
+   CmpAl0 ;
+   Je8 ("scm_sup") ;
+   AndAhImm (0FBH) ;                (* not a superset *)
+   M ("scm_sup") ;
+   IncSi ; IncDi ;
+   Loop8 ("scm_loop") ;
+   (* equality is not a STRICT subset/superset *)
+   M ("scm_final") ;
+   TestAhImm (1) ;
+   Je8 ("scm_done") ;
+   AndAhImm (0F9H) ;
+   M ("scm_done") ;
+   MovAlAh ;                        (* AX := the mask *)
+   MovAh (0) ;
+   PopDi ; PopSi ; PopDx ; PopCx ; PopBx ;
+   MovSpBp ; PopBp ; RetR ;
+
+   M ("set_copy") ;
+   PushBp ; MovBpSp ;
+   PushBx ; PushCx ; PushSi ;
+   MovCxBp4 ;
+   MovSiBp6 ;
+   MovBxBp8 ;
+   Jcxz8 ("scp_done") ;
+   M ("scp_loop") ;
+   LdAlSi ; StBxAl ; IncSi ; IncBx ;
+   Loop8 ("scp_loop") ;
+   M ("scp_done") ;
+   PopSi ; PopCx ; PopBx ;
+   MovSpBp ; PopBp ; RetR
+END EmitSetOps ;
+
 
 
 PROCEDURE EmitData ;
 PROCEDURE EmitData ;
 (* The runtime's data block.  The D_ constants name the offsets in it and are
 (* The runtime's data block.  The D_ constants name the offsets in it and are
@@ -2983,7 +3104,7 @@ BEGIN
    EmitGetCh ; EmitUnGetCh ;
    EmitGetCh ; EmitUnGetCh ;
    EmitRdStr ; EmitStrStore ; EmitCmpStr ; EmitStrCat ;
    EmitRdStr ; EmitStrStore ; EmitCmpStr ; EmitStrCat ;
    EmitRealFromInt ; EmitRealAddSub ; EmitRealMul ;
    EmitRealFromInt ; EmitRealAddSub ; EmitRealMul ;
-   EmitRealCmp ; EmitRealInt ; EmitRealConv ;
+   EmitRealCmp ; EmitRealInt ; EmitRealConv ; EmitSetOps ;
    EmitData ;
    EmitData ;
    FixUp ;
    FixUp ;
    SetStr (entNm [0], "initmem") ;
    SetStr (entNm [0], "initmem") ;
@@ -3017,6 +3138,9 @@ BEGIN
    SetStr (entNm [28], "real_fmt") ;
    SetStr (entNm [28], "real_fmt") ;
    SetStr (entNm [29], "real_val") ;
    SetStr (entNm [29], "real_val") ;
    SetStr (entNm [30], "real_write") ;
    SetStr (entNm [30], "real_write") ;
+   SetStr (entNm [31], "set_op") ;
+   SetStr (entNm [32], "set_cmp") ;
+   SetStr (entNm [33], "set_copy") ;
    built := TRUE
    built := TRUE
 END RT_Build ;
 END RT_Build ;
 
 
@@ -3044,7 +3168,7 @@ BEGIN
    IF NOT built THEN
    IF NOT built THEN
       RT_Build (0)
       RT_Build (0)
    END ;
    END ;
-   IF i > 30 THEN
+   IF i > 33 THEN
       RETURN 0
       RETURN 0
    END ;
    END ;
    RETURN rtBase + LblOff (entNm [i])
    RETURN rtBase + LblOff (entNm [i])

+ 6 - 3
shell/tests/RtProbe.mod

@@ -108,7 +108,7 @@ END PENT ;
 
 
 PROCEDURE Main ;
 PROCEDURE Main ;
 VAR i, n, base : CARDINAL ;
 VAR i, n, base : CARDINAL ;
-    names : ARRAY [0..30] OF ARRAY [0..15] OF CHAR ;
+    names : ARRAY [0..33] OF ARRAY [0..15] OF CHAR ;
 BEGIN
 BEGIN
    base := GetBase () ;
    base := GetBase () ;
    RT_Build (base) ;
    RT_Build (base) ;
@@ -121,7 +121,7 @@ BEGIN
    PCARD (RT_Size ()) ; PS (" bytes") ; NL ;
    PCARD (RT_Size ()) ; PS (" bytes") ; NL ;
    PS ("code ends at ") ; PCARD (RT_CodeEnd ()) ; NL ;
    PS ("code ends at ") ; PCARD (RT_CodeEnd ()) ; NL ;
    i := 0 ;
    i := 0 ;
-   WHILE i <= 30 DO
+   WHILE i <= 33 DO
       names [i] := "" ;
       names [i] := "" ;
       INC (i)
       INC (i)
    END ;
    END ;
@@ -143,8 +143,11 @@ BEGIN
    names [28] := "real_fmt" ;
    names [28] := "real_fmt" ;
    names [29] := "real_val" ;
    names [29] := "real_val" ;
    names [30] := "real_write" ;
    names [30] := "real_write" ;
+   names [31] := "set_op" ;
+   names [32] := "set_cmp" ;
+   names [33] := "set_copy" ;
    i := 0 ;
    i := 0 ;
-   WHILE i <= 30 DO
+   WHILE i <= 33 DO
       PENT (i, names [i]) ;
       PENT (i, names [i]) ;
       INC (i)
       INC (i)
    END ;
    END ;

+ 2 - 1
shell/tests/audit_helpers.py

@@ -146,7 +146,8 @@ NON_ONE_LINE = {
         "AddAxImm": COMP, "AddChImm": COMP, "AddClImm": COMP,
         "AddAxImm": COMP, "AddChImm": COMP, "AddClImm": COMP,
         "AndBlImm": COMP, "AndClImm": COMP, "CmpAxImm": COMP,
         "AndBlImm": COMP, "AndClImm": COMP, "CmpAxImm": COMP,
         "CmpBxByte": COMP, "CmpDxImm": COMP, "CmpSiData": COMP,
         "CmpBxByte": COMP, "CmpDxImm": COMP, "CmpSiData": COMP,
-        "DecData": COMP,
+        "DecData": COMP, "AndAhImm": COMP, "AndAxImm": COMP,
+        "CmpAhImm": COMP, "TestAhImm": COMP, "TestAxImm": COMP,
         "SubAl": PARAM, "CmpAl": PARAM, "AddDl": PARAM, "J8": COMP,
         "SubAl": PARAM, "CmpAl": PARAM, "AddDl": PARAM, "J8": COMP,
         "Jcc": COMP, "CmpCxV": PARAM,
         "Jcc": COMP, "CmpCxV": PARAM,
         "B": DATA, "C8": DATA,
         "B": DATA, "C8": DATA,

+ 1 - 1
shell/tests/check_8086.py

@@ -182,7 +182,7 @@ def probe_runtime():
 # listed rather than detected, and the runtime sweep (the backbone) plus the
 # listed rather than detected, and the runtime sweep (the backbone) plus the
 # execution oracles still cover the emitted instructions.
 # execution oracles still cover the emitted instructions.
 CODE_RESIDENT_CONST = {"t61_setconst", "t64_arrays",
 CODE_RESIDENT_CONST = {"t61_setconst", "t64_arrays",
-                       "t49_strcmp_lit", "t83_strfield_cmp"}
+                       "t49_strcmp_lit", "t83_strfield_cmp", "t85_setops"}
 # The last two emit string literals INLINE in the code stream
 # The last two emit string literals INLINE in the code stream
 # (`JMP over <len><chars>`): the bytes after the jump are data, and a linear
 # (`JMP over <len><chars>`): the bytes after the jump are data, and a linear
 # sweep that does not follow the jump decodes them as instructions.  The
 # sweep that does not follow the jump decodes them as instructions.  The

+ 36 - 0
shell/tests/exec/rtdrv.s

@@ -151,6 +151,13 @@
 	.set	R_BLK34, 0x1520
 	.set	R_BLK34, 0x1520
 	.set	R_BLK35, 0x1530
 	.set	R_BLK35, 0x1530
 	.set	R_BLK36, 0x1540
 	.set	R_BLK36, 0x1540
+	.set	SETA, 0x1580
+	.set	SETB, 0x1590
+	.set	SETC, 0x15A0
+	.set	SETD, 0x15B0
+	.set	SET2A, 0x15C0
+	.set	SET2B, 0x15D0
+	.set	SET2D, 0x15E0
 
 
 	.code16
 	.code16
 	.text
 	.text
@@ -274,6 +281,8 @@ drive:
 # The flags are re-read after the call because the entry has just used AX.
 # The flags are re-read after the call because the entry has just used AX.
 doslot:
 doslot:
 	movb	4(%bp), %al
 	movb	4(%bp), %al
+	testb	$64, %al
+	jnz	.Lfourstack
 	testb	$32, %al
 	testb	$32, %al
 	jnz	.Lthreestack
 	jnz	.Lthreestack
 	testb	$8, %al
 	testb	$8, %al
@@ -290,6 +299,12 @@ doslot:
 	pushw	8(%bp)			# [BP+8]
 	pushw	8(%bp)			# [BP+8]
 	pushw	6(%bp)			# [BP+6]
 	pushw	6(%bp)			# [BP+6]
 	pushw	2(%bp)			# [BP+4]
 	pushw	2(%bp)			# [BP+4]
+	jmp	.Lnostack
+.Lfourstack:
+	pushw	10(%bp)			# [BP+10]
+	pushw	8(%bp)			# [BP+8]
+	pushw	6(%bp)			# [BP+6]
+	pushw	2(%bp)			# [BP+4]
 .Lnostack:
 .Lnostack:
 	testb	$2, %al
 	testb	$2, %al
 	jz	.Lnoax
 	jz	.Lnoax
@@ -306,6 +321,8 @@ doslot:
 	call	*%si
 	call	*%si
 	movw	%ax, D_AX + LOAD_BIAS	# observable return value
 	movw	%ax, D_AX + LOAD_BIAS	# observable return value
 	movb	4(%bp), %al
 	movb	4(%bp), %al
+	testb	$64, %al
+	jnz	.Lcleanfour
 	testb	$32, %al
 	testb	$32, %al
 	jnz	.Lcleanthree
 	jnz	.Lcleanthree
 	testb	$8, %al
 	testb	$8, %al
@@ -321,6 +338,9 @@ doslot:
 .Lcleanthree:
 .Lcleanthree:
 	addw	$6, %sp
 	addw	$6, %sp
 	ret
 	ret
+.Lcleanfour:
+	addw	$8, %sp
+	ret
 
 
 # wrtinl's argument is NOT a stack word: the entry reads a length byte and that
 # wrtinl's argument is NOT a stack word: the entry reads a length byte and that
 # many characters from its own return address.  That is the caller's half of
 # many characters from its own return address.  That is the caller's half of
@@ -581,3 +601,19 @@ HDR:
 
 
 	.org	R_BLK36
 	.org	R_BLK36
 	.byte	0x8E, 0x00, 0x00, 0x00, 0xD0, 0x40, 0x81, 0x00, 0x00, 0x00, 0x00, 0x00
 	.byte	0x8E, 0x00, 0x00, 0x00, 0xD0, 0x40, 0x81, 0x00, 0x00, 0x00, 0x00, 0x00
+
+# Set buffers for set_op/set_cmp/set_copy.
+	.org	SETA
+	.byte	0x0A, 0x00, 0x00, 0x00
+	.org	SETB
+	.byte	0x18, 0x00, 0x00, 0x00
+	.org	SETC
+	.byte	0x02, 0x00, 0x00, 0x00
+	.org	SETD
+	.byte	0x00, 0x00, 0x00, 0x00
+	.org	SET2A
+	.byte	0x0A, 0x0F
+	.org	SET2B
+	.byte	0x18, 0x03
+	.org	SET2D
+	.byte	0x00, 0x00

+ 7 - 6
shell/tests/fixtures/calc_ladder.tsv

@@ -28,9 +28,10 @@
 # Current rung (2026-10-21): `Write(Value:FW:DEC)' in CALC.INC's GotoCell - a
 # Current rung (2026-10-21): `Write(Value:FW:DEC)' in CALC.INC's GotoCell - a
 # REAL write with a field width and decimals.  UpCase (t81_upcase), run-time
 # REAL write with a field width and decimals.  UpCase (t81_upcase), run-time
 # set membership (t82_setin) and a string field written through DI (t79
 # set membership (t82_setin) and a string field written through DI (t79
-# extended) moved the ladder 15911 -> 18267 -> 19847.  REAL output now works
-# (`Write(Value:FW:DEC)`, `Write(Value:FW)` and the default width), and a
-# string field may be compared before the right operand is parsed.  The blocker
-# is now run-time SET ARITHMETIC:
-#   until (Sheet[FX,FY].CellStatus * [OverWritten,Locked] = []) or ...;
-CALC.PAS	ERR	102	19847
+# extended) moved the ladder 15911 -> 18267 -> 19847 -> 20912.  Real output,
+# string comparisons, run-time set algebra (`*`, `+`, `-`, set comparisons and
+# set-expression assignment) and Succ/Pred now work.  The blocker is now the
+# LAYOUT limit: the compiler reserves a fixed 4 KiB code window above the
+# runtime, and CALC's own code has reached it (TP3's error 98, pos 20912).
+# That is the §3 layout change, not a missing construct.
+CALC.PAS	ERR	98	20912

+ 4 - 0
shell/tests/fixtures/expected.tsv

@@ -616,3 +616,7 @@ t82_setin	OK	1052	26
 #   and Write(real:width:decimals) with both formats driven by variables.
 #   and Write(real:width:decimals) with both formats driven by variables.
 t83_strfield_cmp	OK	159	29
 t83_strfield_cmp	OK	159	29
 t84_realwrite	OK	160	15
 t84_realwrite	OK	160	15
+
+#   t85/t86 are the run-time-set rung and the Succ/Pred builtins.
+t85_setops	OK	1355	17
+t86_succ	OK	115	8

+ 7 - 0
shell/tests/fixtures/t85_setops.out

@@ -0,0 +1,7 @@
+inter
+eq
+leftlit
+sup
+sub
+union
+diff

+ 23 - 0
shell/tests/fixtures/t85_setops.pas

@@ -0,0 +1,23 @@
+PROGRAM T85;
+TYPE
+   Attr = (A, B, C, D, E) ;
+   AttrSet = SET OF Attr ;
+   Rec = RECORD
+      Status : AttrSet ;
+   END ;
+VAR
+   M : ARRAY [1..2, 1..2] OF Rec ;
+   I, J : Integer ;
+BEGIN
+   I := 1 ; J := 1 ;
+   M [I,J].Status := [B,D] ;
+   IF M [I,J].Status * [C,D] = [D] THEN WRITELN ('inter') ELSE WRITELN ('bad1') ;
+   IF M [I,J].Status = [B,D] THEN WRITELN ('eq') ELSE WRITELN ('bad2') ;
+   IF [B,D] * M [I,J].Status = [B,D] THEN WRITELN ('leftlit') ELSE WRITELN ('bad3') ;
+   IF M [I,J].Status >= [B] THEN WRITELN ('sup') ELSE WRITELN ('bad4') ;
+   IF [B] <= M [I,J].Status THEN WRITELN ('sub') ELSE WRITELN ('bad5') ;
+   M [I,J].Status := M [I,J].Status + [C] ;
+   IF M [I,J].Status = [B,C,D] THEN WRITELN ('union') ELSE WRITELN ('bad6') ;
+   M [I,J].Status := M [I,J].Status - [B] ;
+   IF M [I,J].Status = [C,D] THEN WRITELN ('diff') ELSE WRITELN ('bad7')
+END.

+ 3 - 0
shell/tests/fixtures/t86_succ.out

@@ -0,0 +1,3 @@
+B
+4
+B

+ 14 - 0
shell/tests/fixtures/t86_succ.pas

@@ -0,0 +1,14 @@
+PROGRAM T86;
+VAR
+   C : Char ;
+   N : Integer ;
+BEGIN
+   C := 'A' ;
+   C := Succ (C) ;
+   WRITELN (C) ;
+   N := 5 ;
+   N := Pred (N) ;
+   WRITELN (N) ;
+   C := Pred (Succ (C)) ;
+   WRITELN (C)
+END.

+ 66 - 5
shell/tests/nonvacuity.sh

@@ -2268,11 +2268,11 @@ cp "$SAVED_C" Compiler.mod
 if python3 - <<'PYX'
 if python3 - <<'PYX'
 p = 'Compiler.mod'
 p = 'Compiler.mod'
 s = open(p).read()
 s = open(p).read()
-old = """      EmPushDi ()
-   ELSIF r.kind = 1 THEN"""
-assert s.count(old) == 1, 'the kind-5 string push found %d times' % s.count(old)
-open(p, 'w').write(s.replace(old, """      Err (ENoLib)
-   ELSIF r.kind = 1 THEN"""))
+old = """   IF r.kind = 5 THEN
+      (* a string element/field computed through DI - `Sheet[X,Y].Contents'"""
+assert s.count(old) == 1, 'the kind-5 string branch found %d times' % s.count(old)
+open(p, 'w').write(s.replace(old, """   IF r.kind = 4 THEN
+      (* a string element/field computed through DI - `Sheet[X,Y].Contents'"""))
 PYX
 PYX
 then
 then
     if rebuild_compiler; then
     if rebuild_compiler; then
@@ -2304,6 +2304,67 @@ fi
 cp "$SAVED" Runtime.mod
 cp "$SAVED" Runtime.mod
 "$GM2" -fiso -c Runtime.mod >/dev/null 2>&1
 "$GM2" -fiso -c Runtime.mod >/dev/null 2>&1
 
 
+# --- set_op's intersection really ANDs the two bytes ---------------------
+# 20 D0 is AND AL,DL; 20 C2 is AND DL,AL and leaves AL (the left byte), which
+# is exactly the bug this rung fixed.  The exact-byte set_op cases catch it.
+cp "$SAVED" Runtime.mod
+if mutate Runtime.mod 's|PROCEDURE AndAlDl ; BEGIN B (20H) ; B (0D0H)|PROCEDURE AndAlDl ; BEGIN B (20H) ; B (0C2H)|'; then
+    if "$GM2" -fiso -c Runtime.mod >/dev/null 2>&1; then
+        expect_red "set_op red when intersection uses the wrong AND operand" \
+            "set_op" python3 tests/rt_exec.py
+    else
+        echo "  FAIL: the runtime would not rebuild with the AND mutation"
+        fail=$((fail + 1))
+    fi
+fi
+cp "$SAVED" Runtime.mod
+"$GM2" -fiso -c Runtime.mod >/dev/null 2>&1
+
+# --- set union is OR, not intersection -----------------------------------
+# t85's `union' line is `Status := Status + [C]'; choosing intersection there
+# loses C (and the later difference line too).  This pins the compiler's
+# operator-to-runtime mapping, not just the runtime core.
+cp "$SAVED_C" Compiler.mod
+if mutate_compiler 's|               SetBinEmit (1, left, right, r)|               SetBinEmit (0, left, right, r)|'; then
+    if rebuild_compiler; then
+        expect_red "t85 red when set addition becomes intersection" \
+            "t85_setops" python3 tests/run_com_exec.py t85_setops
+    else
+        echo "  FAIL: the compiler would not rebuild with set + as *"
+        fail=$((fail + 1))
+    fi
+fi
+cp "$SAVED_C" Compiler.mod
+
+# --- Succ increments, Pred decrements ------------------------------------
+cp "$SAVED_C" Compiler.mod
+if python3 - <<'PYX'
+p = 'Compiler.mod'
+s = open(p).read()
+old = """         IF symtab [idx].cls = BI_Succ THEN
+            EmIncAx ()
+         ELSE
+            EmDecAx ()"""
+assert s.count(old) == 1, 'the Succ branch found %d times' % s.count(old)
+open(p, 'w').write(s.replace(old, """         IF symtab [idx].cls = BI_Succ THEN
+            EmDecAx ()
+         ELSE
+            EmDecAx ()"""))
+PYX
+then
+    if rebuild_compiler; then
+        expect_red "t86 red when Succ decrements" \
+            "t86_succ" python3 tests/run_com_exec.py t86_succ
+    else
+        echo "  FAIL: the compiler would not rebuild with Succ as Pred"
+        fail=$((fail + 1))
+    fi
+else
+    echo "  BROKEN CASE: the Succ mutation did not apply"
+    fail=$((fail + 1))
+fi
+cp "$SAVED_C" Compiler.mod
+
 if rebuild_compiler; then
 if rebuild_compiler; then
     if python3 tests/run_com_exec.py >/dev/null 2>&1; then
     if python3 tests/run_com_exec.py >/dev/null 2>&1; then
         echo "  ok: every executed fixture passes on the restored sources"
         echo "  ok: every executed fixture passes on the restored sources"

+ 48 - 10
shell/tests/rt_exec.py

@@ -110,7 +110,7 @@ ENTS = ["initmem", "progend", "stackchk", "wrint", "wrchar", "wrbool",
         "wrtinl", "rdbyte", "wrstr", "rdstr", "strstore", "cmpstr", "strcat",
         "wrtinl", "rdbyte", "wrstr", "rdstr", "strstore", "cmpstr", "strcat",
         "wrintw", "real_from_int", "real_add", "real_sub", "real_mul",
         "wrintw", "real_from_int", "real_add", "real_sub", "real_mul",
         "real_div", "real_cmp", "real_int", "real_fmt", "real_val",
         "real_div", "real_cmp", "real_int", "real_fmt", "real_val",
-        "real_write"]
+        "real_write", "set_op", "set_cmp", "set_copy"]
 
 
 # A call slot's flags, as rtdrv.s reads them.
 # A call slot's flags, as rtdrv.s reads them.
 F_STACK = 1     # the argument goes on the stack, popped by the caller
 F_STACK = 1     # the argument goes on the stack, popped by the caller
@@ -122,6 +122,7 @@ F_CX = 16       # CX := the word at +8, the maximum length rdstr and strstore
                 # both read from the register
                 # both read from the register
 F_STACK3 = 32   # three stack words: +8 first, then +6, then +2, so +2 is
 F_STACK3 = 32   # three stack words: +8 first, then +6, then +2, so +2 is
                 # [BP+4], +6 is [BP+6] and +8 is [BP+8]
                 # [BP+4], +6 is [BP+6] and +8 is [BP+8]
+F_STACK4 = 64   # four stack words: +10, +8, +6, +2 -> [BP+10]..[BP+4]
 
 
 # The byte patterns check_bp_contract looks for, and the rule they express:
 # The byte patterns check_bp_contract looks for, and the rule they express:
 # "an entry that borrows BP opens with PUSH BP; MOV BP,SP and pops it again
 # "an entry that borrows BP opens with PUSH BP; MOV BP,SP and pops it again
@@ -324,13 +325,14 @@ def case_bytes(c, entries):
         sys.exit("case %s has %d calls; the record holds 4"
         sys.exit("case %s has %d calls; the record holds 4"
                  % (c["name"], len(calls)))
                  % (c["name"], len(calls)))
     b[15] = len(calls)                                  # OFF_NCALLS (byte)
     b[15] = len(calls)                                  # OFF_NCALLS (byte)
-    for i, (ent, arg, mode, arg2, cx) in enumerate(calls):
+    for i, (ent, arg, mode, arg2, cx, arg3) in enumerate(calls):
         o = 16 + 12 * i                                 # SLOT0, SLOT_SZ = 12
         o = 16 + 12 * i                                 # SLOT0, SLOT_SZ = 12
         struct.pack_into("<H", b, o, entries[ent])
         struct.pack_into("<H", b, o, entries[ent])
         struct.pack_into("<H", b, o + 2, arg & 0xFFFF)
         struct.pack_into("<H", b, o + 2, arg & 0xFFFF)
         b[o + 4] = mode
         b[o + 4] = mode
         struct.pack_into("<H", b, o + 6, arg2 & 0xFFFF)
         struct.pack_into("<H", b, o + 6, arg2 & 0xFFFF)
         struct.pack_into("<H", b, o + 8, cx & 0xFFFF)
         struct.pack_into("<H", b, o + 8, cx & 0xFFFF)
+        struct.pack_into("<H", b, o + 10, arg3 & 0xFFFF)
     return bytes(b)
     return bytes(b)
 
 
 
 
@@ -435,36 +437,41 @@ def build_cases():
                    "note": note, "index": len(cs)})
                    "note": note, "index": len(cs)})
 
 
     def s(ent, arg):
     def s(ent, arg):
-        return (ent, arg, F_STACK, 0, 0)
+        return (ent, arg, F_STACK, 0, 0, 0)
 
 
     def x(ent, arg):
     def x(ent, arg):
-        return (ent, arg, F_AX, 0, 0)
+        return (ent, arg, F_AX, 0, 0, 0)
 
 
     def n(ent):
     def n(ent):
-        return (ent, 0, 0, 0, 0)
+        return (ent, 0, 0, 0, 0, 0)
 
 
     def i(ent):
     def i(ent):
-        return (ent, 0, F_INL, 0, 0)
+        return (ent, 0, F_INL, 0, 0, 0)
 
 
     def s2(ent, arg, arg2):
     def s2(ent, arg, arg2):
         """Two stack words: arg2 is pushed first (it lands at [BP+6]), arg
         """Two stack words: arg2 is pushed first (it lands at [BP+6]), arg
         second (at [BP+4]).  real_from_int(src, dst) takes its source first."""
         second (at [BP+4]).  real_from_int(src, dst) takes its source first."""
-        return (ent, arg, F_STACK | F_STACK2, arg2, 0)
+        return (ent, arg, F_STACK | F_STACK2, arg2, 0, 0)
 
 
     def s3(ent, a, b, c):
     def s3(ent, a, b, c):
         """Three stack words: c is pushed first (landing at [BP+8]), then b
         """Three stack words: c is pushed first (landing at [BP+8]), then b
         ([BP+6]), then a ([BP+4])."""
         ([BP+6]), then a ([BP+4])."""
-        return (ent, a, F_STACK | F_STACK3, b, c)
+        return (ent, a, F_STACK | F_STACK3, b, c, 0)
+
+    def s4(ent, a, b, c, d):
+        """Four stack words, d first: d=[BP+10], c=[BP+8], b=[BP+6],
+        a=[BP+4]."""
+        return (ent, a, F_STACK | F_STACK4, b, c, d)
 
 
     def s2cx(ent, arg, arg2, cx):
     def s2cx(ent, arg, arg2, cx):
         """Two stack words AND CX: arg2 is pushed first (it lands at [BP+6]),
         """Two stack words AND CX: arg2 is pushed first (it lands at [BP+6]),
         arg second (at [BP+4]), and CX carries the maximum length.  strstore is
         arg second (at [BP+4]), and CX carries the maximum length.  strstore is
         the only entry that wants all three."""
         the only entry that wants all three."""
-        return (ent, arg, F_STACK | F_STACK2 | F_CX, arg2, cx)
+        return (ent, arg, F_STACK | F_STACK2 | F_CX, arg2, cx, 0)
 
 
     def scx(ent, arg, cx):
     def scx(ent, arg, cx):
         """One stack word and CX, for rdstr: dest at [BP+4], limit in CX."""
         """One stack word and CX, for rdstr: dest at [BP+4], limit in CX."""
-        return (ent, arg, F_STACK | F_CX, 0, cx)
+        return (ent, arg, F_STACK | F_CX, 0, cx, 0)
 
 
     # initmem is handed the header in AX -- and the header's MEMORY address, not
     # initmem is handed the header in AX -- and the header's MEMORY address, not
     # its image offset.  Given the image offset it reads the two words it wants
     # its image offset.  Given the image offset it reads the two words it wants
@@ -688,6 +695,37 @@ def build_cases():
     wr("real_write(3.7:18:FFFF)", 0x1370, 18, 0xFFFF,
     wr("real_write(3.7:18:FFFF)", 0x1370, 18, 0xFFFF,
        b"  3.7000000000E+00")
        b"  3.7000000000E+00")
 
 
+    # --- set algebra ----------------------------------------------------
+    # set_op: [BP+4]=(op<<8)|size, [BP+6]=dest, [BP+8]=right, [BP+10]=left.
+    # 0 = intersection, 1 = union, 2 = difference.
+    def setop(name, op, size, dest, right, left, want):
+        add(name, [s4("set_op", (op << 8) | size, dest + LOAD_BIAS,
+                       right + LOAD_BIAS, left + LOAD_BIAS)],
+            dump=size, dumpbytes=want, dumpadr=dest,
+            note="the loops in EmitSetOps, exact bytes")
+    setop("set_op /", 0, 1, 0x15B0, 0x1590, 0x1580, b"\x08")
+    setop("set_op +", 1, 1, 0x15B0, 0x1590, 0x1580, b"\x1A")
+    setop("set_op -", 2, 1, 0x15B0, 0x1590, 0x1580, b"\x02")
+    setop("set_op / 2 bytes", 0, 2, 0x15E0, 0x15D0, 0x15C0, b"\x08\x03")
+
+    # set_cmp: [BP+4]=size, [BP+6]=right, [BP+8]=left; AX = equal bit 0,
+    # strict subset bit 1, strict superset bit 2.
+    def setcmp(name, size, left, right, mask):
+        add(name, [s3("set_cmp", size, right + LOAD_BIAS, left + LOAD_BIAS)],
+            dump=2, dumpbytes=struct.pack("<H", mask), dumpadr=AXOUT,
+            note="the reference mask: 1 equal, 2 subset, 4 superset")
+    setcmp("set_cmp size 0", 0, 0x1580, 0x1590, 1)
+    setcmp("set_cmp A=A", 1, 0x1580, 0x1580, 1)
+    setcmp("set_cmp A~B", 1, 0x1580, 0x1590, 0)
+    setcmp("set_cmp C<A", 1, 0x15A0, 0x1580, 2)
+    setcmp("set_cmp A>C", 1, 0x1580, 0x15A0, 4)
+    setcmp("set_cmp 2-byte incomparable", 2, 0x15C0, 0x15D0, 0)
+
+    add("set_copy 2 bytes",
+        [s3("set_copy", 2, 0x15C0 + LOAD_BIAS, 0x15E0 + LOAD_BIAS)],
+        dump=2, dumpbytes=b"\x0A\x0F", dumpadr=0x15E0,
+        note="[BP+4]=size, [BP+6]=src, [BP+8]=dest")
+
     add("wrchar('A')", [s("wrchar", ord("A"))], out=b"A")
     add("wrchar('A')", [s("wrchar", ord("A"))], out=b"A")
     add("wrchar('!')", [s("wrchar", ord("!"))], out=b"!")
     add("wrchar('!')", [s("wrchar", ord("!"))], out=b"!")
 
 

+ 200 - 94
shell/tests/runtime.golden

@@ -41,7 +41,7 @@
 0036  58          pop ax
 0036  58          pop ax
 0037  F7 D8       neg ax
 0037  F7 D8       neg ax
 0039  B9 0A 00    mov cx,0ah
 0039  B9 0A 00    mov cx,0ah
-003C  BB DC 0D    mov bx,0ddch
+003C  BB 98 0E    mov bx,0e98h
 003F  89 DE       mov si,bx
 003F  89 DE       mov si,bx
 0041  31 D2       xor dx,dx
 0041  31 D2       xor dx,dx
 0043  F7 F1       div ax,cx
 0043  F7 F1       div ax,cx
@@ -93,7 +93,7 @@
 00A2  58          pop ax
 00A2  58          pop ax
 00A3  F7 D8       neg ax
 00A3  F7 D8       neg ax
 00A5  B9 0A 00    mov cx,0ah
 00A5  B9 0A 00    mov cx,0ah
-00A8  BB DC 0D    mov bx,0ddch
+00A8  BB 98 0E    mov bx,0e98h
 00AB  89 DE       mov si,bx
 00AB  89 DE       mov si,bx
 00AD  31 D2       xor dx,dx
 00AD  31 D2       xor dx,dx
 00AF  F7 F1       div ax,cx
 00AF  F7 F1       div ax,cx
@@ -125,18 +125,18 @@
 00DE  83 7E 04 00 cmp word ptr [bp+4h],0h
 00DE  83 7E 04 00 cmp word ptr [bp+4h],0h
 00E2  89 EC       mov sp,bp
 00E2  89 EC       mov sp,bp
 00E4  75 05       jne 0ebh
 00E4  75 05       jne 0ebh
-00E6  BA E1 0D    mov dx,0de1h
+00E6  BA 9D 0E    mov dx,0e9dh
 00E9  EB 03       jmp 0eeh
 00E9  EB 03       jmp 0eeh
-00EB  BA DC 0D    mov dx,0ddch
+00EB  BA 98 0E    mov dx,0e98h
 00EE  B4 09       mov ah,9h
 00EE  B4 09       mov ah,9h
 00F0  CD 21       int 21h
 00F0  CD 21       int 21h
 00F2  5D          pop bp
 00F2  5D          pop bp
 00F3  C3          ret
 00F3  C3          ret
-00F4  BA EA 0D    mov dx,0deah
+00F4  BA A6 0E    mov dx,0ea6h
 00F7  B4 09       mov ah,9h
 00F7  B4 09       mov ah,9h
 00F9  CD 21       int 21h
 00F9  CD 21       int 21h
 00FB  C3          ret
 00FB  C3          ret
-00FC  BA E7 0D    mov dx,0de7h
+00FC  BA A3 0E    mov dx,0ea3h
 00FF  B4 09       mov ah,9h
 00FF  B4 09       mov ah,9h
 0101  CD 21       int 21h
 0101  CD 21       int 21h
 0103  C3          ret
 0103  C3          ret
@@ -303,12 +303,12 @@
 0217  EB EF       jmp 208h
 0217  EB EF       jmp 208h
 0219  58          pop ax
 0219  58          pop ax
 021A  C3          ret
 021A  C3          ret
-021B  8B 1E F0 0D mov bx,word ptr [0df0h]
+021B  8B 1E AC 0E mov bx,word ptr [0each]
 021F  83 FB 00    cmp bx,0h
 021F  83 FB 00    cmp bx,0h
 0222  74 09       je 22dh
 0222  74 09       je 22dh
 0224  8A C3       mov al,bl
 0224  8A C3       mov al,bl
 0226  31 DB       xor bx,bx
 0226  31 DB       xor bx,bx
-0228  89 1E F0 0D mov word ptr [0df0h],bx
+0228  89 1E AC 0E mov word ptr [0each],bx
 022C  C3          ret
 022C  C3          ret
 022D  B4 08       mov ah,8h
 022D  B4 08       mov ah,8h
 022F  CD 21       int 21h
 022F  CD 21       int 21h
@@ -316,7 +316,7 @@
 0232  88 C2       mov dl,al
 0232  88 C2       mov dl,al
 0234  BB 01 00    mov bx,1h
 0234  BB 01 00    mov bx,1h
 0237  8A DA       mov bl,dl
 0237  8A DA       mov bl,dl
-0239  89 1E F0 0D mov word ptr [0df0h],bx
+0239  89 1E AC 0E mov word ptr [0each],bx
 023D  C3          ret
 023D  C3          ret
 023E  55          push bp
 023E  55          push bp
 023F  8B EC       mov bp,sp
 023F  8B EC       mov bp,sp
@@ -543,7 +543,7 @@
 03C2  8B 4D 06    mov cx,word ptr [di+6h]
 03C2  8B 4D 06    mov cx,word ptr [di+6h]
 03C5  8B 75 08    mov si,word ptr [di+8h]
 03C5  8B 75 08    mov si,word ptr [di+8h]
 03C8  8B 7D 0A    mov di,word ptr [di+0ah]
 03C8  8B 7D 0A    mov di,word ptr [di+0ah]
-03CB  C7 06 F2 0D 00 00 mov word ptr [0df2h],0h
+03CB  C7 06 AE 0E 00 00 mov word ptr [0eaeh],0h
 03D1  E8 4D 00    call 421h
 03D1  E8 4D 00    call 421h
 03D4  5F          pop di
 03D4  5F          pop di
 03D5  89 05       mov word ptr [di],ax
 03D5  89 05       mov word ptr [di],ax
@@ -572,7 +572,7 @@
 03FE  8B 4D 06    mov cx,word ptr [di+6h]
 03FE  8B 4D 06    mov cx,word ptr [di+6h]
 0401  8B 75 08    mov si,word ptr [di+8h]
 0401  8B 75 08    mov si,word ptr [di+8h]
 0404  8B 7D 0A    mov di,word ptr [di+0ah]
 0404  8B 7D 0A    mov di,word ptr [di+0ah]
-0407  C7 06 F2 0D 00 80 mov word ptr [0df2h],8000h
+0407  C7 06 AE 0E 00 80 mov word ptr [0eaeh],8000h
 040D  E8 11 00    call 421h
 040D  E8 11 00    call 421h
 0410  5F          pop di
 0410  5F          pop di
 0411  89 05       mov word ptr [di],ax
 0411  89 05       mov word ptr [di],ax
@@ -587,7 +587,7 @@
 0420  C3          ret
 0420  C3          ret
 0421  80 F9 00    cmp cl,0h
 0421  80 F9 00    cmp cl,0h
 0424  74 0E       je 434h
 0424  74 0E       je 434h
-0426  33 3E F2 0D xor di,word ptr [0df2h]
+0426  33 3E AE 0E xor di,word ptr [0eaeh]
 042A  3C 00       cmp al,0h
 042A  3C 00       cmp al,0h
 042C  75 07       jne 435h
 042C  75 07       jne 435h
 042E  89 C8       mov ax,cx
 042E  89 C8       mov ax,cx
@@ -599,16 +599,16 @@
 0439  91          xchg ax,cx
 0439  91          xchg ax,cx
 043A  87 F3       xchg bx,si
 043A  87 F3       xchg bx,si
 043C  87 FA       xchg dx,di
 043C  87 FA       xchg dx,di
-043E  88 0E F6 0D mov byte ptr [0df6h],cl
+043E  88 0E B2 0E mov byte ptr [0eb2h],cl
 0442  28 C1       sub cl,al
 0442  28 C1       sub cl,al
 0444  80 F9 28    cmp cl,28h
 0444  80 F9 28    cmp cl,28h
 0447  72 06       jb 44fh
 0447  72 06       jb 44fh
-0449  8A 0E F6 0D mov cl,byte ptr [0df6h]
+0449  8A 0E B2 0E mov cl,byte ptr [0eb2h]
 044D  EB DF       jmp 42eh
 044D  EB DF       jmp 42eh
-044F  89 3E F2 0D mov word ptr [0df2h],di
-0453  80 26 F3 0D 80 and byte ptr [0df3h],80h
-0458  89 3E F4 0D mov word ptr [0df4h],di
-045C  30 36 F5 0D xor byte ptr [0df5h],dh
+044F  89 3E AE 0E mov word ptr [0eaeh],di
+0453  80 26 AF 0E 80 and byte ptr [0eafh],80h
+0458  89 3E B0 0E mov word ptr [0eb0h],di
+045C  30 36 B1 0E xor byte ptr [0eb1h],dh
 0460  81 CF 00 80 or di,8000h
 0460  81 CF 00 80 or di,8000h
 0464  80 CE 80    or dh,80h
 0464  80 CE 80    or dh,80h
 0467  80 F9 10    cmp cl,10h
 0467  80 F9 10    cmp cl,10h
@@ -633,8 +633,8 @@
 0492  D0 DC       rcr ah,1h
 0492  D0 DC       rcr ah,1h
 0494  FE C9       dec cl
 0494  FE C9       dec cl
 0496  75 F6       jne 48eh
 0496  75 F6       jne 48eh
-0498  A0 F6 0D    mov al,byte ptr [0df6h]
-049B  F6 06 F5 0D 80 test byte ptr [0df5h],80h
+0498  A0 B2 0E    mov al,byte ptr [0eb2h]
+049B  F6 06 B1 0E 80 test byte ptr [0eb1h],80h
 04A0  75 14       jne 4b6h
 04A0  75 14       jne 4b6h
 04A2  00 EC       add ah,ch
 04A2  00 EC       add ah,ch
 04A4  11 F3       adc bx,si
 04A4  11 F3       adc bx,si
@@ -654,7 +654,7 @@
 04BE  19 F3       sbb bx,si
 04BE  19 F3       sbb bx,si
 04C0  19 FA       sbb dx,di
 04C0  19 FA       sbb dx,di
 04C2  73 14       jnb 4d8h
 04C2  73 14       jnb 4d8h
-04C4  80 36 F3 0D 80 xor byte ptr [0df3h],80h
+04C4  80 36 AF 0E 80 xor byte ptr [0eafh],80h
 04C9  F6 D4       not ah
 04C9  F6 D4       not ah
 04CB  F7 D3       not bx
 04CB  F7 D3       not bx
 04CD  F7 D2       not dx
 04CD  F7 D2       not dx
@@ -686,7 +686,7 @@
 0506  31 D2       xor dx,dx
 0506  31 D2       xor dx,dx
 0508  C3          ret
 0508  C3          ret
 0509  80 E6 7F    and dh,7fh
 0509  80 E6 7F    and dh,7fh
-050C  32 36 F3 0D xor dh,byte ptr [0df3h]
+050C  32 36 AF 0E xor dh,byte ptr [0eafh]
 0510  C3          ret
 0510  C3          ret
 0511  55          push bp
 0511  55          push bp
 0512  8B EC       mov bp,sp
 0512  8B EC       mov bp,sp
@@ -732,23 +732,23 @@
 0565  B0 01       mov al,1h
 0565  B0 01       mov al,1h
 0567  B4 4C       mov ah,4ch
 0567  B4 4C       mov ah,4ch
 0569  CD 21       int 21h
 0569  CD 21       int 21h
-056B  89 0E FD 0D mov word ptr [0dfdh],cx
+056B  89 0E B9 0E mov word ptr [0eb9h],cx
 056F  8B CA       mov cx,dx
 056F  8B CA       mov cx,dx
 0571  31 F9       xor cx,di
 0571  31 F9       xor cx,di
 0573  F6 D5       not ch
 0573  F6 D5       not ch
 0575  80 E5 80    and ch,80h
 0575  80 E5 80    and ch,80h
-0578  88 2E F3 0D mov byte ptr [0df3h],ch
+0578  88 2E AF 0E mov byte ptr [0eafh],ch
 057C  80 CE 80    or dh,80h
 057C  80 CE 80    or dh,80h
 057F  81 CF 00 80 or di,8000h
 057F  81 CF 00 80 or di,8000h
-0583  89 36 FF 0D mov word ptr [0dffh],si
-0587  89 3E 01 0E mov word ptr [0e01h],di
-058B  A3 F7 0D    mov word ptr [0df7h],ax
-058E  89 1E F9 0D mov word ptr [0df9h],bx
-0592  89 16 FB 0D mov word ptr [0dfbh],dx
+0583  89 36 BB 0E mov word ptr [0ebbh],si
+0587  89 3E BD 0E mov word ptr [0ebdh],di
+058B  A3 B3 0E    mov word ptr [0eb3h],ax
+058E  89 1E B5 0E mov word ptr [0eb5h],bx
+0592  89 16 B7 0E mov word ptr [0eb7h],dx
 0596  30 E4       xor ah,ah
 0596  30 E4       xor ah,ah
 0598  31 DB       xor bx,bx
 0598  31 DB       xor bx,bx
 059A  31 D2       xor dx,dx
 059A  31 D2       xor dx,dx
-059C  BF FD 0D    mov di,0dfdh
+059C  BF B9 0E    mov di,0eb9h
 059F  B1 05       mov cl,5h
 059F  B1 05       mov cl,5h
 05A1  47          inc di
 05A1  47          inc di
 05A2  8A 2D       mov ch,byte ptr [di]
 05A2  8A 2D       mov ch,byte ptr [di]
@@ -763,9 +763,9 @@
 05B5  BE 08 00    mov si,8h
 05B5  BE 08 00    mov si,8h
 05B8  D0 DD       rcr ch,1h
 05B8  D0 DD       rcr ch,1h
 05BA  73 0C       jnb 5c8h
 05BA  73 0C       jnb 5c8h
-05BC  02 26 F8 0D add ah,byte ptr [0df8h]
-05C0  13 1E F9 0D adc bx,word ptr [0df9h]
-05C4  13 16 FB 0D adc dx,word ptr [0dfbh]
+05BC  02 26 B4 0E add ah,byte ptr [0eb4h]
+05C0  13 1E B5 0E adc bx,word ptr [0eb5h]
+05C4  13 16 B7 0E adc dx,word ptr [0eb7h]
 05C8  D1 DA       rcr dx,1h
 05C8  D1 DA       rcr dx,1h
 05CA  D1 DB       rcr bx,1h
 05CA  D1 DB       rcr bx,1h
 05CC  D0 DC       rcr ah,1h
 05CC  D0 DC       rcr ah,1h
@@ -785,7 +785,7 @@
 05E6  74 02       je 5eah
 05E6  74 02       je 5eah
 05E8  FE C9       dec cl
 05E8  FE C9       dec cl
 05EA  91          xchg ax,cx
 05EA  91          xchg ax,cx
-05EB  32 36 F3 0D xor dh,byte ptr [0df3h]
+05EB  32 36 AF 0E xor dh,byte ptr [0eafh]
 05EF  3C 00       cmp al,0h
 05EF  3C 00       cmp al,0h
 05F1  75 06       jne 5f9h
 05F1  75 06       jne 5f9h
 05F3  31 C0       xor ax,ax
 05F3  31 C0       xor ax,ax
@@ -834,29 +834,29 @@
 0647  B0 01       mov al,1h
 0647  B0 01       mov al,1h
 0649  B4 4C       mov ah,4ch
 0649  B4 4C       mov ah,4ch
 064B  CD 21       int 21h
 064B  CD 21       int 21h
-064D  89 0E FD 0D mov word ptr [0dfdh],cx
+064D  89 0E B9 0E mov word ptr [0eb9h],cx
 0651  8B CA       mov cx,dx
 0651  8B CA       mov cx,dx
 0653  31 F9       xor cx,di
 0653  31 F9       xor cx,di
 0655  F6 D5       not ch
 0655  F6 D5       not ch
 0657  80 E5 80    and ch,80h
 0657  80 E5 80    and ch,80h
-065A  88 2E F3 0D mov byte ptr [0df3h],ch
+065A  88 2E AF 0E mov byte ptr [0eafh],ch
 065E  80 CE 80    or dh,80h
 065E  80 CE 80    or dh,80h
 0661  81 CF 00 80 or di,8000h
 0661  81 CF 00 80 or di,8000h
-0665  89 36 FF 0D mov word ptr [0dffh],si
-0669  89 3E 01 0E mov word ptr [0e01h],di
-066D  A2 F7 0D    mov byte ptr [0df7h],al
-0670  BF FC 0D    mov di,0dfch
+0665  89 36 BB 0E mov word ptr [0ebbh],si
+0669  89 3E BD 0E mov word ptr [0ebdh],di
+066D  A2 B3 0E    mov byte ptr [0eb3h],al
+0670  BF B8 0E    mov di,0eb8h
 0673  B1 05       mov cl,5h
 0673  B1 05       mov cl,5h
 0675  BE 08 00    mov si,8h
 0675  BE 08 00    mov si,8h
-0678  3B 16 01 0E cmp dx,word ptr [0e01h]
+0678  3B 16 BD 0E cmp dx,word ptr [0ebdh]
 067C  75 0A       jne 688h
 067C  75 0A       jne 688h
-067E  3B 1E FF 0D cmp bx,word ptr [0dffh]
+067E  3B 1E BB 0E cmp bx,word ptr [0ebbh]
 0682  75 04       jne 688h
 0682  75 04       jne 688h
-0684  3A 26 FE 0D cmp ah,byte ptr [0dfeh]
+0684  3A 26 BA 0E cmp ah,byte ptr [0ebah]
 0688  72 0C       jb 696h
 0688  72 0C       jb 696h
-068A  2A 26 FE 0D sub ah,byte ptr [0dfeh]
-068E  1B 1E FF 0D sbb bx,word ptr [0dffh]
-0692  1B 16 01 0E sbb dx,word ptr [0e01h]
+068A  2A 26 BA 0E sub ah,byte ptr [0ebah]
+068E  1B 1E BB 0E sbb bx,word ptr [0ebbh]
+0692  1B 16 BD 0E sbb dx,word ptr [0ebdh]
 0696  F5          cmc
 0696  F5          cmc
 0697  D0 D5       rcl ch,1h
 0697  D0 D5       rcl ch,1h
 0699  4E          dec si
 0699  4E          dec si
@@ -870,24 +870,24 @@
 06A8  D1 D3       rcl bx,1h
 06A8  D1 D3       rcl bx,1h
 06AA  D1 D2       rcl dx,1h
 06AA  D1 D2       rcl dx,1h
 06AC  73 CA       jnb 678h
 06AC  73 CA       jnb 678h
-06AE  2A 26 FE 0D sub ah,byte ptr [0dfeh]
-06B2  1B 1E FF 0D sbb bx,word ptr [0dffh]
-06B6  1B 16 01 0E sbb dx,word ptr [0e01h]
+06AE  2A 26 BA 0E sub ah,byte ptr [0ebah]
+06B2  1B 1E BB 0E sbb bx,word ptr [0ebbh]
+06B6  1B 16 BD 0E sbb dx,word ptr [0ebdh]
 06BA  F8          clc
 06BA  F8          clc
 06BB  EB D9       jmp 696h
 06BB  EB D9       jmp 696h
 06BD  D0 E4       shl ah,1h
 06BD  D0 E4       shl ah,1h
 06BF  D1 D3       rcl bx,1h
 06BF  D1 D3       rcl bx,1h
 06C1  D1 D2       rcl dx,1h
 06C1  D1 D2       rcl dx,1h
 06C3  72 11       jb 6d6h
 06C3  72 11       jb 6d6h
-06C5  3B 16 01 0E cmp dx,word ptr [0e01h]
+06C5  3B 16 BD 0E cmp dx,word ptr [0ebdh]
 06C9  75 0A       jne 6d5h
 06C9  75 0A       jne 6d5h
-06CB  3B 1E FF 0D cmp bx,word ptr [0dffh]
+06CB  3B 1E BB 0E cmp bx,word ptr [0ebbh]
 06CF  75 04       jne 6d5h
 06CF  75 04       jne 6d5h
-06D1  3A 26 FE 0D cmp ah,byte ptr [0dfeh]
+06D1  3A 26 BA 0E cmp ah,byte ptr [0ebah]
 06D5  F5          cmc
 06D5  F5          cmc
-06D6  8B 0E F7 0D mov cx,word ptr [0df7h]
-06DA  8B 1E F9 0D mov bx,word ptr [0df9h]
-06DE  8B 16 FB 0D mov dx,word ptr [0dfbh]
+06D6  8B 0E B3 0E mov cx,word ptr [0eb3h]
+06DA  8B 1E B5 0E mov bx,word ptr [0eb5h]
+06DE  8B 16 B7 0E mov dx,word ptr [0eb7h]
 06E2  9F          lahf
 06E2  9F          lahf
 06E3  F6 C6 80    test dh,80h
 06E3  F6 C6 80    test dh,80h
 06E6  75 09       jne 6f1h
 06E6  75 09       jne 6f1h
@@ -1030,47 +1030,47 @@
 07EC  B5 00       mov ch,0h
 07EC  B5 00       mov ch,0h
 07EE  B6 00       mov dh,0h
 07EE  B6 00       mov dh,0h
 07F0  51          push cx
 07F0  51          push cx
-07F1  BB 4D 0E    mov bx,0e4dh
+07F1  BB 09 0F    mov bx,0f09h
 07F4  E8 41 02    call 0a38h
 07F4  E8 41 02    call 0a38h
 07F7  59          pop cx
 07F7  59          pop cx
 07F8  89 D8       mov ax,bx
 07F8  89 D8       mov ax,bx
-07FA  BB 4D 0E    mov bx,0e4dh
+07FA  BB 09 0F    mov bx,0f09h
 07FD  2B C3       sub ax,bx
 07FD  2B C3       sub ax,bx
-07FF  A3 8D 0E    mov word ptr [0e8dh],ax
-0802  89 0E 8F 0E mov word ptr [0e8fh],cx
-0806  8B 06 8F 0E mov ax,word ptr [0e8fh]
-080A  8B 16 8D 0E mov dx,word ptr [0e8dh]
+07FF  A3 49 0F    mov word ptr [0f49h],ax
+0802  89 0E 4B 0F mov word ptr [0f4bh],cx
+0806  8B 06 4B 0F mov ax,word ptr [0f4bh]
+080A  8B 16 49 0F mov dx,word ptr [0f49h]
 080E  2B C2       sub ax,dx
 080E  2B C2       sub ax,dx
 0810  83 F8 00    cmp ax,0h
 0810  83 F8 00    cmp ax,0h
 0813  7D 02       jnl 817h
 0813  7D 02       jnl 817h
 0815  31 C0       xor ax,ax
 0815  31 C0       xor ax,ax
-0817  A3 91 0E    mov word ptr [0e91h],ax
-081A  8B 16 8D 0E mov dx,word ptr [0e8dh]
+0817  A3 4D 0F    mov word ptr [0f4dh],ax
+081A  8B 16 49 0F mov dx,word ptr [0f49h]
 081E  03 C2       add ax,dx
 081E  03 C2       add ax,dx
 0820  3D FF 00    cmp ax,0ffh
 0820  3D FF 00    cmp ax,0ffh
 0823  77 03       jnbe 828h
 0823  77 03       jnbe 828h
 0825  E9 03 00    jmp 82bh
 0825  E9 03 00    jmp 82bh
 0828  B8 FF 00    mov ax,0ffh
 0828  B8 FF 00    mov ax,0ffh
-082B  A3 93 0E    mov word ptr [0e93h],ax
+082B  A3 4F 0F    mov word ptr [0f4fh],ax
 082E  8B 56 06    mov dx,word ptr [bp+6h]
 082E  8B 56 06    mov dx,word ptr [bp+6h]
 0831  89 D7       mov di,dx
 0831  89 D7       mov di,dx
 0833  88 05       mov byte ptr [di],al
 0833  88 05       mov byte ptr [di],al
 0835  47          inc di
 0835  47          inc di
-0836  8B 0E 91 0E mov cx,word ptr [0e91h]
+0836  8B 0E 4D 0F mov cx,word ptr [0f4dh]
 083A  E3 07       jcxz 843h
 083A  E3 07       jcxz 843h
 083C  B0 20       mov al,20h
 083C  B0 20       mov al,20h
 083E  88 05       mov byte ptr [di],al
 083E  88 05       mov byte ptr [di],al
 0840  47          inc di
 0840  47          inc di
 0841  E2 F9       loop 83ch
 0841  E2 F9       loop 83ch
-0843  BE 4D 0E    mov si,0e4dh
-0846  8B 0E 8D 0E mov cx,word ptr [0e8dh]
+0843  BE 09 0F    mov si,0f09h
+0846  8B 0E 49 0F mov cx,word ptr [0f49h]
 084A  E3 08       jcxz 854h
 084A  E3 08       jcxz 854h
 084C  8A 04       mov al,byte ptr [si]
 084C  8A 04       mov al,byte ptr [si]
 084E  88 05       mov byte ptr [di],al
 084E  88 05       mov byte ptr [di],al
 0850  46          inc si
 0850  46          inc si
 0851  47          inc di
 0851  47          inc di
 0852  E2 F8       loop 84ch
 0852  E2 F8       loop 84ch
-0854  8B 06 93 0E mov ax,word ptr [0e93h]
+0854  8B 06 4F 0F mov ax,word ptr [0f4fh]
 0858  5F          pop di
 0858  5F          pop di
 0859  5E          pop si
 0859  5E          pop si
 085A  5A          pop dx
 085A  5A          pop dx
@@ -1086,12 +1086,12 @@
 0866  57          push di
 0866  57          push di
 0867  8B 5E 04    mov bx,word ptr [bp+4h]
 0867  8B 5E 04    mov bx,word ptr [bp+4h]
 086A  8B 7E 06    mov di,word ptr [bp+6h]
 086A  8B 7E 06    mov di,word ptr [bp+6h]
-086D  89 1E 95 0E mov word ptr [0e95h],bx
+086D  89 1E 51 0F mov word ptr [0f51h],bx
 0871  E8 CF 02    call 0b43h
 0871  E8 CF 02    call 0b43h
 0874  73 03       jnb 879h
 0874  73 03       jnb 879h
 0876  E9 0B 00    jmp 884h
 0876  E9 0B 00    jmp 884h
 0879  89 D8       mov ax,bx
 0879  89 D8       mov ax,bx
-087B  8B 16 95 0E mov dx,word ptr [0e95h]
+087B  8B 16 51 0F mov dx,word ptr [0f51h]
 087F  2B C2       sub ax,dx
 087F  2B C2       sub ax,dx
 0881  E9 03 00    jmp 887h
 0881  E9 03 00    jmp 887h
 0884  B8 FF FF    mov ax,0ffffh
 0884  B8 FF FF    mov ax,0ffffh
@@ -1140,7 +1140,7 @@
 08CE  52          push dx
 08CE  52          push dx
 08CF  53          push bx
 08CF  53          push bx
 08D0  50          push ax
 08D0  50          push ax
-08D1  88 0E 0F 0E mov byte ptr [0e0fh],cl
+08D1  88 0E CB 0E mov byte ptr [0ecbh],cl
 08D5  80 F9 00    cmp cl,0h
 08D5  80 F9 00    cmp cl,0h
 08D8  78 03       js 8ddh
 08D8  78 03       js 8ddh
 08DA  E9 02 00    jmp 8dfh
 08DA  E9 02 00    jmp 8dfh
@@ -1151,7 +1151,7 @@
 08E6  D0 EB       shr bl,1h
 08E6  D0 EB       shr bl,1h
 08E8  00 FB       add bl,bh
 08E8  00 FB       add bl,bh
 08EA  30 FF       xor bh,bh
 08EA  30 FF       xor bh,bh
-08EC  8D BF 11 0E lea di,[bx+0e11h]
+08EC  8D BF CD 0E lea di,[bx+0ecdh]
 08F0  8B 05       mov ax,word ptr [di]
 08F0  8B 05       mov ax,word ptr [di]
 08F2  8B 5D 02    mov bx,word ptr [di+2h]
 08F2  8B 5D 02    mov bx,word ptr [di+2h]
 08F5  8B 55 04    mov dx,word ptr [di+4h]
 08F5  8B 55 04    mov dx,word ptr [di+4h]
@@ -1168,7 +1168,7 @@
 0910  58          pop ax
 0910  58          pop ax
 0911  5B          pop bx
 0911  5B          pop bx
 0912  5A          pop dx
 0912  5A          pop dx
-0913  F6 06 0F 0E 80 test byte ptr [0e0fh],80h
+0913  F6 06 CB 0E 80 test byte ptr [0ecbh],80h
 0918  74 03       je 91dh
 0918  74 03       je 91dh
 091A  E9 03 00    jmp 920h
 091A  E9 03 00    jmp 920h
 091D  E9 27 FC    jmp 547h
 091D  E9 27 FC    jmp 547h
@@ -1195,11 +1195,11 @@
 0947  3C 00       cmp al,0h
 0947  3C 00       cmp al,0h
 0949  74 03       je 94eh
 0949  74 03       je 94eh
 094B  E9 16 00    jmp 964h
 094B  E9 16 00    jmp 964h
-094E  BE 03 0E    mov si,0e03h
+094E  BE BF 0E    mov si,0ebfh
 0951  C7 04 30 30 mov word ptr [si],3030h
 0951  C7 04 30 30 mov word ptr [si],3030h
 0955  46          inc si
 0955  46          inc si
 0956  46          inc si
 0956  46          inc si
-0957  81 FE 0F 0E cmp si,0e0fh
+0957  81 FE CB 0E cmp si,0ecbh
 095B  74 03       je 960h
 095B  74 03       je 960h
 095D  E9 F1 FF    jmp 951h
 095D  E9 F1 FF    jmp 951h
 0960  B9 00 00    mov cx,0h
 0960  B9 00 00    mov cx,0h
@@ -1243,7 +1243,7 @@
 09AF  FE C9       dec cl
 09AF  FE C9       dec cl
 09B1  74 03       je 9b6h
 09B1  74 03       je 9b6h
 09B3  E9 F3 FF    jmp 9a9h
 09B3  E9 F3 FF    jmp 9a9h
-09B6  BE 03 0E    mov si,0e03h
+09B6  BE BF 0E    mov si,0ebfh
 09B9  88 F5       mov ch,dh
 09B9  88 F5       mov ch,dh
 09BB  B1 04       mov cl,4h
 09BB  B1 04       mov cl,4h
 09BD  D2 ED       shr ch,cl
 09BD  D2 ED       shr ch,cl
@@ -1269,13 +1269,13 @@
 09E1  D1 D3       rcl bx,1h
 09E1  D1 D3       rcl bx,1h
 09E3  D1 D2       rcl dx,1h
 09E3  D1 D2       rcl dx,1h
 09E5  46          inc si
 09E5  46          inc si
-09E6  81 FE 0F 0E cmp si,0e0fh
+09E6  81 FE CB 0E cmp si,0ecbh
 09EA  74 03       je 9efh
 09EA  74 03       je 9efh
 09EC  E9 CA FF    jmp 9b9h
 09EC  E9 CA FF    jmp 9b9h
 09EF  59          pop cx
 09EF  59          pop cx
 09F0  C3          ret
 09F0  C3          ret
 09F1  30 E4       xor ah,ah
 09F1  30 E4       xor ah,ah
-09F3  BB 03 0E    mov bx,0e03h
+09F3  BB BF 0E    mov bx,0ebfh
 09F6  03 D8       add bx,ax
 09F6  03 D8       add bx,ax
 09F8  80 3F 35    cmp byte ptr [bx],35h
 09F8  80 3F 35    cmp byte ptr [bx],35h
 09FB  C6 07 00    mov byte ptr [bx],0h
 09FB  C6 07 00    mov byte ptr [bx],0h
@@ -1346,7 +1346,7 @@
 0A92  00 C8       add al,cl
 0A92  00 C8       add al,cl
 0A94  78 03       js 0a99h
 0A94  78 03       js 0a99h
 0A96  E9 08 00    jmp 0aa1h
 0A96  E9 08 00    jmp 0aa1h
-0A99  C6 06 03 0E 00 mov byte ptr [0e03h],0h
+0A99  C6 06 BF 0E 00 mov byte ptr [0ebfh],0h
 0A9E  E9 0C 00    jmp 0aadh
 0A9E  E9 0C 00    jmp 0aadh
 0AA1  3C 0C       cmp al,0ch
 0AA1  3C 0C       cmp al,0ch
 0AA3  73 03       jnb 0aa8h
 0AA3  73 03       jnb 0aa8h
@@ -1354,7 +1354,7 @@
 0AA8  B0 0B       mov al,0bh
 0AA8  B0 0B       mov al,0bh
 0AAA  E8 44 FF    call 9f1h
 0AAA  E8 44 FF    call 9f1h
 0AAD  5B          pop bx
 0AAD  5B          pop bx
-0AAE  BE 03 0E    mov si,0e03h
+0AAE  BE BF 0E    mov si,0ebfh
 0AB1  F6 C5 80    test ch,80h
 0AB1  F6 C5 80    test ch,80h
 0AB4  75 03       jne 0ab9h
 0AB4  75 03       jne 0ab9h
 0AB6  E9 05 00    jmp 0abeh
 0AB6  E9 05 00    jmp 0abeh
@@ -1440,7 +1440,7 @@
 0B75  31 DB       xor bx,bx
 0B75  31 DB       xor bx,bx
 0B77  31 D2       xor dx,dx
 0B77  31 D2       xor dx,dx
 0B79  31 C9       xor cx,cx
 0B79  31 C9       xor cx,cx
-0B7B  C6 06 10 0E 00 mov byte ptr [0e10h],0h
+0B7B  C6 06 CC 0E 00 mov byte ptr [0ecch],0h
 0B80  8A 0C       mov cl,byte ptr [si]
 0B80  8A 0C       mov cl,byte ptr [si]
 0B82  80 F9 61    cmp cl,61h
 0B82  80 F9 61    cmp cl,61h
 0B85  73 03       jnb 0b8ah
 0B85  73 03       jnb 0b8ah
@@ -1469,7 +1469,7 @@
 0BB5  58          pop ax
 0BB5  58          pop ax
 0BB6  5B          pop bx
 0BB6  5B          pop bx
 0BB7  5A          pop dx
 0BB7  5A          pop dx
-0BB8  C7 06 F2 0D 00 00 mov word ptr [0df2h],0h
+0BB8  C7 06 AE 0E 00 00 mov word ptr [0eaeh],0h
 0BBE  E8 60 F8    call 421h
 0BBE  E8 60 F8    call 421h
 0BC1  59          pop cx
 0BC1  59          pop cx
 0BC2  5E          pop si
 0BC2  5E          pop si
@@ -1477,7 +1477,7 @@
 0BC4  F6 C5 40    test ch,40h
 0BC4  F6 C5 40    test ch,40h
 0BC7  75 03       jne 0bcch
 0BC7  75 03       jne 0bcch
 0BC9  E9 04 00    jmp 0bd0h
 0BC9  E9 04 00    jmp 0bd0h
-0BCC  FE 0E 10 0E dec byte ptr [0e10h]
+0BCC  FE 0E CC 0E dec byte ptr [0ecch]
 0BD0  46          inc si
 0BD0  46          inc si
 0BD1  E9 AC FF    jmp 0b80h
 0BD1  E9 AC FF    jmp 0b80h
 0BD4  80 F9 2E    cmp cl,2eh
 0BD4  80 F9 2E    cmp cl,2eh
@@ -1489,7 +1489,7 @@
 0BE4  80 CD 40    or ch,40h
 0BE4  80 CD 40    or ch,40h
 0BE7  E9 E6 FF    jmp 0bd0h
 0BE7  E9 E6 FF    jmp 0bd0h
 0BEA  80 F9 45    cmp cl,45h
 0BEA  80 F9 45    cmp cl,45h
-0BED  8A 0E 10 0E mov cl,byte ptr [0e10h]
+0BED  8A 0E CC 0E mov cl,byte ptr [0ecch]
 0BF1  74 03       je 0bf6h
 0BF1  74 03       je 0bf6h
 0BF3  E9 4D 00    jmp 0c43h
 0BF3  E9 4D 00    jmp 0c43h
 0BF6  E8 2A FD    call 923h
 0BF6  E8 2A FD    call 923h
@@ -1555,31 +1555,31 @@
 0C77  56          push si
 0C77  56          push si
 0C78  57          push di
 0C78  57          push di
 0C79  8B 46 06    mov ax,word ptr [bp+6h]
 0C79  8B 46 06    mov ax,word ptr [bp+6h]
-0C7C  A3 8F 0E    mov word ptr [0e8fh],ax
+0C7C  A3 4B 0F    mov word ptr [0f4bh],ax
 0C7F  8B 56 04    mov dx,word ptr [bp+4h]
 0C7F  8B 56 04    mov dx,word ptr [bp+4h]
 0C82  8B 4E 06    mov cx,word ptr [bp+6h]
 0C82  8B 4E 06    mov cx,word ptr [bp+6h]
 0C85  8B 7E 08    mov di,word ptr [bp+8h]
 0C85  8B 7E 08    mov di,word ptr [bp+8h]
-0C88  BB 4D 0E    mov bx,0e4dh
+0C88  BB 09 0F    mov bx,0f09h
 0C8B  E8 AA FD    call 0a38h
 0C8B  E8 AA FD    call 0a38h
 0C8E  89 D8       mov ax,bx
 0C8E  89 D8       mov ax,bx
-0C90  BB 4D 0E    mov bx,0e4dh
+0C90  BB 09 0F    mov bx,0f09h
 0C93  2B C3       sub ax,bx
 0C93  2B C3       sub ax,bx
-0C95  A3 8D 0E    mov word ptr [0e8dh],ax
-0C98  8B 06 8F 0E mov ax,word ptr [0e8fh]
-0C9C  8B 16 8D 0E mov dx,word ptr [0e8dh]
+0C95  A3 49 0F    mov word ptr [0f49h],ax
+0C98  8B 06 4B 0F mov ax,word ptr [0f4bh]
+0C9C  8B 16 49 0F mov dx,word ptr [0f49h]
 0CA0  2B C2       sub ax,dx
 0CA0  2B C2       sub ax,dx
 0CA2  83 F8 00    cmp ax,0h
 0CA2  83 F8 00    cmp ax,0h
 0CA5  7D 02       jnl 0ca9h
 0CA5  7D 02       jnl 0ca9h
 0CA7  31 C0       xor ax,ax
 0CA7  31 C0       xor ax,ax
-0CA9  A3 91 0E    mov word ptr [0e91h],ax
-0CAC  8B 0E 91 0E mov cx,word ptr [0e91h]
+0CA9  A3 4D 0F    mov word ptr [0f4dh],ax
+0CAC  8B 0E 4D 0F mov cx,word ptr [0f4dh]
 0CB0  E3 08       jcxz 0cbah
 0CB0  E3 08       jcxz 0cbah
 0CB2  B0 20       mov al,20h
 0CB2  B0 20       mov al,20h
 0CB4  B4 02       mov ah,2h
 0CB4  B4 02       mov ah,2h
 0CB6  CD 21       int 21h
 0CB6  CD 21       int 21h
 0CB8  E2 F8       loop 0cb2h
 0CB8  E2 F8       loop 0cb2h
-0CBA  BE 4D 0E    mov si,0e4dh
-0CBD  8B 0E 8D 0E mov cx,word ptr [0e8dh]
+0CBA  BE 09 0F    mov si,0f09h
+0CBD  8B 0E 49 0F mov cx,word ptr [0f49h]
 0CC1  E3 09       jcxz 0ccch
 0CC1  E3 09       jcxz 0ccch
 0CC3  8A 04       mov al,byte ptr [si]
 0CC3  8A 04       mov al,byte ptr [si]
 0CC5  B4 02       mov ah,2h
 0CC5  B4 02       mov ah,2h
@@ -1593,3 +1593,109 @@
 0CD0  89 EC       mov sp,bp
 0CD0  89 EC       mov sp,bp
 0CD2  5D          pop bp
 0CD2  5D          pop bp
 0CD3  C3          ret
 0CD3  C3          ret
+0CD4  55          push bp
+0CD5  8B EC       mov bp,sp
+0CD7  53          push bx
+0CD8  51          push cx
+0CD9  52          push dx
+0CDA  56          push si
+0CDB  57          push di
+0CDC  8B 46 04    mov ax,word ptr [bp+4h]
+0CDF  88 C6       mov dh,al
+0CE1  8B 76 0A    mov si,word ptr [bp+0ah]
+0CE4  8B 7E 08    mov di,word ptr [bp+8h]
+0CE7  8B 5E 06    mov bx,word ptr [bp+6h]
+0CEA  80 FE 00    cmp dh,0h
+0CED  74 23       je 0d12h
+0CEF  8A 04       mov al,byte ptr [si]
+0CF1  8A 15       mov dl,byte ptr [di]
+0CF3  80 FC 00    cmp ah,0h
+0CF6  74 0B       je 0d03h
+0CF8  80 FC 01    cmp ah,1h
+0CFB  74 0A       je 0d07h
+0CFD  F6 D2       not dl
+0CFF  20 D0       and al,dl
+0D01  EB 06       jmp 0d09h
+0D03  20 D0       and al,dl
+0D05  EB 02       jmp 0d09h
+0D07  08 D0       or al,dl
+0D09  88 07       mov byte ptr [bx],al
+0D0B  46          inc si
+0D0C  47          inc di
+0D0D  43          inc bx
+0D0E  FE CE       dec dh
+0D10  75 DD       jne 0cefh
+0D12  5F          pop di
+0D13  5E          pop si
+0D14  5A          pop dx
+0D15  59          pop cx
+0D16  5B          pop bx
+0D17  89 EC       mov sp,bp
+0D19  5D          pop bp
+0D1A  C3          ret
+0D1B  55          push bp
+0D1C  8B EC       mov bp,sp
+0D1E  53          push bx
+0D1F  51          push cx
+0D20  52          push dx
+0D21  56          push si
+0D22  57          push di
+0D23  8B 4E 04    mov cx,word ptr [bp+4h]
+0D26  8B 76 08    mov si,word ptr [bp+8h]
+0D29  8B 7E 06    mov di,word ptr [bp+6h]
+0D2C  B4 07       mov ah,7h
+0D2E  E3 2B       jcxz 0d5bh
+0D30  8A 04       mov al,byte ptr [si]
+0D32  8A 15       mov dl,byte ptr [di]
+0D34  88 C3       mov bl,al
+0D36  88 D6       mov dh,dl
+0D38  3A C2       cmp al,dl
+0D3A  74 03       je 0d3fh
+0D3C  80 E4 FE    and ah,0feh
+0D3F  F6 D2       not dl
+0D41  20 D0       and al,dl
+0D43  3C 00       cmp al,0h
+0D45  74 03       je 0d4ah
+0D47  80 E4 FD    and ah,0fdh
+0D4A  8A C3       mov al,bl
+0D4C  F6 D0       not al
+0D4E  20 F0       and al,dh
+0D50  3C 00       cmp al,0h
+0D52  74 03       je 0d57h
+0D54  80 E4 FB    and ah,0fbh
+0D57  46          inc si
+0D58  47          inc di
+0D59  E2 D5       loop 0d30h
+0D5B  F6 C4 01    test ah,1h
+0D5E  74 03       je 0d63h
+0D60  80 E4 F9    and ah,0f9h
+0D63  88 E0       mov al,ah
+0D65  B4 00       mov ah,0h
+0D67  5F          pop di
+0D68  5E          pop si
+0D69  5A          pop dx
+0D6A  59          pop cx
+0D6B  5B          pop bx
+0D6C  89 EC       mov sp,bp
+0D6E  5D          pop bp
+0D6F  C3          ret
+0D70  55          push bp
+0D71  8B EC       mov bp,sp
+0D73  53          push bx
+0D74  51          push cx
+0D75  56          push si
+0D76  8B 4E 04    mov cx,word ptr [bp+4h]
+0D79  8B 76 06    mov si,word ptr [bp+6h]
+0D7C  8B 5E 08    mov bx,word ptr [bp+8h]
+0D7F  E3 08       jcxz 0d89h
+0D81  8A 04       mov al,byte ptr [si]
+0D83  88 07       mov byte ptr [bx],al
+0D85  46          inc si
+0D86  43          inc bx
+0D87  E2 F8       loop 0d81h
+0D89  5E          pop si
+0D8A  59          pop cx
+0D8B  5B          pop bx
+0D8C  89 EC       mov sp,bp
+0D8E  5D          pop bp
+0D8F  C3          ret