ソースを参照

runtime: MBF division (rediv)

Transcribe TPSRC2/3's rediv as entry 25 (real_div), sharing testexp's
tail and remult's rm_noadj/rm_zero/rm_ret exits.  ABI unchanged: [BP+4]
points at a then b, the result overwrites a.

Three bugs this rung exposed, each now covered:

  * the div core's first label was rd_core, which add/sub already used.
    LblOff returns the FIRST spelling, so real_div called readd and every
    quotient was a sum (1/1 = 2, 6/2 = 8).  M now HALTs on a duplicate
    label, and a non-vacuity case re-adds one.
  * TPSRC's first mantissa subtraction is SUB.B AH,remul21a, not SBB:
    in the carry-out path CF is 1 and SBB made 42/6 two ulps low.  The
    ordinary compare path has CF=0, which hid it in 13 of 14 cases.  A
    non-vacuity case re-encodes it as SBB and requires real_div red.
  * the runtime grew to 1833 bytes, past the probe's scaffold: rtdrv.s
    and rt_exec.py moved their records and blocks up 0x200 (HDR=0x0A00,
    blocks at 0x0B30+).

rt_exec is 143/143, including fourteen exact-byte division cases
(5/2 = 2.5, 42/6, signs, zero numerator, exact and fractional).
check_runtime re-blessed; audit_helpers covers the new emitters.
non-vacuity 111/111; run_all ALL PASS.
Eric Streit 1 日 前
親
コミット
1addb53272

+ 21 - 6
CALC-COMPILE.md

@@ -552,10 +552,11 @@ Exec86):
   **OVERALL: ALL PASS**, compile matrix **83/83**, CALC ladder **1/1** at
   **OVERALL: ALL PASS**, compile matrix **83/83**, CALC ladder **1/1** at
   `ERR 102 18267`, terminal config **4/4**, 64 `.COM` linked and **72 executed
   `ERR 102 18267`, terminal config **4/4**, 64 `.COM` linked and **72 executed
   under both qemu and Exec86** (`t64_arrays` is compile-only: its image is past
   under both qemu and Exec86** (`t64_arrays` is compile-only: its image is past
-  the 8 KB boot-sector read).  `tests/nonvacuity.sh`: **108 ok, 0 failed**.
-  The runtime is 1573 bytes (wrintw, real_from_int, real_add, real_sub,
-  real_mul; the golden was re-blessed) and `tests/rt_exec.py` passes
-  **99/99**, including 16 add/sub and ten multiply exact-byte cases.
+  the 8 KB boot-sector read).  `tests/nonvacuity.sh`: **111 ok, 0 failed**.
+  The runtime is 1833 bytes (wrintw, real_from_int, real_add, real_sub,
+  real_mul, real_div; the golden was re-blessed) and `tests/rt_exec.py`
+  passes **143/143**, including 16 add/sub, ten multiply and fourteen
+  division exact-byte cases.
   `check_realconst.py` pins the measured 6-byte Real operand bytes.
   `check_realconst.py` pins the measured 6-byte Real 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
@@ -686,8 +687,22 @@ Then the two that are *outside* the ladder and gate the goal as stated:
         with `testexp` inlined; ten rt_exec cases.  Two jump bugs found:
         with `testexp` inlined; ten rt_exec cases.  Two jump bugs found:
         rel8 overflow to the far zero/return targets (JccNear/JmpNear plus a
         rel8 overflow to the far zero/return targets (JccNear/JmpNear plus a
         FixUp range guard now), and JccNear's condition polarity.
         FixUp range guard now), and JccNear's condition polarity.
-      * **NEXT:** `rediv` (the five-byte long division), `recmp`, `reint`,
-        then `fmtreal`/`ascreal` for `Write(Value:FW:DEC)`, `Str` and `Val`.
+      * **DONE: `real_div`** (`v-TP3-MBF-DIV`, entry 25).  TPSRC2/3 `rediv`,
+        sharing `testexp`'s tail and `remult`'s `rm_noadj`/`rm_zero`/`rm_ret`
+        exits.  Fourteen rt_exec cases, including 5/2 = 2.5 and 42/6, the one
+        quotient below 1 (where the five-byte loop normalises by a left
+        shift).  Three traps found:
+          - the div core's first label was `rd_core`, which add/sub already
+            used; `LblOff` returned the FIRST spelling, so `real_div` called
+            `readd` and every "quotient" was a sum.  `M` now refuses a
+            duplicate label.
+          - TPSRC's `SUB.B AH,remul21a` must be SUB, not SBB: in the
+            carry-out path CF is 1, and SBB made 42/6 two ulps low.  The
+            normal compare path has CF=0, which hid it in 13 of 14 cases.
+          - the runtime outgrew the probe scaffold: rtdrv.s/rt_exec.py moved
+            their records and blocks up 0x200 (HDR=0x0A00, blocks 0x0B30+).
+      * **NEXT:** `recmp` (the six real comparisons), `reint`, then
+        `fmtreal`/`ascreal` for `Write(Value:FW:DEC)`, `Str` and `Val`.
         Each is a direct transcription with rt_exec cases.
         Each is a direct transcription with rt_exec cases.
       * **THEN** the compiler side: real expressions need a value model
       * **THEN** the compiler side: real expressions need a value model
         (pointers to 6-byte temporaries), real comparisons, and real function
         (pointers to 6-byte temporaries), real comparisons, and real function

+ 1 - 0
shell/Runtime.def

@@ -57,6 +57,7 @@ CONST
                                then b, and the result overwrites a *)
                                then b, and the result overwrites a *)
    E_RealSub = 23 ;         (* ...and subtraction: a - b *)
    E_RealSub = 23 ;         (* ...and subtraction: a - b *)
    E_RealMul = 24 ;         (* ...and multiplication: a * b *)
    E_RealMul = 24 ;         (* ...and multiplication: a * b *)
