فهرست منبع

runtime: MBF multiplication (remult)

TPSRC2 1532-1587 with testexp (TPSRC3 50-78) inlined.  Same block ABI as
real_add/real_sub: [BP+4] holds a then b; the result overwrites a; a is
AX/BX/DX and b CX/SI/DI.

testexp's reference version POPS ITS RETURN ADDRESS on underflow/overflow
to leave remult entirely.  That cannot survive being called from our
wrapper, so the two fault paths jump to this core's exits instead:
underflow returns zero, overflow leaves through TP3's error 1 (exit 1).

The multiply is the reference's shift-and-add over the five mantissa
bytes, with LAHF/SAHF carrying the guard bit across the normalisation
TEST.  Data slots for a's saved AX/BX/DX and b's CX/SI/DI (the low byte
of the CX slot is the exponent and is skipped, exactly as the original's
`INC DI' does).

Two jump bugs, both silent before the tests:
  * remult's early zero/return tests are more than 127 bytes from their
    targets, so Jcc's rel8 wrapped.  JccNear (inverse Jcc_s over an E9)
    and JmpNear are now used, and FixUp REFUSES a rel8 whose target is
    out of range instead of wrapping.
  * the first JccNear emitted the condition raw, so it jumped when the
    condition was FALSE: every product became zero.  The inverse is what
    makes the E9 run when the condition HOLDS.

rt_exec: ten real_mul cases against the measured table - 1*2, 3*5, 5*3,
1*1, 1000*1, -3*2, 42*1000, 32767*1, 0*5, -3*-2.  99/99 entries pass.
The driver gains two blocks and RT_BASE moves to 0x190 because the
runtime now runs into the test scaffold at 0x800.

Non-vacuity puts the raw condition back into JccNear and requires the
real_mul cases to go red.

The ladder is unchanged at 18267; rediv is the remaining half of this
step, then recmp/reint and the formatter.
Eric Streit 1 روز پیش
والد
کامیت
c92d2a842f

+ 1 - 0
shell/Runtime.def

@@ -56,6 +56,7 @@ CONST
    E_RealAdd = 22 ;         (* MBF add: [BP+4] is a 12-byte block holding a
                                then b, and the result overwrites a *)
    E_RealSub = 23 ;         (* ...and subtraction: a - b *)
+   E_RealMul = 24 ;         (* ...and multiplication: a * b *)
 
    (* 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

+ 190 - 5
shell/Runtime.mod

@@ -76,7 +76,13 @@ CONST
    D_RMANT = 32 ;     (* 2 bytes: the second operand's saved MSB *)
    D_RMANT1 = 33 ;    (* its high byte, mixed with operand 1's sign *)
    D_CVDEC = 34 ;     (* 1 byte: the second exponent during alignment *)
-   D_END   = 35 ;     (* the block is padded to here *)
+   D_RMUL11 = 35 ;    (* a's saved AX; D_RMUL11+1 is its high byte (AH) *)
+   D_RMUL12 = 37 ;    (* a's saved BX *)
+   D_RMUL13 = 39 ;    (* a's saved DX *)
+   D_RMUL21 = 41 ;    (* b's saved CX (low byte is the exponent, skipped) *)
+   D_RMUL22 = 43 ;    (* b's saved SI *)
+   D_RMUL23 = 45 ;    (* b's saved DI *)
+   D_END   = 47 ;     (* the block is padded to here *)
 
    (* THE LOAD BIAS.  Everything above is an offset into the image as this
       compiler numbers it: the entry JMP is at image 0.  But a DOS .COM is
@@ -133,7 +139,7 @@ VAR
    dataAt : CARDINAL ;
    rtBase : CARDINAL ;
    built  : BOOLEAN ;
-   entNm  : ARRAY [0..23] OF ARRAY [0..MaxNm] OF CHAR ;
+   entNm  : ARRAY [0..24] OF ARRAY [0..MaxNm] OF CHAR ;
 
 (* ---------------------------------------------------------------- *)
 (*  name helpers                                                     *)
@@ -620,6 +626,41 @@ PROCEDURE Stc ; BEGIN B (0F9H) END Stc ;                    (* STC *)
 PROCEDURE CmpAlCl ; BEGIN B (38H) ; B (0C8H) END CmpAlCl ;  (* CMP AL,CL *)
 PROCEDURE CmpCl0 ; BEGIN B (80H) ; B (0F9H) ; B (0) END CmpCl0 ; (* 80 F9 00 *)
 PROCEDURE MovBhBl ; BEGIN B (88H) ; B (0DFH) END MovBhBl ;  (* BH:=BL *)
+PROCEDURE CmpCh0 ; BEGIN B (80H) ; B (0FDH) ; B (0) END CmpCh0 ;
+PROCEDURE AddAlCl ; BEGIN B (00H) ; B (0C8H) END AddAlCl ;  (* AL:=AL+CL *)
+PROCEDURE AddAlImm (v : CARDINAL) ;
+BEGIN B (04H) ; B (v MOD 256) END AddAlImm ;
+PROCEDURE MovSiImm (v : CARDINAL) ;
+BEGIN B (0BEH) ; W (v) END MovSiImm ;
+PROCEDURE RcrCh1 ; BEGIN B (0D0H) ; B (0DDH) END RcrCh1 ;   (* RCR CH,1 *)
+PROCEDURE RclCh1 ; BEGIN B (0D0H) ; B (0D5H) END RclCh1 ;   (* RCL CH,1 *)
+PROCEDURE Lahf ; BEGIN B (9FH) END Lahf ;
+PROCEDURE Sahf ; BEGIN B (9EH) END Sahf ;
+PROCEDURE XorCxDi ; BEGIN B (31H) ; B (0F9H) END XorCxDi ;   (* CX:=CX XOR DI *)
+PROCEDURE NotCh ; BEGIN B (0F6H) ; B (0D5H) END NotCh ;     (* NOT CH *)
+PROCEDURE AndChImm (v : CARDINAL) ;
+BEGIN B (80H) ; B (0E5H) ; B (v MOD 256) END AndChImm ;
+PROCEDURE MovDiData (delta : CARDINAL) ;
+BEGIN B (0BFH) ; Dd (delta) END MovDiData ;
+PROCEDURE LdChDiOff ; BEGIN B (8AH) ; B (2DH) END LdChDiOff ; (* CH:=[DI] *)
+PROCEDURE AddAhData (delta : CARDINAL) ;
+BEGIN B (02H) ; B (26H) ; Dd (delta) END AddAhData ;        (* ADD AH,[Vx] *)
+PROCEDURE AdcBxData (delta : CARDINAL) ;
+BEGIN B (13H) ; B (1EH) ; Dd (delta) END AdcBxData ;        (* ADC BX,[Vx] *)
+PROCEDURE AdcDxData (delta : CARDINAL) ;
+BEGIN B (13H) ; B (16H) ; Dd (delta) END AdcDxData ;        (* ADC DX,[Vx] *)
+PROCEDURE StDataCh (delta : CARDINAL) ;
+BEGIN B (88H) ; B (2EH) ; Dd (delta) END StDataCh ;
+PROCEDURE StDataCx (delta : CARDINAL) ;
+BEGIN B (89H) ; B (0EH) ; Dd (delta) END StDataCx ;
+PROCEDURE StDataSi (delta : CARDINAL) ;
+BEGIN B (89H) ; B (36H) ; Dd (delta) END StDataSi ;
+PROCEDURE StDataAx (delta : CARDINAL) ;
+BEGIN B (0A3H) ; Dd (delta) END StDataAx ;
+PROCEDURE StDataBx (delta : CARDINAL) ;
+BEGIN B (89H) ; B (1EH) ; Dd (delta) END StDataBx ;
+PROCEDURE StDataDx (delta : CARDINAL) ;
+BEGIN B (89H) ; B (16H) ; Dd (delta) END StDataDx ;
 PROCEDURE SubAhCh ; BEGIN B (28H) ; B (0ECH) END SubAhCh ;  (* AH:=AH-CH *)
 PROCEDURE MovClImm (v : CARDINAL) ;
 BEGIN B (0B1H) ; B (v MOD 256) END MovClImm ;
@@ -678,6 +719,23 @@ BEGIN B (8BH) ; B (75H) ; B (off MOD 256) END LdSiDiOff ;
 PROCEDURE LdDiDiOff (off : CARDINAL) ;
 BEGIN B (8BH) ; B (7DH) ; B (off MOD 256) END LdDiDiOff ;
 PROCEDURE PushBp4 ; BEGIN B (0FFH) ; B (76H) ; B (4) END PushBp4 ; (* PUSH [BP+4] *)
+PROCEDURE JccNear (code : CARDINAL ; nm : ARRAY OF CHAR) ;
+(* A conditional near jump: the 8086 has no Jcc rel16, so an INVERSE Jcc_s
+   +3 over an E9 rel16.  The inverse is what makes the E9 run when `code'
+   HOLDS; a raw Jcc here would jump when it does NOT (remult's zero test did
+   exactly that and multiplied everything to zero).  Use this when the target
+   is more than 127 bytes away; Jcc's rel8 wraps silently otherwise (the
+   FixUp guard below now refuses that). *)
+BEGIN
+   IF (code MOD 2) = 0 THEN
+      B (code + 1)
+   ELSE
+      B (code - 1)
+   END ;
+   B (3) ; B (0E9H) ; AddFix (1, rpos, nm, 0) ; W (0)
+END JccNear ;
+PROCEDURE JmpNear (nm : ARRAY OF CHAR) ;
+BEGIN B (0E9H) ; AddFix (1, rpos, nm, 0) ; W (0) END JmpNear ;
 PROCEDURE Call (nm : ARRAY OF CHAR) ;
 BEGIN B (0E8H) ; AddFix (1, rpos, nm, 0) ; W (0) END Call ;
 PROCEDURE StVxBx   (delta : CARDINAL ) ;