+   E_RealDiv = 25 ;         (* ...and division: a / b *)
 
 
    (* 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

+ 123 - 3
shell/Runtime.mod

@@ -139,7 +139,7 @@ VAR
    dataAt : CARDINAL ;
    dataAt : CARDINAL ;
    rtBase : CARDINAL ;
    rtBase : CARDINAL ;
    built  : BOOLEAN ;
    built  : BOOLEAN ;
-   entNm  : ARRAY [0..24] OF ARRAY [0..MaxNm] OF CHAR ;
+   entNm  : ARRAY [0..25] OF ARRAY [0..MaxNm] OF CHAR ;
 
 
 (* ---------------------------------------------------------------- *)
 (* ---------------------------------------------------------------- *)
 (*  name helpers                                                     *)
 (*  name helpers                                                     *)
@@ -194,6 +194,7 @@ END W ;
 
 
 PROCEDURE M (nm : ARRAY OF CHAR ) ;
 PROCEDURE M (nm : ARRAY OF CHAR ) ;
 (* mark: nm is the current offset *)
 (* mark: nm is the current offset *)
+VAR i : CARDINAL ;
 BEGIN
 BEGIN
    (* A dropped label is not a smaller runtime, it is a WRONG one: its bytes
    (* A dropped label is not a smaller runtime, it is a WRONG one: its bytes
       are still emitted, so only a branch that names it goes off target.  That
       are still emitted, so only a branch that names it goes off target.  That
@@ -202,6 +203,16 @@ BEGIN
    IF ltop >= MaxLbl THEN
    IF ltop >= MaxLbl THEN
       HALT
       HALT
    END ;
    END ;
+   (* A DUPLICATE label is worse than a missing one: LblOff returns the FIRST
+      spelling, so the second body (and every branch meant for it) silently
+      runs the first.  That is exactly how real_div came to call readd.  *)
+   i := 0 ;
+   WHILE i < ltop DO
+      IF StrEq (lbl [i].nm, nm) THEN
+         HALT
+      END ;
+      INC (i)
+   END ;
    SetStr (lbl [ltop].nm, nm) ;
    SetStr (lbl [ltop].nm, nm) ;
    lbl [ltop].off := rpos ;
    lbl [ltop].off := rpos ;
    INC (ltop)
    INC (ltop)
@@ -661,12 +672,38 @@ PROCEDURE StDataBx (delta : CARDINAL) ;
 BEGIN B (89H) ; B (1EH) ; Dd (delta) END StDataBx ;
 BEGIN B (89H) ; B (1EH) ; Dd (delta) END StDataBx ;
 PROCEDURE StDataDx (delta : CARDINAL) ;
 PROCEDURE StDataDx (delta : CARDINAL) ;
 BEGIN B (89H) ; B (16H) ; Dd (delta) END StDataDx ;
 BEGIN B (89H) ; B (16H) ; Dd (delta) END StDataDx ;
+PROCEDURE StDataAl (delta : CARDINAL) ;
+BEGIN B (0A2H) ; Dd (delta) END StDataAl ;
+PROCEDURE MovCxData (delta : CARDINAL) ;
+BEGIN B (8BH) ; B (0EH) ; Dd (delta) END MovCxData ;
+PROCEDURE MovBxData (delta : CARDINAL) ;
+BEGIN B (8BH) ; B (1EH) ; Dd (delta) END MovBxData ;
+PROCEDURE MovDxData (delta : CARDINAL) ;
+BEGIN B (8BH) ; B (16H) ; Dd (delta) END MovDxData ;
+PROCEDURE CmpDxData (delta : CARDINAL) ;
+BEGIN B (3BH) ; B (16H) ; Dd (delta) END CmpDxData ;
+PROCEDURE CmpBxData (delta : CARDINAL) ;
+BEGIN B (3BH) ; B (1EH) ; Dd (delta) END CmpBxData ;
+PROCEDURE CmpAhData (delta : CARDINAL) ;
+BEGIN B (3AH) ; B (26H) ; Dd (delta) END CmpAhData ;
+PROCEDURE SubAhData (delta : CARDINAL) ;
+BEGIN B (2AH) ; B (26H) ; Dd (delta) END SubAhData ;  (* SUB.B AH,remul21a: ignores the carry *)
+PROCEDURE SbbBxData (delta : CARDINAL) ;
+BEGIN B (1BH) ; B (1EH) ; Dd (delta) END SbbBxData ;
+PROCEDURE SbbDxData (delta : CARDINAL) ;
+BEGIN B (1BH) ; B (16H) ; Dd (delta) END SbbDxData ;
+PROCEDURE StDiCh ; BEGIN B (88H) ; B (2DH) END StDiCh ;     (* [DI]:=CH *)
+PROCEDURE Cmc ; BEGIN B (0F5H) END Cmc ;
+PROCEDURE Clc ; BEGIN B (0F8H) END Clc ;
+PROCEDURE IncCl ; BEGIN B (0FEH) ; B (0C1H) END IncCl ;
+PROCEDURE DecDi ; BEGIN B (4FH) END DecDi ;
 PROCEDURE SubAhCh ; BEGIN B (28H) ; B (0ECH) END SubAhCh ;  (* AH:=AH-CH *)
 PROCEDURE SubAhCh ; BEGIN B (28H) ; B (0ECH) END SubAhCh ;  (* AH:=AH-CH *)
 PROCEDURE MovClImm (v : CARDINAL) ;
 PROCEDURE MovClImm (v : CARDINAL) ;
 BEGIN B (0B1H) ; B (v MOD 256) END MovClImm ;
 BEGIN B (0B1H) ; B (v MOD 256) END MovClImm ;
 PROCEDURE CmpClImm (v : CARDINAL) ;
 PROCEDURE CmpClImm (v : CARDINAL) ;
 BEGIN B (80H) ; B (0F9H) ; B (v MOD 256) END CmpClImm ;
 BEGIN B (80H) ; B (0F9H) ; B (v MOD 256) END CmpClImm ;
 PROCEDURE SubClAl ; BEGIN B (28H) ; B (0C1H) END SubClAl ;  (* CL:=CL-AL *)
 PROCEDURE SubClAl ; BEGIN B (28H) ; B (0C1H) END SubClAl ;  (* CL:=CL-AL *)
+PROCEDURE SubAlCl ; BEGIN B (28H) ; B (0C8H) END SubAlCl ;  (* AL:=AL-CL *)
 PROCEDURE SubClImm (v : CARDINAL) ;
 PROCEDURE SubClImm (v : CARDINAL) ;
 BEGIN B (80H) ; B (0E9H) ; B (v MOD 256) END SubClImm ;
 BEGIN B (80H) ; B (0E9H) ; B (v MOD 256) END SubClImm ;
 PROCEDURE AddAhCh ; BEGIN B (00H) ; B (0ECH) END AddAhCh ;  (* AH:=AH+CH *)
 PROCEDURE AddAhCh ; BEGIN B (00H) ; B (0ECH) END AddAhCh ;  (* AH:=AH+CH *)
@@ -1863,7 +1900,89 @@ BEGIN
    M ("rm_zero") ;
    M ("rm_zero") ;
    XorAxAx ; XorBxBx ; XorDxDx ;
    XorAxAx ; XorBxBx ; XorDxDx ;
    M ("rm_ret") ;
    M ("rm_ret") ;
-   RetR
+   RetR ;
+
+   M ("real_div") ;
+   PushBp ; MovBpSp ;
+   PushBx ; PushDx ; PushSi ; PushDi ;
+   PushBp4 ;
+   MovSiBp4 ;
+   LdAxSi ;
+   LdCxSiOff (2) ; LdDxSiOff (4) ;
+   MovBxCx ;
+   MovDiSi ;
+   LdCxDiOff (6) ; LdSiDiOff (8) ; LdDiDiOff (10) ;
+   Call ("rv_core") ;
+   PopDi ;
+   StDiAx ; StDiOffBx (2) ; StDiOffDx (4) ;
+   PopDi ; PopSi ; PopDx ; PopBx ;
+   MovSpBp ; PopBp ; RetR ;
+
+   M ("rv_core") ;
+   CmpAl0 ; JccNear (74H, "rm_ret") ;
+   SubAlCl ;
+   Cmc ;
+   Jb8 ("rd_ovr1") ;
+   AddAlImm (80H) ;
+   Jb8 ("rd_okx") ;
+   JmpNear ("rm_zero") ;                 (* underflow *)
+   M ("rd_ovr1") ;
+   AddAlImm (80H) ;
+   Jae8 ("rd_okx") ;
+   MovAlD (1) ; MovAh (4CH) ; Int21 ;
+   M ("rd_okx") ;
+   (* testexp's tail *)
+   StDataCx (D_RMUL21) ;
+   MovCxDx ; XorCxDi ; NotCh ; AndChImm (80H) ; StDataCh (D_RESAVE) ;
+   OrDhImm (80H) ; OrDiImm (8000H) ;
+   StDataSi (D_RMUL22) ; StDataDi (D_RMUL23) ;
+   (* rediv *)
+   StDataAl (D_RMUL11) ;
+   MovDiData (D_RMUL21 - 1) ;            (* remul21b: one before the mantissa *)
+   MovClImm (5) ;
+   MovSiImm (8) ;
+   M ("rd_loop") ;
+   CmpDxData (D_RMUL23) ; Jne8 ("rd_cmp") ;
+   CmpBxData (D_RMUL22) ; Jne8 ("rd_cmp") ;
+   CmpAhData (D_RMUL21 + 1) ;
+   M ("rd_cmp") ;
+   Jb8 ("rd_shft") ;
+   SubAhData (D_RMUL21 + 1) ; SbbBxData (D_RMUL22) ; SbbDxData (D_RMUL23) ;
+   M ("rd_shft") ;
+   Cmc ;
+   RclCh1 ;
+   DecSi ; Jne8 ("rd_bit") ;
+   StDiCh ;
+   DecCl ; Je8 ("rd_last") ;
+   DecDi ;
+   MovSiImm (8) ;
+   M ("rd_bit") ;
+   ShlAh1 ; RclBx1 ; RclDx1 ;
+   Jae8 ("rd_loop") ;
+   SubAhData (D_RMUL21 + 1) ; SbbBxData (D_RMUL22) ; SbbDxData (D_RMUL23) ;
+   Clc ;
+   Jmp8 ("rd_shft") ;
+   M ("rd_last") ;
+   ShlAh1 ; RclBx1 ; RclDx1 ;
+   Jb8 ("rd_shft2") ;
+   CmpDxData (D_RMUL23) ; Jne8 ("rd_cmp2") ;
+   CmpBxData (D_RMUL22) ; Jne8 ("rd_cmp2") ;
+   CmpAhData (D_RMUL21 + 1) ;
+   M ("rd_cmp2") ;
+   Cmc ;
+   M ("rd_shft2") ;
+   MovCxData (D_RMUL11) ; MovBxData (D_RMUL12) ; MovDxData (D_RMUL13) ;
+   Lahf ;
+   TestDhImm (80H) ; Jne8 ("rd_nrm") ;
+   Sahf ;
+   RclCh1 ; RclBx1 ; RclDx1 ;
+   Jmp8 ("rd_ok") ;
+   M ("rd_nrm") ;
+   IncCl ;
+   Jne8 ("rd_ok") ;
+   MovAlD (1) ; MovAh (4CH) ; Int21 ;
+   M ("rd_ok") ;
+   JmpNear ("rm_noadj")
 END EmitRealMul ;
 END EmitRealMul ;
 
 
 PROCEDURE EmitData ;
 PROCEDURE EmitData ;
@@ -2034,6 +2153,7 @@ BEGIN
    SetStr (entNm [22], "real_add") ;
    SetStr (entNm [22], "real_add") ;
    SetStr (entNm [23], "real_sub") ;
    SetStr (entNm [23], "real_sub") ;
    SetStr (entNm [24], "real_mul") ;
    SetStr (entNm [24], "real_mul") ;
+   SetStr (entNm [25], "real_div") ;
    built := TRUE
    built := TRUE
 END RT_Build ;
 END RT_Build ;
 
 
@@ -2061,7 +2181,7 @@ BEGIN
    IF NOT built THEN
    IF NOT built THEN
       RT_Build (0)
       RT_Build (0)
    END ;
    END ;
-   IF i > 24 THEN
+   IF i > 25 THEN
       RETURN 0
       RETURN 0
    END ;
    END ;
    RETURN rtBase + LblOff (entNm [i])
    RETURN rtBase + LblOff (entNm [i])

+ 4 - 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..24] OF ARRAY [0..15] OF CHAR ;
+    names : ARRAY [0..25] 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 <= 24 DO
+   WHILE i <= 25 DO
       names [i] := "" ;
       names [i] := "" ;
       INC (i)
       INC (i)
    END ;
    END ;
@@ -137,8 +137,9 @@ BEGIN
    names [22] := "real_add" ;
    names [22] := "real_add" ;
    names [23] := "real_sub" ;
    names [23] := "real_sub" ;
    names [24] := "real_mul" ;
    names [24] := "real_mul" ;
+   names [25] := "real_div" ;
    i := 0 ;
    i := 0 ;
-   WHILE i <= 24 DO
+   WHILE i <= 25 DO
       PENT (i, names [i]) ;
       PENT (i, names [i]) ;
       INC (i)
       INC (i)
    END ;
    END ;

+ 9 - 0
shell/tests/audit_helpers.py

@@ -125,6 +125,13 @@ NON_ONE_LINE = {
         "JmpNear": COMP, "MovDiData": COMP, "MovSiImm": COMP,
         "JmpNear": COMP, "MovDiData": COMP, "MovSiImm": COMP,
         "StDataAx": COMP, "StDataBx": COMP, "StDataCh": COMP,
         "StDataAx": COMP, "StDataBx": COMP, "StDataCh": COMP,
         "StDataCx": COMP, "StDataDx": COMP, "StDataSi": COMP,
         "StDataCx": COMP, "StDataDx": COMP, "StDataSi": COMP,
+        # rediv's memory-operand compares/subtracts and result loads.  The
+        # displacement is a parameter, so the bytes cannot be disassembled as
+        # a fixed sequence; rt_exec's fourteen real_div cases pin them.
+        "CmpDxData": COMP, "CmpBxData": COMP, "CmpAhData": COMP,
+        "MovCxData": COMP, "MovBxData": COMP, "MovDxData": COMP,
+        "SbbBxData": COMP, "SbbDxData": COMP,
+        "SubAhData": COMP, "StDataAl": COMP,
         "MovBxImm": PARAM, "MovCxImm": PARAM, "MovDxImm": PARAM,
         "MovBxImm": PARAM, "MovCxImm": PARAM, "MovDxImm": PARAM,
         "MovDl": PARAM, "MovAlD": PARAM, "MovAh": PARAM,
         "MovDl": PARAM, "MovAlD": PARAM, "MovAh": PARAM,
         "SubAl": PARAM, "CmpAl": PARAM, "AddDl": PARAM, "J8": COMP,
         "SubAl": PARAM, "CmpAl": PARAM, "AddDl": PARAM, "J8": COMP,
@@ -404,6 +411,8 @@ PATTERNS = [
     (re.compile(r"^(Shl|Shr|Rcl|Rcr|Rol|Ror|Sar)(%s)1$" % _ALT),
     (re.compile(r"^(Shl|Shr|Rcl|Rcr|Rol|Ror|Sar)(%s)1$" % _ALT),
      None, ["r:%(2)s", "i:1"], {0xD0, 0xD1}),
      None, ["r:%(2)s", "i:1"], {0xD0, 0xD1}),
     (re.compile(r"^Stc$"), "stc", [], {0xF9}),
     (re.compile(r"^Stc$"), "stc", [], {0xF9}),
+    (re.compile(r"^Cmc$"), "cmc", [], {0xF5}),
+    (re.compile(r"^Clc$"), "clc", [], {0xF8}),
     (re.compile(r"^Lahf$"), "lahf", [], {0x9F}),
     (re.compile(r"^Lahf$"), "lahf", [], {0x9F}),
     (re.compile(r"^Sahf$"), "sahf", [], {0x9E}),
     (re.compile(r"^Sahf$"), "sahf", [], {0x9E}),
     (re.compile(r"^LdChDiOff$"), "mov", ["r:Ch", "m:Di"], {0x8A}),
     (re.compile(r"^LdChDiOff$"), "mov", ["r:Ch", "m:Di"], {0x8A}),

+ 1 - 0
shell/tests/check_runtime.py

@@ -136,6 +136,7 @@ GOLDEN = {
     "real_add": "55 8B EC 53 52 56 57",
     "real_add": "55 8B EC 53 52 56 57",
     "real_sub": "55 8B EC 53 52 56 57",
     "real_sub": "55 8B EC 53 52 56 57",
     "real_mul": "55 8B EC 53 52 56 57",
     "real_mul": "55 8B EC 53 52 56 57",
+    "real_div": "55 8B EC 53 52 56 57",
     # wrchar: AL, not DL.  DOS INT 21h AH=02h takes the character in AL, and
     # wrchar: AL, not DL.  DOS INT 21h AH=02h takes the character in AL, and
     # DL is the *other* 8086 convention (BIOS teletype).  This read DL, so
     # DL is the *other* 8086 convention (BIOS teletype).  This read DL, so
     # every write of a character printed whatever the *last* character read
     # every write of a character printed whatever the *last* character read

+ 59 - 27
shell/tests/exec/rtdrv.s

@@ -92,36 +92,46 @@
 # silently run into the test scaffolding.  rt_exec.py asserts
 # silently run into the test scaffolding.  rt_exec.py asserts
 # RT_BASE + blob size <= HDR, so the bound is a checked one.
 # RT_BASE + blob size <= HDR, so the bound is a checked one.
 	.set	RT_BASE, 0x0190
 	.set	RT_BASE, 0x0190
-	.set	HDR, 0x0800
-	.set	DATA, 0x0810
+	.set	HDR, 0x0A00
+	.set	DATA, 0x0A10
 	.set	DLEN, 32			# bytes of data area for initmem to clear
 	.set	DLEN, 32			# bytes of data area for initmem to clear
-	.set	STORE, 0x0840		# where a read entry's result is stored
-	.set	WSTR, 0x0850		# a string for the wrstr case: length + chars
-	.set	WSTR_EMPTY, 0x0858	# the same, with a length of 0
-	.set	CASE, 0x0860		# the case record
-	.set	D_DUMPLEN, 0x08A0	# the driver's own three words
-	.set	D_DUMPADR, 0x08A2
-	.set	D_CNT, 0x08A4
-	.set	RDSTR_DST, 0x08B0	# destination for the rdstr cases
-	.set	SST_HELLO, 0x08C0	# a short source string for strstore
-	.set	SST_LONG, 0x08D0	# a source longer than a small max
-	.set	SST_EMPTY, 0x08E0	# an empty source string
-	.set	SST_DST, 0x08F0		# destination for the strstore cases
-	.set	SST_CAT, 0x0900		# destination for the strcat cases, with a
+	.set	STORE, 0x0A40		# where a read entry's result is stored
+	.set	WSTR, 0x0A50		# a string for the wrstr case: length + chars
+	.set	WSTR_EMPTY, 0x0A58	# the same, with a length of 0
+	.set	CASE, 0x0A60		# the case record
+	.set	D_DUMPLEN, 0x0AA0	# the driver's own three words
+	.set	D_DUMPADR, 0x0AA2
+	.set	D_CNT, 0x0AA4
+	.set	RDSTR_DST, 0x0AB0	# destination for the rdstr cases
+	.set	SST_HELLO, 0x0AC0	# a short source string for strstore
+	.set	SST_LONG, 0x0AD0	# a source longer than a small max
+	.set	SST_EMPTY, 0x0AE0	# an empty source string
+	.set	SST_DST, 0x0AF0		# destination for the strstore cases
+	.set	SST_CAT, 0x0B00		# destination for the strcat cases, with a
 					# length to append to -- unlike SST_DST,
 					# length to append to -- unlike SST_DST,
 					# which strstore overwrites
 					# which strstore overwrites
-	.set	SST_CAT0, 0x0910	# ...and one that starts empty
-	.set	SST_WORLD, 0x0920	# a source distinct from SST_HELLO
-	.set	R_BLK1, 0x0930
-	.set	R_BLK2, 0x0940
-	.set	R_BLK3, 0x0950
-	.set	R_BLK4, 0x0960
-	.set	R_BLK5, 0x0970
-	.set	R_BLK6, 0x0980
-	.set	R_BLK7, 0x0990
-	.set	R_BLK8, 0x09A0
-	.set	R_BLK9, 0x09B0
-	.set	R_BLK10, 0x09C0
+	.set	SST_CAT0, 0x0B10	# ...and one that starts empty
+	.set	SST_WORLD, 0x0B20	# a source distinct from SST_HELLO
+	.set	R_BLK1, 0x0B30
+	.set	R_BLK2, 0x0B40
+	.set	R_BLK3, 0x0B50
+	.set	R_BLK4, 0x0B60
+	.set	R_BLK5, 0x0B70
+	.set	R_BLK6, 0x0B80
+	.set	R_BLK7, 0x0B90
+	.set	R_BLK8, 0x0BA0
+	.set	R_BLK9, 0x0BB0
+	.set	R_BLK10, 0x0BC0
+	.set	R_BLK11, 0x0BD0
+	.set	R_BLK12, 0x0BE0
+	.set	R_BLK13, 0x0BF0
+	.set	R_BLK14, 0x0C00
+	.set	R_BLK15, 0x0C10
+	.set	R_BLK16, 0x0C20
+	.set	R_BLK17, 0x0C30
+	.set	R_BLK18, 0x0C40
+	.set	R_BLK19, 0x0C50
+	.set	R_BLK20, 0x0C60
 
 
 	.code16
 	.code16
 	.text
 	.text
@@ -443,3 +453,25 @@ HDR:
 	.byte	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x83, 0x00, 0x00, 0x00, 0x00, 0x20
 	.byte	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x83, 0x00, 0x00, 0x00, 0x00, 0x20
 	.org	R_BLK10
 	.org	R_BLK10
 	.byte	0x82, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x82, 0x00, 0x00, 0x00, 0x00, 0x80
 	.byte	0x82, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x82, 0x00, 0x00, 0x00, 0x00, 0x80
+
+# Division pairs for real_div.
+	.org	R_BLK11
+	.byte	0x83, 0x00, 0x00, 0x00, 0x00, 0x40, 0x82, 0x00, 0x00, 0x00, 0x00, 0x00
+	.org	R_BLK12
+	.byte	0x84, 0x00, 0x00, 0x00, 0x00, 0x20, 0x82, 0x00, 0x00, 0x00, 0x00, 0x00
+	.org	R_BLK13
+	.byte	0x84, 0x00, 0x00, 0x00, 0x00, 0x70, 0x82, 0x00, 0x00, 0x00, 0x00, 0x40
+	.org	R_BLK14
+	.byte	0x8A, 0x00, 0x00, 0x00, 0x00, 0x7A, 0x82, 0x00, 0x00, 0x00, 0x00, 0x00
+	.org	R_BLK15
+	.byte	0x83, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x82, 0x00, 0x00, 0x00, 0x00, 0x00
+	.org	R_BLK16
+	.byte	0x83, 0x00, 0x00, 0x00, 0x00, 0x40, 0x82, 0x00, 0x00, 0x00, 0x00, 0x80
+	.org	R_BLK17
+	.byte	0x83, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x82, 0x00, 0x00, 0x00, 0x00, 0x80
+	.org	R_BLK18
+	.byte	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x83, 0x00, 0x00, 0x00, 0x00, 0x20
+	.org	R_BLK19
+	.byte	0x83, 0x00, 0x00, 0x00, 0x00, 0x20, 0x82, 0x00, 0x00, 0x00, 0x00, 0x00
+	.org	R_BLK20
+	.byte	0x86, 0x00, 0x00, 0x00, 0x00, 0x28, 0x83, 0x00, 0x00, 0x00, 0x00, 0x40

+ 19 - 0
shell/tests/nonvacuity.sh

@@ -1422,6 +1422,25 @@ 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
 
 
+# --- rediv's first subtraction is SUB, not SBB ---------------------------
+# TPSRC's `SUB.B AH,remul21a' ignores the carry; `SBB' would subtract the
+# carry-out of the shifted numerator as well.  In the ordinary compare path
+# CF is 0, so the two agree and a casual transcription passes most divisions;
+# only 42/6 - the one quotient below 1, where the loop subtracts on equality -
+# comes out two ulps low.  Encoding the AH subtraction as SBB must turn the
+# exact-byte real_div cases red.
+if mutate Runtime.mod 's|BEGIN B (2AH) ; B (26H) ; Dd (delta) END SubAhData|BEGIN B (1AH) ; B (26H) ; Dd (delta) END SubAhData|'; then
+    if "$GM2" -fiso -c Runtime.mod >/dev/null 2>&1; then
+        expect_red "real_div red when the mantissa subtraction uses SBB instead of SUB" \
+            "real_div" python3 tests/rt_exec.py
+    else
+        echo "  FAIL: the runtime would not rebuild with SubAhData as SBB"
+        fail=$((fail + 1))
+    fi
+fi
+cp "$SAVED" Runtime.mod
+"$GM2" -fiso -c Runtime.mod >/dev/null 2>&1
+
 # --- the compiler's arms --------------------------------------------------
 # --- the compiler's arms --------------------------------------------------
 # The limit both entries read is MOV CX,imm16.  MOV AX,imm16 is one opcode away,
 # The limit both entries read is MOV CX,imm16.  MOV AX,imm16 is one opcode away,
 # the same length, and the audit's MovCxi row is COMP - "no single sequence to
 # the same length, and the audit's MovCxi row is COMP - "no single sequence to

+ 31 - 17
shell/tests/rt_exec.py

@@ -62,22 +62,22 @@ SHELL = os.path.dirname(HERE)
 # two are written down and then CHECKED against each other (see build_image).
 # two are written down and then CHECKED against each other (see build_image).
 # A restated constant that is never compared is a constant waiting to lie.
 # A restated constant that is never compared is a constant waiting to lie.
 RT_BASE = 0x0190
 RT_BASE = 0x0190
-HDR = 0x0800
+HDR = 0x0A00
 DLEN = 32
 DLEN = 32
-DATA = 0x0810
-STORE = 0x0840
-WSTR = 0x0850
-WSTR_EMPTY = 0x0858
-CASE = 0x0860
+DATA = 0x0A10
+STORE = 0x0A40
+WSTR = 0x0A50
+WSTR_EMPTY = 0x0A58
+CASE = 0x0A60
 CASE_SZ = 64
 CASE_SZ = 64
-RDSTR_DST = 0x08B0
-SST_HELLO = 0x08C0
-SST_LONG = 0x08D0
-SST_EMPTY = 0x08E0
-SST_DST = 0x08F0
-SST_CAT = 0x0900
-SST_CAT0 = 0x0910
-SST_WORLD = 0x0920
+RDSTR_DST = 0x0AB0
+SST_HELLO = 0x0AC0
+SST_LONG = 0x0AD0
+SST_EMPTY = 0x0AE0
+SST_DST = 0x0AF0
+SST_CAT = 0x0B00
+SST_CAT0 = 0x0B10
+SST_WORLD = 0x0B20
 
 
 # A .COM is loaded at CS:0100, and every address in the image is an image
 # A .COM is loaded at CS:0100, and every address in the image is an image
 # offset.  The load bias is therefore the difference between the two, and
 # offset.  The load bias is therefore the difference between the two, and
@@ -103,7 +103,8 @@ SOH, STX, ETX, EOT = 0x01, 0x02, 0x03, 0x04
 ENTS = ["initmem", "progend", "stackchk", "wrint", "wrchar", "wrbool",
 ENTS = ["initmem", "progend", "stackchk", "wrint", "wrchar", "wrbool",
         "wrreal", "wrln", "rdint", "rdchar", "rdbool", "rdln", "halt",
         "wrreal", "wrln", "rdint", "rdchar", "rdbool", "rdln", "halt",
         "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"]
 
 
 # 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
@@ -497,9 +498,11 @@ def build_cases():
     # The driver preloads 12-byte blocks (a then b); real_add/real_sub take
     # The driver preloads 12-byte blocks (a then b); real_add/real_sub take
     # the block's address, read both operands, and overwrite a with the result.
     # the block's address, read both operands, and overwrite a with the result.
     BLOCKS = [(1, 2), (3, 5), (5, 3), (1, 1), (1000, 1), (-3, 2),
     BLOCKS = [(1, 2), (3, 5), (5, 3), (1, 1), (1000, 1), (-3, 2),
-              (42, 1000), (32767, 1), (0, 5), (-3, -2)]
+              (42, 1000), (32767, 1), (0, 5), (-3, -2),
+              (6, 2), (10, 2), (15, 3), (1000, 2), (-6, 2), (6, -2),
+              (-6, -2), (0, 5), (5, 2), (42, 6)]
     for bi, (a, b) in enumerate(BLOCKS):
     for bi, (a, b) in enumerate(BLOCKS):
-        blk = 0x0930 + 16 * bi
+        blk = 0x0B30 + 16 * bi
         add("real_add(%d,%d)" % (a, b),
         add("real_add(%d,%d)" % (a, b),
             [s("real_add", blk + LOAD_BIAS)],
             [s("real_add", blk + LOAD_BIAS)],
             dump=6, dumpbytes=mbf(a + b), dumpadr=blk,
             dump=6, dumpbytes=mbf(a + b), dumpadr=blk,
@@ -512,6 +515,17 @@ def build_cases():
             [s("real_mul", blk + LOAD_BIAS)],
             [s("real_mul", blk + LOAD_BIAS)],
             dump=6, dumpbytes=mbf(a * b), dumpadr=blk,
             dump=6, dumpbytes=mbf(a * b), dumpadr=blk,
             note="the measured MBF bytes, the reference's remult")
             note="the measured MBF bytes, the reference's remult")
+        if b != 0 and a % b == 0:
+            q = mbf(a // b)
+        elif a == 5 and b == 2:
+            q = bytes.fromhex("820000000020")   # 2.5
+        else:
+            q = None
+        if q is not None:
+            add("real_div(%d,%d)" % (a, b),
+                [s("real_div", blk + LOAD_BIAS)],
+                dump=6, dumpbytes=q, dumpadr=blk,
+                note="the measured MBF bytes, the reference's rediv")
 
 
     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"!")

+ 144 - 34
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 FE 06    mov bx,6feh
+003C  BB 02 08    mov bx,802h
 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 FE 06    mov bx,6feh
+00A8  BB 02 08    mov bx,802h
 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 03 07    mov dx,703h
+00E6  BA 07 08    mov dx,807h
 00E9  EB 03       jmp 0eeh
 00E9  EB 03       jmp 0eeh
-00EB  BA FE 06    mov dx,6feh
+00EB  BA 02 08    mov dx,802h
 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 0C 07    mov dx,70ch
+00F4  BA 10 08    mov dx,810h
 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 09 07    mov dx,709h
+00FC  BA 0D 08    mov dx,80dh
 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 12 07 mov bx,word ptr [712h]
+021B  8B 1E 16 08 mov bx,word ptr [816h]
 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 12 07 mov word ptr [712h],bx
+0228  89 1E 16 08 mov word ptr [816h],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 12 07 mov word ptr [712h],bx
+0239  89 1E 16 08 mov word ptr [816h],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
@@ -541,7 +541,7 @@
 03BE  8B 4D 06    mov cx,word ptr [di+6h]
 03BE  8B 4D 06    mov cx,word ptr [di+6h]
 03C1  8B 75 08    mov si,word ptr [di+8h]
 03C1  8B 75 08    mov si,word ptr [di+8h]
 03C4  8B 7D 0A    mov di,word ptr [di+0ah]
 03C4  8B 7D 0A    mov di,word ptr [di+0ah]
-03C7  C7 06 14 07 00 00 mov word ptr [714h],0h
+03C7  C7 06 18 08 00 00 mov word ptr [818h],0h
 03CD  E8 4D 00    call 41dh
 03CD  E8 4D 00    call 41dh
 03D0  5F          pop di
 03D0  5F          pop di
 03D1  89 05       mov word ptr [di],ax
 03D1  89 05       mov word ptr [di],ax
@@ -570,7 +570,7 @@
 03FA  8B 4D 06    mov cx,word ptr [di+6h]
 03FA  8B 4D 06    mov cx,word ptr [di+6h]
 03FD  8B 75 08    mov si,word ptr [di+8h]
 03FD  8B 75 08    mov si,word ptr [di+8h]
 0400  8B 7D 0A    mov di,word ptr [di+0ah]
 0400  8B 7D 0A    mov di,word ptr [di+0ah]
-0403  C7 06 14 07 00 80 mov word ptr [714h],8000h
+0403  C7 06 18 08 00 80 mov word ptr [818h],8000h
 0409  E8 11 00    call 41dh
 0409  E8 11 00    call 41dh
 040C  5F          pop di
 040C  5F          pop di
 040D  89 05       mov word ptr [di],ax
 040D  89 05       mov word ptr [di],ax
@@ -585,7 +585,7 @@
 041C  C3          ret
 041C  C3          ret
 041D  80 F9 00    cmp cl,0h
 041D  80 F9 00    cmp cl,0h
 0420  74 0E       je 430h
 0420  74 0E       je 430h
-0422  33 3E 14 07 xor di,word ptr [714h]
+0422  33 3E 18 08 xor di,word ptr [818h]
 0426  3C 00       cmp al,0h
 0426  3C 00       cmp al,0h
 0428  75 07       jne 431h
 0428  75 07       jne 431h
 042A  89 C8       mov ax,cx
 042A  89 C8       mov ax,cx
@@ -597,16 +597,16 @@
 0435  91          xchg ax,cx
 0435  91          xchg ax,cx
 0436  87 F3       xchg bx,si
 0436  87 F3       xchg bx,si
 0438  87 FA       xchg dx,di
 0438  87 FA       xchg dx,di
-043A  88 0E 18 07 mov byte ptr [718h],cl
+043A  88 0E 1C 08 mov byte ptr [81ch],cl
 043E  28 C1       sub cl,al
 043E  28 C1       sub cl,al
 0440  80 F9 28    cmp cl,28h
 0440  80 F9 28    cmp cl,28h
 0443  72 06       jb 44bh
 0443  72 06       jb 44bh
-0445  8A 0E 18 07 mov cl,byte ptr [718h]
+0445  8A 0E 1C 08 mov cl,byte ptr [81ch]
 0449  EB DF       jmp 42ah
 0449  EB DF       jmp 42ah
-044B  89 3E 14 07 mov word ptr [714h],di
-044F  80 26 15 07 80 and byte ptr [715h],80h
-0454  89 3E 16 07 mov word ptr [716h],di
-0458  30 36 17 07 xor byte ptr [717h],dh
+044B  89 3E 18 08 mov word ptr [818h],di
+044F  80 26 19 08 80 and byte ptr [819h],80h
+0454  89 3E 1A 08 mov word ptr [81ah],di
+0458  30 36 1B 08 xor byte ptr [81bh],dh
 045C  81 CF 00 80 or di,8000h
 045C  81 CF 00 80 or di,8000h
 0460  80 CE 80    or dh,80h
 0460  80 CE 80    or dh,80h
 0463  80 F9 10    cmp cl,10h
 0463  80 F9 10    cmp cl,10h
@@ -631,8 +631,8 @@
 048E  D0 DC       rcr ah,1h
 048E  D0 DC       rcr ah,1h
 0490  FE C9       dec cl
 0490  FE C9       dec cl
 0492  75 F6       jne 48ah
 0492  75 F6       jne 48ah
-0494  A0 18 07    mov al,byte ptr [718h]
-0497  F6 06 17 07 80 test byte ptr [717h],80h
+0494  A0 1C 08    mov al,byte ptr [81ch]
+0497  F6 06 1B 08 80 test byte ptr [81bh],80h
 049C  75 14       jne 4b2h
 049C  75 14       jne 4b2h
 049E  00 EC       add ah,ch
 049E  00 EC       add ah,ch
 04A0  11 F3       adc bx,si
 04A0  11 F3       adc bx,si
@@ -652,7 +652,7 @@
 04BA  19 F3       sbb bx,si
 04BA  19 F3       sbb bx,si
 04BC  19 FA       sbb dx,di
 04BC  19 FA       sbb dx,di
 04BE  73 14       jnb 4d4h
 04BE  73 14       jnb 4d4h
-04C0  80 36 15 07 80 xor byte ptr [715h],80h
+04C0  80 36 19 08 80 xor byte ptr [819h],80h
 04C5  F6 D4       not ah
 04C5  F6 D4       not ah
 04C7  F7 D3       not bx
 04C7  F7 D3       not bx
 04C9  F7 D2       not dx
 04C9  F7 D2       not dx
@@ -684,7 +684,7 @@
 0502  31 D2       xor dx,dx
 0502  31 D2       xor dx,dx
 0504  C3          ret
 0504  C3          ret
 0505  80 E6 7F    and dh,7fh
 0505  80 E6 7F    and dh,7fh
-0508  32 36 15 07 xor dh,byte ptr [715h]
+0508  32 36 19 08 xor dh,byte ptr [819h]
 050C  C3          ret
 050C  C3          ret
 050D  55          push bp
 050D  55          push bp
 050E  8B EC       mov bp,sp
 050E  8B EC       mov bp,sp
@@ -730,23 +730,23 @@
 0561  B0 01       mov al,1h
 0561  B0 01       mov al,1h
 0563  B4 4C       mov ah,4ch
 0563  B4 4C       mov ah,4ch
 0565  CD 21       int 21h
 0565  CD 21       int 21h
-0567  89 0E 1F 07 mov word ptr [71fh],cx
+0567  89 0E 23 08 mov word ptr [823h],cx
 056B  8B CA       mov cx,dx
 056B  8B CA       mov cx,dx
 056D  31 F9       xor cx,di
 056D  31 F9       xor cx,di
 056F  F6 D5       not ch
 056F  F6 D5       not ch
 0571  80 E5 80    and ch,80h
 0571  80 E5 80    and ch,80h
-0574  88 2E 15 07 mov byte ptr [715h],ch
+0574  88 2E 19 08 mov byte ptr [819h],ch
 0578  80 CE 80    or dh,80h
 0578  80 CE 80    or dh,80h
 057B  81 CF 00 80 or di,8000h
 057B  81 CF 00 80 or di,8000h
-057F  89 36 21 07 mov word ptr [721h],si
-0583  89 3E 23 07 mov word ptr [723h],di
-0587  A3 19 07    mov word ptr [719h],ax
-058A  89 1E 1B 07 mov word ptr [71bh],bx
-058E  89 16 1D 07 mov word ptr [71dh],dx
+057F  89 36 25 08 mov word ptr [825h],si
+0583  89 3E 27 08 mov word ptr [827h],di
+0587  A3 1D 08    mov word ptr [81dh],ax
+058A  89 1E 1F 08 mov word ptr [81fh],bx
+058E  89 16 21 08 mov word ptr [821h],dx
 0592  30 E4       xor ah,ah
 0592  30 E4       xor ah,ah
 0594  31 DB       xor bx,bx
 0594  31 DB       xor bx,bx
 0596  31 D2       xor dx,dx
 0596  31 D2       xor dx,dx
-0598  BF 1F 07    mov di,71fh
+0598  BF 23 08    mov di,823h
 059B  B1 05       mov cl,5h
 059B  B1 05       mov cl,5h
 059D  47          inc di
 059D  47          inc di
 059E  8A 2D       mov ch,byte ptr [di]
 059E  8A 2D       mov ch,byte ptr [di]
@@ -761,9 +761,9 @@
 05B1  BE 08 00    mov si,8h
 05B1  BE 08 00    mov si,8h
 05B4  D0 DD       rcr ch,1h
 05B4  D0 DD       rcr ch,1h
 05B6  73 0C       jnb 5c4h
 05B6  73 0C       jnb 5c4h
-05B8  02 26 1A 07 add ah,byte ptr [71ah]
-05BC  13 1E 1B 07 adc bx,word ptr [71bh]
-05C0  13 16 1D 07 adc dx,word ptr [71dh]
+05B8  02 26 1E 08 add ah,byte ptr [81eh]
+05BC  13 1E 1F 08 adc bx,word ptr [81fh]
+05C0  13 16 21 08 adc dx,word ptr [821h]
 05C4  D1 DA       rcr dx,1h
 05C4  D1 DA       rcr dx,1h
 05C6  D1 DB       rcr bx,1h
 05C6  D1 DB       rcr bx,1h
 05C8  D0 DC       rcr ah,1h
 05C8  D0 DC       rcr ah,1h
@@ -783,10 +783,120 @@
 05E2  74 02       je 5e6h
 05E2  74 02       je 5e6h
 05E4  FE C9       dec cl
 05E4  FE C9       dec cl
 05E6  91          xchg ax,cx
 05E6  91          xchg ax,cx
-05E7  32 36 15 07 xor dh,byte ptr [715h]
+05E7  32 36 19 08 xor dh,byte ptr [819h]
 05EB  3C 00       cmp al,0h
 05EB  3C 00       cmp al,0h
 05ED  75 06       jne 5f5h
 05ED  75 06       jne 5f5h
 05EF  31 C0       xor ax,ax
 05EF  31 C0       xor ax,ax
 05F1  31 DB       xor bx,bx
 05F1  31 DB       xor bx,bx
 05F3  31 D2       xor dx,dx
 05F3  31 D2       xor dx,dx
 05F5  C3          ret
 05F5  C3          ret
+05F6  55          push bp
+05F7  8B EC       mov bp,sp
+05F9  53          push bx
+05FA  52          push dx
+05FB  56          push si
+05FC  57          push di
+05FD  FF 76 04    push word ptr [bp+4h]
+0600  8B 76 04    mov si,word ptr [bp+4h]
+0603  8B 04       mov ax,word ptr [si]
+0605  8B 4C 02    mov cx,word ptr [si+2h]
+0608  8B 54 04    mov dx,word ptr [si+4h]
+060B  89 CB       mov bx,cx
+060D  8B FE       mov di,si
+060F  8B 4D 06    mov cx,word ptr [di+6h]
+0612  8B 75 08    mov si,word ptr [di+8h]
+0615  8B 7D 0A    mov di,word ptr [di+0ah]
+0618  E8 11 00    call 62ch
+061B  5F          pop di
+061C  89 05       mov word ptr [di],ax
+061E  89 5D 02    mov word ptr [di+2h],bx
+0621  89 55 04    mov word ptr [di+4h],dx
+0624  5F          pop di
+0625  5E          pop si
+0626  5A          pop dx
+0627  5B          pop bx
+0628  89 EC       mov sp,bp
+062A  5D          pop bp
+062B  C3          ret
+062C  3C 00       cmp al,0h
+062E  75 03       jne 633h
+0630  E9 C2 FF    jmp 5f5h
+0633  28 C8       sub al,cl
+0635  F5          cmc
+0636  72 07       jb 63fh
+0638  04 80       add al,80h
+063A  72 0D       jb 649h
+063C  E9 B0 FF    jmp 5efh
+063F  04 80       add al,80h
+0641  73 06       jnb 649h
+0643  B0 01       mov al,1h
+0645  B4 4C       mov ah,4ch
+0647  CD 21       int 21h
+0649  89 0E 23 08 mov word ptr [823h],cx
+064D  8B CA       mov cx,dx
+064F  31 F9       xor cx,di
+0651  F6 D5       not ch
+0653  80 E5 80    and ch,80h
+0656  88 2E 19 08 mov byte ptr [819h],ch
+065A  80 CE 80    or dh,80h
+065D  81 CF 00 80 or di,8000h
+0661  89 36 25 08 mov word ptr [825h],si
+0665  89 3E 27 08 mov word ptr [827h],di
+0669  A2 1D 08    mov byte ptr [81dh],al
+066C  BF 22 08    mov di,822h
+066F  B1 05       mov cl,5h
+0671  BE 08 00    mov si,8h
+0674  3B 16 27 08 cmp dx,word ptr [827h]
+0678  75 0A       jne 684h
+067A  3B 1E 25 08 cmp bx,word ptr [825h]
+067E  75 04       jne 684h
+0680  3A 26 24 08 cmp ah,byte ptr [824h]
+0684  72 0C       jb 692h
+0686  2A 26 24 08 sub ah,byte ptr [824h]
+068A  1B 1E 25 08 sbb bx,word ptr [825h]
+068E  1B 16 27 08 sbb dx,word ptr [827h]
+0692  F5          cmc
+0693  D0 D5       rcl ch,1h
+0695  4E          dec si
+0696  75 0A       jne 6a2h
+0698  88 2D       mov byte ptr [di],ch
+069A  FE C9       dec cl
+069C  74 1B       je 6b9h
+069E  4F          dec di
+069F  BE 08 00    mov si,8h
+06A2  D0 E4       shl ah,1h
+06A4  D1 D3       rcl bx,1h
+06A6  D1 D2       rcl dx,1h
+06A8  73 CA       jnb 674h
+06AA  2A 26 24 08 sub ah,byte ptr [824h]
+06AE  1B 1E 25 08 sbb bx,word ptr [825h]
+06B2  1B 16 27 08 sbb dx,word ptr [827h]
+06B6  F8          clc
+06B7  EB D9       jmp 692h
+06B9  D0 E4       shl ah,1h
+06BB  D1 D3       rcl bx,1h
+06BD  D1 D2       rcl dx,1h
+06BF  72 11       jb 6d2h
+06C1  3B 16 27 08 cmp dx,word ptr [827h]
+06C5  75 0A       jne 6d1h
+06C7  3B 1E 25 08 cmp bx,word ptr [825h]
+06CB  75 04       jne 6d1h
+06CD  3A 26 24 08 cmp ah,byte ptr [824h]
+06D1  F5          cmc
+06D2  8B 0E 1D 08 mov cx,word ptr [81dh]
+06D6  8B 1E 1F 08 mov bx,word ptr [81fh]
+06DA  8B 16 21 08 mov dx,word ptr [821h]
+06DE  9F          lahf
+06DF  F6 C6 80    test dh,80h
+06E2  75 09       jne 6edh
+06E4  9E          sahf
+06E5  D0 D5       rcl ch,1h
+06E7  D1 D3       rcl bx,1h
+06E9  D1 D2       rcl dx,1h
+06EB  EB 0A       jmp 6f7h
+06ED  FE C1       inc cl
+06EF  75 06       jne 6f7h
+06F1  B0 01       mov al,1h
+06F3  B4 4C       mov ah,4ch
+06F5  CD 21       int 21h
+06F7  E9 EC FE    jmp 5e6h