@@ -1714,6 +1772,100 @@ BEGIN
    RetR
 END EmitRealAddSub ;
 
+PROCEDURE EmitRealMul ;
+(* remult, TPSRC2 1532-1587, with testexp (TPSRC3 50-78) inlined.
+
+   ABI and register convention are real_add's: [BP+4] is a 12-byte block
+   holding a then b; the result overwrites a; a is AX/BX/DX and b CX/SI/DI.
+
+   testexp is inlined because the reference's version is called and, on
+   underflow or overflow, POPS ITS RETURN ADDRESS to leave remult entirely.
+   That trick cannot survive being called from our wrapper, so the two
+   exponent fault paths jump to this core's zero/error exits instead.
+
+   Multiplication is the reference's shift-and-add over the five mantissa
+   bytes: for each byte, if it is zero the 40-bit result is shifted right
+   eight; otherwise each of its eight bits conditionally adds a's mantissa
+   and shifts the result one.  LAHF/SAHF carry the guard bit across the
+   normalisation TEST.  Overflow leaves through TP3's error 1 (exit code 1);
+   underflow returns zero. *)
+BEGIN
+   M ("real_mul") ;
+   PushBp ; MovBpSp ;
+   PushBx ; PushDx ; PushSi ; PushDi ;
+   PushBp4 ;
+   MovSiBp4 ;
+   LdAxSi ;
+   LdCxSiOff (2) ; LdDxSiOff (4) ;
+   MovBxCx ;
+   MovDiSi ;
+   LdCxDiOff (6) ; LdSiDiOff (8) ; LdDiDiOff (10) ;
+   Call ("rm_core") ;
+   PopDi ;
+   StDiAx ; StDiOffBx (2) ; StDiOffDx (4) ;
+   PopDi ; PopSi ; PopDx ; PopBx ;
+   MovSpBp ; PopBp ; RetR ;
+
+   M ("rm_core") ;
+   CmpCl0 ; JccNear (74H, "rm_zero") ;
+   CmpAl0 ; JccNear (74H, "rm_ret") ;
+   AddAlCl ;
+   Jb8 ("rm_ovr1") ;
+   AddAlImm (80H) ;
+   Jb8 ("rm_ok") ;
+   JmpNear ("rm_zero") ;                 (* underflow *)
+   M ("rm_ovr1") ;
+   AddAlImm (80H) ;
+   Jae8 ("rm_ok") ;
+   (* overflow: TP3 error 1 *)
+   MovAlD (1) ; MovAh (4CH) ; Int21 ;
+   M ("rm_ok") ;
+   (* testexp's tail *)
+   StDataCx (D_RMUL21) ;
+   MovCxDx ; XorCxDi ; NotCh ; AndChImm (80H) ; StDataCh (D_RESAVE) ;
+   OrDhImm (80H) ; OrDiImm (8000H) ;
+   StDataSi (D_RMUL22) ; StDataDi (D_RMUL23) ;
+   (* remult *)
+   StDataAx (D_RMUL11) ; StDataBx (D_RMUL12) ; StDataDx (D_RMUL13) ;
+   XorAhAh ; XorBxBx ; XorDxDx ;
+   MovDiData (D_RMUL21) ;
+   MovClImm (5) ;
+   M ("rm_byt") ;
+   IncDi ;
+   LdChDiOff ;
+   CmpCh0 ; Jne8 ("rm_domul") ;
+   MovAhBl ; MovBlBh ; MovBhDl ; MovDlDh ; XorDhDh ;
+   Jmp8 ("rm_nxt") ;
+   M ("rm_domul") ;
+   MovSiImm (8) ;
+   M ("rm_mul") ;
+   RcrCh1 ;
+   Jae8 ("rm_bit0") ;
+   AddAhData (D_RMUL11 + 1) ;
+   AdcBxData (D_RMUL12) ;
+   AdcDxData (D_RMUL13) ;
+   M ("rm_bit0") ;
+   RcrDx1 ; RcrBx1 ; RcrAh1 ;
+   DecSi ; Jne8 ("rm_mul") ;
+   M ("rm_nxt") ;
+   DecCl ; Jne8 ("rm_byt") ;
+   XchgAxCx ;
+   Lahf ;
+   TestDhImm (80H) ; Jne8 ("rm_noadj") ;
+   Sahf ;
+   RclCh1 ; RclBx1 ; RclDx1 ;
+   CmpCl0 ; Je8 ("rm_noadj") ;
+   DecCl ;
+   M ("rm_noadj") ;
+   XchgAxCx ;
+   XorDhData (D_RESAVE) ;
+   CmpAl0 ; Jne8 ("rm_ret") ;
+   M ("rm_zero") ;
+   XorAxAx ; XorBxBx ; XorDxDx ;
+   M ("rm_ret") ;
+   RetR
+END EmitRealMul ;
+
 PROCEDURE EmitData ;
 (* The runtime's data block.  The D_ constants name the offsets in it and are
    ASSERTED against what is emitted here, three ways: the starting offset of
@@ -1762,6 +1914,30 @@ BEGIN
       HALT
    END ;
    B (0) ;
+   IF dataAt + D_RMUL11 # rpos THEN
+      HALT
+   END ;
+   B (0) ; B (0) ;
+   IF dataAt + D_RMUL12 # rpos THEN
+      HALT
+   END ;
+   B (0) ; B (0) ;
+   IF dataAt + D_RMUL13 # rpos THEN
+      HALT
+   END ;
+   B (0) ; B (0) ;
+   IF dataAt + D_RMUL21 # rpos THEN
+      HALT
+   END ;
+   B (0) ; B (0) ;
+   IF dataAt + D_RMUL22 # rpos THEN
+      HALT
+   END ;
+   B (0) ; B (0) ;
+   IF dataAt + D_RMUL23 # rpos THEN
+      HALT
+   END ;
+   B (0) ; B (0) ;
    WHILE rpos < dataAt + D_END DO
       B (0)
    END ;
@@ -1789,7 +1965,15 @@ BEGIN
          t := LblOff (fix [i].nm) ;
          IF fix [i].kind = 0 THEN
             (* rel8 is measured from the end of the instruction, i.e. one
-               byte past the displacement field *)
+               byte past the displacement field.  A target beyond +127/-128
+               would wrap silently and send the machine into the middle of
+               an instruction; that happened in remult's early zero/return
+               jumps.  Refuse it. *)
+            IF (VAL (LONGINT, t) - VAL (LONGINT, fix [i].place + 1) < -128)
+               OR (VAL (LONGINT, t) - VAL (LONGINT, fix [i].place + 1) > 127)
+            THEN
+               HALT
+            END ;
             rel := (t + 100H - (fix [i].place + 1)) MOD 100H ;
             rt [fix [i].place] := VAL (BYTE, rel)
          ELSE
@@ -1822,7 +2006,7 @@ BEGIN
    EmitRdChar ; EmitRdBool ; EmitRdLn ;
    EmitGetCh ; EmitUnGetCh ;
    EmitRdStr ; EmitStrStore ; EmitCmpStr ; EmitStrCat ;
-   EmitRealFromInt ; EmitRealAddSub ;
+   EmitRealFromInt ; EmitRealAddSub ; EmitRealMul ;
    EmitData ;
    FixUp ;
    SetStr (entNm [0], "initmem") ;
@@ -1849,6 +2033,7 @@ BEGIN
    SetStr (entNm [21], "real_from_int") ;
    SetStr (entNm [22], "real_add") ;
    SetStr (entNm [23], "real_sub") ;
+   SetStr (entNm [24], "real_mul") ;
    built := TRUE
 END RT_Build ;
 
@@ -1876,7 +2061,7 @@ BEGIN
    IF NOT built THEN
       RT_Build (0)
    END ;
-   IF i > 23 THEN
+   IF i > 24 THEN
       RETURN 0
    END ;
    RETURN rtBase + LblOff (entNm [i])

+ 4 - 3
shell/tests/RtProbe.mod

@@ -108,7 +108,7 @@ END PENT ;
 
 PROCEDURE Main ;
 VAR i, n, base : CARDINAL ;
-    names : ARRAY [0..23] OF ARRAY [0..15] OF CHAR ;
+    names : ARRAY [0..24] OF ARRAY [0..15] OF CHAR ;
 BEGIN
    base := GetBase () ;
    RT_Build (base) ;
@@ -121,7 +121,7 @@ BEGIN
    PCARD (RT_Size ()) ; PS (" bytes") ; NL ;
    PS ("code ends at ") ; PCARD (RT_CodeEnd ()) ; NL ;
    i := 0 ;
-   WHILE i <= 23 DO
+   WHILE i <= 24 DO
       names [i] := "" ;
       INC (i)
    END ;
@@ -136,8 +136,9 @@ BEGIN
    names [21] := "real_from_int" ;
    names [22] := "real_add" ;
    names [23] := "real_sub" ;
+   names [24] := "real_mul" ;
    i := 0 ;
-   WHILE i <= 23 DO
+   WHILE i <= 24 DO
       PENT (i, names [i]) ;
       INC (i)
    END ;

+ 10 - 0
shell/tests/audit_helpers.py

@@ -118,6 +118,13 @@ NON_ONE_LINE = {
         "SubClImm": COMP, "TestDhImm": COMP, "TestDataImm": COMP,
         "XorDhData": COMP, "XorDiData": COMP, "XorDataDh": COMP,
         "XorDataImm": COMP, "PushBp4": COMP,
+        # remult/testexp helpers.  The multiplication is pinned by rt_exec's
+        # ten real_mul cases, including zero, cancellation and signs.
+        "AdcBxData": COMP, "AdcDxData": COMP, "AddAhData": COMP,
+        "AddAlImm": COMP, "AndChImm": COMP, "JccNear": COMP,
+        "JmpNear": COMP, "MovDiData": COMP, "MovSiImm": COMP,
+        "StDataAx": COMP, "StDataBx": COMP, "StDataCh": COMP,
+        "StDataCx": COMP, "StDataDx": COMP, "StDataSi": COMP,
         "MovBxImm": PARAM, "MovCxImm": PARAM, "MovDxImm": PARAM,
         "MovDl": PARAM, "MovAlD": PARAM, "MovAh": PARAM,
         "SubAl": PARAM, "CmpAl": PARAM, "AddDl": PARAM, "J8": COMP,
@@ -397,6 +404,9 @@ PATTERNS = [
     (re.compile(r"^(Shl|Shr|Rcl|Rcr|Rol|Ror|Sar)(%s)1$" % _ALT),
      None, ["r:%(2)s", "i:1"], {0xD0, 0xD1}),
     (re.compile(r"^Stc$"), "stc", [], {0xF9}),
+    (re.compile(r"^Lahf$"), "lahf", [], {0x9F}),
+    (re.compile(r"^Sahf$"), "sahf", [], {0x9E}),
+    (re.compile(r"^LdChDiOff$"), "mov", ["r:Ch", "m:Di"], {0x8A}),
     (re.compile(r"^PushBp4$"), "push", ["m:Bp+4"], {0xFF}),
     (re.compile(r"^Adc(%s)(%s)$" % (_ALT16, _ALT16)),
      "adc", ["r:%(1)s", "r:%(2)s"], {0x11, 0x13}),

+ 1 - 0
shell/tests/check_runtime.py

@@ -135,6 +135,7 @@ GOLDEN = {
     # real_add/real_sub share a frame and the readd core.
     "real_add": "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",
     # 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
     # every write of a character printed whatever the *last* character read

+ 8 - 1
shell/tests/exec/rtdrv.s

@@ -91,7 +91,7 @@
 # above 0x0800 so that a runtime which grew by a few hundred bytes would not
 # silently run into the test scaffolding.  rt_exec.py asserts
 # RT_BASE + blob size <= HDR, so the bound is a checked one.
-	.set	RT_BASE, 0x0200
+	.set	RT_BASE, 0x0190
 	.set	HDR, 0x0800
 	.set	DATA, 0x0810
 	.set	DLEN, 32			# bytes of data area for initmem to clear
@@ -120,6 +120,8 @@
 	.set	R_BLK6, 0x0980
 	.set	R_BLK7, 0x0990
 	.set	R_BLK8, 0x09A0
+	.set	R_BLK9, 0x09B0
+	.set	R_BLK10, 0x09C0
 
 	.code16
 	.text
@@ -436,3 +438,8 @@ HDR:
 	.byte	0x86, 0x00, 0x00, 0x00, 0x00, 0x28, 0x8A, 0x00, 0x00, 0x00, 0x00, 0x7A
 	.org	R_BLK8
 	.byte	0x8F, 0x00, 0x00, 0x00, 0xFE, 0x7F, 0x81, 0x00, 0x00, 0x00, 0x00, 0x00
+
+	.org	R_BLK9
+	.byte	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x83, 0x00, 0x00, 0x00, 0x00, 0x20
+	.org	R_BLK10
+	.byte	0x82, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x82, 0x00, 0x00, 0x00, 0x00, 0x80

+ 31 - 0
shell/tests/nonvacuity.sh

@@ -1391,6 +1391,37 @@ fi
 cp "$SAVED" Runtime.mod
 "$GM2" -fiso -c Runtime.mod >/dev/null 2>&1
 
+# --- JccNear jumps when the condition HOLDS ------------------------------
+# The near form is an INVERSE Jcc over an E9.  Putting the condition back
+# unchanged makes remult's `b = 0 ?' test jump when b is NON-zero, so every
+# product becomes zero.  The rt_exec real_mul cases compare exact bytes.
+cp "$SAVED" Runtime.mod
+if python3 - <<'PYX'
+p = 'Runtime.mod'
+s = open(p).read()
+old = """   IF (code MOD 2) = 0 THEN
+      B (code + 1)
+   ELSE
+      B (code - 1)
+   END ;"""
+assert s.count(old) == 1, 'the JccNear inverse found %d times' % s.count(old)
+open(p, 'w').write(s.replace(old, '   B (code) ;'))
+PYX
+then
+    if "$GM2" -fiso -c Runtime.mod >/dev/null 2>&1; then
+        expect_red "real_mul red when JccNear uses the raw condition" \
+            "real_mul" python3 tests/rt_exec.py
+    else
+        echo "  FAIL: the runtime would not rebuild with the raw JccNear"
+        fail=$((fail + 1))
+    fi
+else
+    echo "  BROKEN CASE: the JccNear-inverse mutation did not apply"
+    fail=$((fail + 1))
+fi
+cp "$SAVED" Runtime.mod
+"$GM2" -fiso -c Runtime.mod >/dev/null 2>&1
+
 # --- the compiler's arms --------------------------------------------------
 # 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

+ 7 - 3
shell/tests/rt_exec.py

@@ -61,7 +61,7 @@ SHELL = os.path.dirname(HERE)
 # a known offset and Python needs to know where the driver thinks it is, so the
 # 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.
-RT_BASE = 0x0200
+RT_BASE = 0x0190
 HDR = 0x0800
 DLEN = 32
 DATA = 0x0810
@@ -103,7 +103,7 @@ SOH, STX, ETX, EOT = 0x01, 0x02, 0x03, 0x04
 ENTS = ["initmem", "progend", "stackchk", "wrint", "wrchar", "wrbool",
         "wrreal", "wrln", "rdint", "rdchar", "rdbool", "rdln", "halt",
         "wrtinl", "rdbyte", "wrstr", "rdstr", "strstore", "cmpstr", "strcat",
-        "wrintw", "real_from_int", "real_add", "real_sub"]
+        "wrintw", "real_from_int", "real_add", "real_sub", "real_mul"]
 
 # A call slot's flags, as rtdrv.s reads them.
 F_STACK = 1     # the argument goes on the stack, popped by the caller
@@ -497,7 +497,7 @@ def build_cases():
     # 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.
     BLOCKS = [(1, 2), (3, 5), (5, 3), (1, 1), (1000, 1), (-3, 2),
-              (42, 1000), (32767, 1)]
+              (42, 1000), (32767, 1), (0, 5), (-3, -2)]
     for bi, (a, b) in enumerate(BLOCKS):
         blk = 0x0930 + 16 * bi
         add("real_add(%d,%d)" % (a, b),
@@ -508,6 +508,10 @@ def build_cases():
             [s("real_sub", blk + LOAD_BIAS)],
             dump=6, dumpbytes=mbf(a - b), dumpadr=blk,
             note="the measured MBF bytes, the reference's resub")
+        add("real_mul(%d,%d)" % (a, b),
+            [s("real_mul", blk + LOAD_BIAS)],
+            dump=6, dumpbytes=mbf(a * b), dumpadr=blk,
+            note="the measured MBF bytes, the reference's remult")
 
     add("wrchar('A')", [s("wrchar", ord("A"))], out=b"A")
     add("wrchar('!')", [s("wrchar", ord("!"))], out=b"!")

+ 126 - 22
shell/tests/runtime.golden

@@ -41,7 +41,7 @@
 0036  58          pop ax
 0037  F7 D8       neg ax
 0039  B9 0A 00    mov cx,0ah
-003C  BB 15 06    mov bx,615h
+003C  BB FE 06    mov bx,6feh
 003F  89 DE       mov si,bx
 0041  31 D2       xor dx,dx
 0043  F7 F1       div ax,cx
@@ -93,7 +93,7 @@
 00A2  58          pop ax
 00A3  F7 D8       neg ax
 00A5  B9 0A 00    mov cx,0ah
-00A8  BB 15 06    mov bx,615h
+00A8  BB FE 06    mov bx,6feh
 00AB  89 DE       mov si,bx
 00AD  31 D2       xor dx,dx
 00AF  F7 F1       div ax,cx
@@ -125,18 +125,18 @@
 00DE  83 7E 04 00 cmp word ptr [bp+4h],0h
 00E2  89 EC       mov sp,bp
 00E4  75 05       jne 0ebh
-00E6  BA 1A 06    mov dx,61ah
+00E6  BA 03 07    mov dx,703h
 00E9  EB 03       jmp 0eeh
-00EB  BA 15 06    mov dx,615h
+00EB  BA FE 06    mov dx,6feh
 00EE  B4 09       mov ah,9h
 00F0  CD 21       int 21h
 00F2  5D          pop bp
 00F3  C3          ret
-00F4  BA 23 06    mov dx,623h
+00F4  BA 0C 07    mov dx,70ch
 00F7  B4 09       mov ah,9h
 00F9  CD 21       int 21h
 00FB  C3          ret
-00FC  BA 20 06    mov dx,620h
+00FC  BA 09 07    mov dx,709h
 00FF  B4 09       mov ah,9h
 0101  CD 21       int 21h
 0103  C3          ret
@@ -303,12 +303,12 @@
 0217  EB EF       jmp 208h
 0219  58          pop ax
 021A  C3          ret
-021B  8B 1E 29 06 mov bx,word ptr [629h]
+021B  8B 1E 12 07 mov bx,word ptr [712h]
 021F  83 FB 00    cmp bx,0h
 0222  74 09       je 22dh
 0224  8A C3       mov al,bl
 0226  31 DB       xor bx,bx
-0228  89 1E 29 06 mov word ptr [629h],bx
+0228  89 1E 12 07 mov word ptr [712h],bx
 022C  C3          ret
 022D  B4 08       mov ah,8h
 022F  CD 21       int 21h
@@ -316,7 +316,7 @@
 0232  88 C2       mov dl,al
 0234  BB 01 00    mov bx,1h
 0237  8A DA       mov bl,dl
-0239  89 1E 29 06 mov word ptr [629h],bx
+0239  89 1E 12 07 mov word ptr [712h],bx
 023D  C3          ret
 023E  55          push bp
 023F  8B EC       mov bp,sp
@@ -541,7 +541,7 @@
 03BE  8B 4D 06    mov cx,word ptr [di+6h]
 03C1  8B 75 08    mov si,word ptr [di+8h]
 03C4  8B 7D 0A    mov di,word ptr [di+0ah]
-03C7  C7 06 2B 06 00 00 mov word ptr [62bh],0h
+03C7  C7 06 14 07 00 00 mov word ptr [714h],0h
 03CD  E8 4D 00    call 41dh
 03D0  5F          pop di
 03D1  89 05       mov word ptr [di],ax
@@ -570,7 +570,7 @@
 03FA  8B 4D 06    mov cx,word ptr [di+6h]
 03FD  8B 75 08    mov si,word ptr [di+8h]
 0400  8B 7D 0A    mov di,word ptr [di+0ah]
-0403  C7 06 2B 06 00 80 mov word ptr [62bh],8000h
+0403  C7 06 14 07 00 80 mov word ptr [714h],8000h
 0409  E8 11 00    call 41dh
 040C  5F          pop di
 040D  89 05       mov word ptr [di],ax
@@ -585,7 +585,7 @@
 041C  C3          ret
 041D  80 F9 00    cmp cl,0h
 0420  74 0E       je 430h
-0422  33 3E 2B 06 xor di,word ptr [62bh]
+0422  33 3E 14 07 xor di,word ptr [714h]
 0426  3C 00       cmp al,0h
 0428  75 07       jne 431h
 042A  89 C8       mov ax,cx
@@ -597,16 +597,16 @@
 0435  91          xchg ax,cx
 0436  87 F3       xchg bx,si
 0438  87 FA       xchg dx,di
-043A  88 0E 2F 06 mov byte ptr [62fh],cl
+043A  88 0E 18 07 mov byte ptr [718h],cl
 043E  28 C1       sub cl,al
 0440  80 F9 28    cmp cl,28h
 0443  72 06       jb 44bh
-0445  8A 0E 2F 06 mov cl,byte ptr [62fh]
+0445  8A 0E 18 07 mov cl,byte ptr [718h]
 0449  EB DF       jmp 42ah
-044B  89 3E 2B 06 mov word ptr [62bh],di
-044F  80 26 2C 06 80 and byte ptr [62ch],80h
-0454  89 3E 2D 06 mov word ptr [62dh],di
-0458  30 36 2E 06 xor byte ptr [62eh],dh
+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
 045C  81 CF 00 80 or di,8000h
 0460  80 CE 80    or dh,80h
 0463  80 F9 10    cmp cl,10h
@@ -631,8 +631,8 @@
 048E  D0 DC       rcr ah,1h
 0490  FE C9       dec cl
 0492  75 F6       jne 48ah
-0494  A0 2F 06    mov al,byte ptr [62fh]
-0497  F6 06 2E 06 80 test byte ptr [62eh],80h
+0494  A0 18 07    mov al,byte ptr [718h]
+0497  F6 06 17 07 80 test byte ptr [717h],80h
 049C  75 14       jne 4b2h
 049E  00 EC       add ah,ch
 04A0  11 F3       adc bx,si
@@ -652,7 +652,7 @@
 04BA  19 F3       sbb bx,si
 04BC  19 FA       sbb dx,di
 04BE  73 14       jnb 4d4h
-04C0  80 36 2C 06 80 xor byte ptr [62ch],80h
+04C0  80 36 15 07 80 xor byte ptr [715h],80h
 04C5  F6 D4       not ah
 04C7  F7 D3       not bx
 04C9  F7 D2       not dx
@@ -684,5 +684,109 @@
 0502  31 D2       xor dx,dx
 0504  C3          ret
 0505  80 E6 7F    and dh,7fh
-0508  32 36 2C 06 xor dh,byte ptr [62ch]
+0508  32 36 15 07 xor dh,byte ptr [715h]
 050C  C3          ret
+050D  55          push bp
+050E  8B EC       mov bp,sp
+0510  53          push bx
+0511  52          push dx
+0512  56          push si
+0513  57          push di
+0514  FF 76 04    push word ptr [bp+4h]
+0517  8B 76 04    mov si,word ptr [bp+4h]
+051A  8B 04       mov ax,word ptr [si]
+051C  8B 4C 02    mov cx,word ptr [si+2h]
+051F  8B 54 04    mov dx,word ptr [si+4h]
+0522  89 CB       mov bx,cx
+0524  8B FE       mov di,si
+0526  8B 4D 06    mov cx,word ptr [di+6h]
+0529  8B 75 08    mov si,word ptr [di+8h]
+052C  8B 7D 0A    mov di,word ptr [di+0ah]
+052F  E8 11 00    call 543h
+0532  5F          pop di
+0533  89 05       mov word ptr [di],ax
+0535  89 5D 02    mov word ptr [di+2h],bx
+0538  89 55 04    mov word ptr [di+4h],dx
+053B  5F          pop di
+053C  5E          pop si
+053D  5A          pop dx
+053E  5B          pop bx
+053F  89 EC       mov sp,bp
+0541  5D          pop bp
+0542  C3          ret
+0543  80 F9 00    cmp cl,0h
+0546  75 03       jne 54bh
+0548  E9 A4 00    jmp 5efh
+054B  3C 00       cmp al,0h
+054D  75 03       jne 552h
+054F  E9 A3 00    jmp 5f5h
+0552  00 C8       add al,cl
+0554  72 07       jb 55dh
+0556  04 80       add al,80h
+0558  72 0D       jb 567h
+055A  E9 92 00    jmp 5efh
+055D  04 80       add al,80h
+055F  73 06       jnb 567h
+0561  B0 01       mov al,1h
+0563  B4 4C       mov ah,4ch
+0565  CD 21       int 21h
+0567  89 0E 1F 07 mov word ptr [71fh],cx
+056B  8B CA       mov cx,dx
+056D  31 F9       xor cx,di
+056F  F6 D5       not ch
+0571  80 E5 80    and ch,80h
+0574  88 2E 15 07 mov byte ptr [715h],ch
+0578  80 CE 80    or dh,80h
+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
+0592  30 E4       xor ah,ah
+0594  31 DB       xor bx,bx
+0596  31 D2       xor dx,dx
+0598  BF 1F 07    mov di,71fh
+059B  B1 05       mov cl,5h
+059D  47          inc di
+059E  8A 2D       mov ch,byte ptr [di]
+05A0  80 FD 00    cmp ch,0h
+05A3  75 0C       jne 5b1h
+05A5  88 DC       mov ah,bl
+05A7  88 FB       mov bl,bh
+05A9  88 D7       mov bh,dl
+05AB  88 F2       mov dl,dh
+05AD  30 F6       xor dh,dh
+05AF  EB 1C       jmp 5cdh
+05B1  BE 08 00    mov si,8h
+05B4  D0 DD       rcr ch,1h
+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]
+05C4  D1 DA       rcr dx,1h
+05C6  D1 DB       rcr bx,1h
+05C8  D0 DC       rcr ah,1h
+05CA  4E          dec si
+05CB  75 E7       jne 5b4h
+05CD  FE C9       dec cl
+05CF  75 CC       jne 59dh
+05D1  91          xchg ax,cx
+05D2  9F          lahf
+05D3  F6 C6 80    test dh,80h
+05D6  75 0E       jne 5e6h
+05D8  9E          sahf
+05D9  D0 D5       rcl ch,1h
+05DB  D1 D3       rcl bx,1h
+05DD  D1 D2       rcl dx,1h
+05DF  80 F9 00    cmp cl,0h
+05E2  74 02       je 5e6h
+05E4  FE C9       dec cl
+05E6  91          xchg ax,cx
+05E7  32 36 15 07 xor dh,byte ptr [715h]
+05EB  3C 00       cmp al,0h
+05ED  75 06       jne 5f5h
+05EF  31 C0       xor ax,ax
+05F1  31 DB       xor bx,bx
+05F3  31 D2       xor dx,dx
+05F5  C3          ret