Kaynağa Gözat

calc: text Eof/Readln and integer Str (ladder 28074)

Text-file reads work byte by byte through INT 21h AH=3Fh: file_readln
terminates on LF/^Z/physical EOF, skips CR, truncates to the destination
string's capacity and leaves IOResult at 0.  file_eof compares the DOS current
position with the file size and also remembers a ^Z seen by the reader.

Str(integer, S) is lowered to the new int_fmt entry: it converts a signed
16-bit value to decimal and writes the counted string.  CALC's
Str(count,st) is this form; width/decimals for integers remain a later
increment.

The probe scaffold moved to HDR=0x1300 with its data block at 0x2110, because
the runtime is now 4248 bytes (the old 0x1100 HDR had two bytes left).  All
probe addresses moved by the same amount, so the driver and Python constants
still agree.

t94_textread (compile-only, no filesystem) covers Eof/Readln into a
pointer-indexed string; t95_strint executes positive, negative and zero
integer formatting under both qemu and Exec86.

The CALC ladder moves 27648 -> 28074; the next blocker is Val
string-to-integer conversion.

Verified: compile matrix 96/96, ladder 1/1, 87 .COM linked, 82 executed under
both qemu and Exec86, rt_exec 276/276, nonvacuity 121/121, run_all ALL PASS.
Eric Streit 5 gün önce
ebeveyn
işleme
e940a1d6db

+ 28 - 16
CALC-COMPILE.md

@@ -97,7 +97,7 @@ Current rung (measured today, normalised position):
 
 | position | blocker |
 |---|---|
-| **27648** | `Eof(H)` in `Help` — text-file end-of-file (`ERR 41`) |
+| **28074** | `Val(Buffer^[0],EndOfFile,ErrorResult)` — string-to-integer (`ERR 41`) |
 
 Rungs behind it (now passed):
 
@@ -139,7 +139,9 @@ Rungs ahead:
 | 25674 | text-file output (`Writeln(MCFile)`) - DONE |
 | 26066 | `Str(Value:FW:DEC,P)` - real-to-string formatting - DONE |
 | 26924 | `Buffer : ^Pages` - pointer type - DONE |
-| 27648 | `Eof(H)` / text-file reads |
+| 27648 | text-file `Eof`/`Readln` - DONE |
+| 27759 | `Str(count,st)` - integer Str - DONE |
+| 28074 | `Val(Buffer^[0],...)` - string-to-integer |
 
 Corrections the measurements force, worth stating plainly because the stage list
 below was written before them:
@@ -348,7 +350,7 @@ recipe above regenerates them, and the numbers are what this document keeps.
    grow into the other. CALC's code is **16,560 bytes**, which the old fixed
    4 KiB window could not emit; that was a port artefact, not a TP3 limit.
 2. **`MaxCode = 24,000` is not the binding constraint for the compile goal.**
-   16,560 + 3,950 (our current runtime) = 20,510, comfortably inside 24,000.
+   16,560 + 4,248 (our current runtime) = 20,808, comfortably inside 24,000.
    The old `dataBase` alone had to move; `t43_codewindow` was the fixture that
    policed it and has been re-baselined (§3.2).
 3. **The §3 data budget is confirmed, not inferred.** Reported data is
@@ -361,7 +363,7 @@ recipe above regenerates them, and the numbers are what this document keeps.
    **DS size `0315h` (12,624 B)**, and **heap/stack `0400h` (16,384 B)**, with
    `A000h` as the maximum (640 KiB, in paragraphs). A `.COM` still uses
    separate CS/DS segments; the original proves it.
-5. **The runtime is 11,341 bytes** in the original. Ours is 3,950 B. It
+5. **The runtime is 11,341 bytes** in the original. Ours is 4,248 B. It
    explains where the original's fixed `pc := $2D7C` / `dc := $0240` came
    from, and why `TPSRC7:81-82` looks the way it does.
 
@@ -428,7 +430,7 @@ inline initmem    mode 0006, CS 0813, DS 11D7,
 
 The file is runtime + code, exactly the shape we now emit; the data is in the
 separate DS described by the inline parameters. Our CALC image will be smaller
-in runtime (3,950 B instead of 11,341 B) but has the same code-only, high-data
+in runtime (4,248 B instead of 11,341 B) but has the same code-only, high-data
 shape. The ladder moved **20,912 → 22,253** on this change; the next blocker is
 not layout but the untyped `file` declaration; that is fixed in the next rung.
 
@@ -461,9 +463,10 @@ assignment, string fields through DI, REAL constants, UpCase, run-time set
 membership, string fields in WRITE, real output, run-time set algebra,
 `Succ`/`Pred`, the original memory layout, the untyped file type, the
 file control-block operations, VAR string parameters, `Chr`, typed-file
-block I/O, text-file output, `Str`, and pointer types with `New`/dereference). The
-ladder has moved from the first typed constant at 7,791 to **27,648**, where
-`Eof(H)` asks for text-file end-of-file.
+block I/O, text-file output, `Str`, pointer types with `New`/dereference,
+text `Eof`/`Readln`, and integer `Str`). The
+ladder has moved from the first typed constant at 7,791 to **28,074**, where
+`Val(Buffer^[0],EndOfFile,ErrorResult)` asks for string-to-integer conversion.
 
 The rung commits and their tags, in order (each is one rung with its own
 fixture, red proof, and — where the harness allows — execution under qemu and
@@ -505,7 +508,8 @@ Exec86):
 | `0859a3b` | `v-TP3-CALC-FILEIO` | `ERR 102 25674` (text-file output) |
 | `93d2ed4` | `v-TP3-CALC-TEXTOUT` | `ERR 41 26066` (`Str`) |
 | `38b6184` | `v-TP3-CALC-STR` | `ERR 30 26924` (pointer type) |
-| *(this commit)* | `v-TP3-CALC-POINTER` | **`ERR 41 27648`** (`Eof`) |
+| `1aed9cd` | `v-TP3-CALC-POINTER` | `ERR 41 27648` (`Eof`) |
+| *(this commit)* | `v-TP3-CALC-TEXTREAD` | **`ERR 41 28074`** (`Val`) |
 
 - **Code HEAD** is the layout rung (`v-TP3-CALC-LAYOUT`).  Nothing is pushed.
   The terminal-config work (`v-TP3-TERMCFG`) and the editor key map
@@ -551,6 +555,13 @@ Exec86):
   parameter slot holds the caller's address; assignment, `Read`, `Length`,
   `writeln`, concatenation, comparison and `x[i]` all go through that address.
   `Chr(n)` folds or loads an ordinal and yields a CHAR.
+- **Text `Eof`/`Readln` and integer `Str` are landed** (`t94_textread`,
+  compile-only; `t95_strint`, executed).  `file_eof` compares the DOS current
+  position with the size (and remembers ^Z from the text reader); `file_readln`
+  reads one line byte-by-byte, skips CR, terminates on LF/^Z/EOF, and truncates
+  to the destination's capacity.  `int_fmt` converts a signed integer to a
+  counted decimal string.  The probe scaffold moved to HDR=0x1300 and its data
+  block to 0x2110 to make room; runtime is 4,248 bytes.
 - **Pointer types, `New`/`Dispose`, and dereference are landed
   (`t93_pointer`).**  A pointer is one word; its `elem` holds the pointee TYPE
   symbol.  `Buffer^` loads the pointer into DI and hands the pointee's
@@ -642,7 +653,7 @@ Exec86):
   `ERR 1 22253`, terminal config **4/4**, 78 `.COM` linked and **76 executed
   under both qemu and Exec86** (`t64_arrays` remains compile-only because it
   has no `.out`).  `tests/nonvacuity.sh`: **121 ok, 0 failed**.  The runtime is
-  3,950 bytes (wrintw, real_from_int, real_add, real_sub, real_mul, real_div,
+  4,248 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
@@ -1148,11 +1159,12 @@ under qemu and Exec86, and `rt_exec` pins the name copy.
 
 Typed-file block I/O (`write`/`read` with a `TFile`) is done (`t90_fileio`)
 and TEXT file output is done (`t91_textout`), both compile-only because the
-harness has no filesystem.  `Str` real formatting is done (`t92_strreal`) and
-pointer types with `New`/`Dispose`/dereference are done (`t93_pointer`).  The
-next ladder blocker is `Eof(H)` and text `Readln(H, ...)`, which need
-text-mode newline/`^Z` semantics; `Val` is still open.  The runtime is 3,950
-bytes, only 2 bytes below the probe HDR, so that work must move the scaffold.
+harness has no filesystem.  `Str` real formatting is done (`t92_strreal`),
+pointer types with `New`/`Dispose`/dereference are done (`t93_pointer`), and
+text `Eof`/`Readln` plus integer `Str` are done (`t94_textread`/`t95_strint`).
+The next ladder blocker is `Val` string-to-integer conversion.  The probe
+scaffold has been moved to HDR=0x1300 / data 0x2110; the runtime is 4,248
+bytes and now has room for the remaining work.
 
 **Stage 14 — the CRT identifiers.** `GotoXY` (25), `LowVideo`/`NormVideo`
 (16 + 16), `ClrEol` (10), `ClrScr` (6), `KeyPressed` (3), `Delay` (1),
@@ -1196,7 +1208,7 @@ remaining run-time capacity note.
 | limit | value | CALC needs | verdict |
 |---|---|---|---|
 | `TextLimit` (source buffer) | 62,903 | `CALC.PAS` + `CALC.INC`, normalised = **62,415** | **488 bytes of slack** |
-| `MaxCode` | 24,000 | 16,560 B program + 3,950 B runtime = **20,510 B** | **OK, 3,490 B spare** (§3.2) |
+| `MaxCode` | 24,000 | 16,560 B program + 4,248 B runtime = **20,808 B** | **OK, 3,192 B spare** (§3.2) |
 | code window | `CodeMax = 6F00h`, capped by `MaxCode` | 20,227 B | **OK**; no data gap (§3.2) |
 | data area | fixed image `8000h`, zeroed by `initmem` | **12,032 B** (measured, §3.1) | **OK for compile**; see the run-time cargo note (§3.2) |
 | stack | 16,384 min / 655,360 max | 16,384 min | matches the original's `minstk`/`maxstk` |

+ 3 - 3
SUMMARY.md

@@ -2044,7 +2044,7 @@ the compiler *emitting* a 16,560-byte program). The ratchet and front-end
 features through **file control-block operations and the original memory
 layout** are landed: the ladder (`tests/calc_ladder.sh` +
 `tests/fixtures/calc_ladder.tsv`, run by `run_all.sh`; CALC.PAS now stops at
-`ERR 41` at pos 27648, `Eof(H)` in Help), the `{$I}` include,
+`ERR 41` at pos 28074, `Val(Buffer^[0],...)` in Help), the `{$I}` include,
 `^X`/`#nn`, scalar typed constants, sets, enums, records (CellRec = 80),
 subranges, arrays, element/field access, file types, string value parameters,
 `Length`, the CRT identifiers (`ClrScr`/`GotoXY`/`ClrEol`/`LowVideo`/
@@ -2062,8 +2062,8 @@ type (`t87`), file control-block operations (`t88`: `Assign`/`Reset`/
 `Rewrite`/`Close`/`IoResult`; data I/O is still refused), and VAR string
 parameters plus `Chr` (`t89`), typed-file block I/O (`t90`, compile-only), and
 text-file output (`t91`, compile-only), `Str` real formatting (`t92`), and
-pointer types with `New`/`Dispose`/dereference (`t93`). The next rung is text
-`Eof`/`Readln`. The runtime is 3,907 bytes / 39 entries and its probe
+pointer types with `New`/`Dispose`/dereference (`t93`), text `Eof`/`Readln`
+(`t94`), and integer `Str` (`t95`). The next rung is `Val` string-to-integer. The runtime is 3,907 bytes / 39 entries and its probe
 scaffold is nearly full, so the next runtime addition must move HDR. Items 1-4
 below are independent of both tracks.
 

+ 82 - 3
shell/Compiler.mod

@@ -141,7 +141,7 @@ CONST
       next file increment. *)
    BI_Assign = 16 ; BI_Reset = 17 ; BI_Rewrite = 18 ;
    BI_Close = 19 ; BI_IoResult = 20 ; BI_Chr = 21 ; BI_Str = 22 ;
-   BI_New = 23 ; BI_Dispose = 24 ;
+   BI_New = 23 ; BI_Dispose = 24 ; BI_Eof = 25 ;
    (* the sub-codes EmCrtSeq takes *)
    CrtClr = 0 ; CrtDl = 1 ; CrtDh = 2 ; CrtCaret = 3 ; CrtEol = 4 ;
    CrtLow = 5 ; CrtNorm = 6 ; CrtDelay = 7 ; CrtKey = 8 ;
@@ -408,6 +408,9 @@ VAR
    TU_IoResult    : CARDINAL ;
    TU_IoStore     : CARDINAL ;  (* save AX as the last I/O status *)
    TU_HeapNew     : CARDINAL ;  (* bump allocation for New *)
+   TU_FileEof     : CARDINAL ;  (* text-file end of file *)
+   TU_FileReadln  : CARDINAL ;  (* text-file line read *)
+   TU_IntFmt      : CARDINAL ;  (* integer -> counted string *)
    TU_CmpStr   : CARDINAL ;  (* string comparison; two addresses on the stack,
                                 signed -1/0/+1 in AX *)
    TU_StrCat   : CARDINAL ;  (* string concatenation; dest and source addresses
@@ -4112,6 +4115,31 @@ BEGIN
       r.cls := TChar ;
       r.sz := 1 ;
       RETURN
+   ELSIF (symtab [idx].tag = KBuiltin) AND (symtab [idx].cls = BI_Eof) THEN
+      (* Eof(F): text/typed-file end of file.  The runtime compares the DOS
+         current position with the file size and also remembers a ^Z seen by
+         the text reader. *)
+      IF NOT MatchDelim ('(') THEN
+         Err (ENoSemi) ;
+         RETURN
+      END ;
+      ParseExpr (r) ;
+      IF OK () THEN
+         IF (r.kind = 1) AND
+            ((r.cls = TText) OR (r.cls = TFile)) THEN
+            EmPushVarAddr (symtab [r.idx].local,
+                           (symtab [r.idx].off + r.boff) MOD 10000H) ;
+            DropC (EmCall (TU_FileEof)) ;
+            EmAddSp (2) ;
+            r.kind := 2 ;
+            r.cls := TBool ;
+            r.chr := FALSE
+         ELSE
+            Err (ETypeErr)
+         END
+      END ;
+      ExpectDelim (')', ENoSemi) ;
+      RETURN
    ELSIF (symtab [idx].tag = KBuiltin) AND (symtab [idx].cls = BI_IoResult) THEN
       (* IOResult: the last file operation's DOS status; reading it clears the
          slot in the runtime.  It is a no-argument function. *)
@@ -5123,6 +5151,32 @@ BEGIN
          RETURN
       END ;
       ParseExpr (arg) ;
+      IF OK () AND (arg.cls = TScalar) THEN
+         (* Str(integer, S): no width formatting here; TP3's default width is
+            zero, and CALC uses `Str(count,st)`.  A colon would ask for a field
+            width, which is a separate increment. *)
+         IF MatchDelim (':') THEN
+            Err (ENoLib) ;
+            RETURN
+         END ;
+         LoadAtom (arg) ;
+         EmPushAx () ;                    (* value at [BP+6] *)
+         IF NOT MatchDelim (',') THEN
+            Err (ENoSemi) ;
+            RETURN
+         END ;
+         ParseExpr (dummy) ;
+         IF OK () AND (dummy.cls = TString) AND
+            ((dummy.kind = 1) OR (dummy.kind = 5)) THEN
+            EmPushStrAddr (dummy) ;        (* destination at [BP+4] *)
+            DropC (EmCall (TU_IntFmt)) ;
+            EmAddSp (4)
+         ELSIF OK () THEN
+            Err (ETypeErr)
+         END ;
+         ExpectDelim (')', ENoSemi) ;
+         RETURN
+      END ;
       IF OK () AND (arg.cls = TReal) AND
          ((arg.kind = 1) OR (arg.kind = 5)) THEN
          IF arg.kind = 5 THEN
@@ -5287,8 +5341,28 @@ BEGIN
                   END ;
                   skipArg := TRUE
                ELSIF reading THEN
-                  (* Text-file Read/Readln is the next increment. *)
-                  Err (ENoLib) ;
+                  (* Readln(F, S): read one line from a text file into the
+                     counted string S.  The runtime takes the file block,
+                     destination and capacity; it consumes CR and terminates
+                     on LF/^Z/physical EOF. *)
+                  IF NOT MatchDelim (',') THEN
+                     Err (ENoSemi) ;
+                     RETURN
+                  END ;
+                  ParseExpr (dummy) ;
+                  IF OK () AND (dummy.cls = TString) AND
+                     ((dummy.kind = 1) OR (dummy.kind = 5)) THEN
+                     EmMovAxi ((VarSize (dummy) - 1) MOD 10000H) ;
+                     EmPushAx () ;
+                     EmPushStrAddr (dummy) ;
+                     EmPushVarAddr (symtab [arg.idx].local,
+                                    (symtab [arg.idx].off + arg.boff) MOD 10000H) ;
+                     DropC (EmCall (TU_FileReadln)) ;
+                     EmAddSp (6)
+                  ELSIF OK () THEN
+                     Err (ETypeErr)
+                  END ;
+                  ExpectDelim (')', ENoSemi) ;
                   RETURN
                ELSE
                   (* Text-file output: Writeln(File) is CRLF, Write(File, C)
@@ -7211,6 +7285,8 @@ BEGIN
    symtab [i].defnd := TRUE ;
    i := NewSym ("DISPOSE", KBuiltin, BI_Dispose, 0, 0, 0, 0, FALSE) ;
    symtab [i].defnd := TRUE ;
+   i := NewSym ("EOF", KBuiltin, BI_Eof, 0, 0, 0, 0, FALSE) ;
+   symtab [i].defnd := TRUE ;
    (* 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
       reads a character exactly as `Read(Ch)' does. *)
@@ -7375,6 +7451,9 @@ BEGIN
    TU_IoResult    := RT_Entry (38) ;
    TU_IoStore     := RT_Entry (39) ;
    TU_HeapNew     := RT_Entry (40) ;
+   TU_FileEof     := RT_Entry (41) ;
+   TU_FileReadln  := RT_Entry (42) ;
+   TU_IntFmt      := RT_Entry (43) ;
    TU_WrStr    := RT_Entry (15) ;      (* a string variable is written through
                                           the address on the stack *)
    TU_RdStr    := RT_Entry (16) ;      (* readln(s)/read(s): TPSRC8 prdstr,

+ 3 - 0
shell/Runtime.def

@@ -79,6 +79,9 @@ CONST
    E_IoResult = 38 ;        (* AX = last DOS status, then clear it *)
    E_IoStore = 39 ;         (* AX = status; save it for IOResult *)
    E_HeapNew = 40 ;         (* [BP+4]=pointer variable, [BP+6]=size *)
+   E_FileEof = 41 ;         (* [BP+4]=text file; AX = 1 at end *)
+   E_FileReadln = 42 ;      (* [BP+4]=file, [BP+6]=dest string, [BP+8]=max *)
+   E_IntFmt = 43 ;          (* [BP+4]=dest string, [BP+6]=integer value *)
 
    (* File control block, mirrored by Compiler.FileVarSize. *)
    F_NameOff = 4 ;           (* handle word, mode word, then the name *)

+ 130 - 4
shell/Runtime.mod

@@ -41,7 +41,7 @@ IMPLEMENTATION MODULE Runtime ;
 FROM SYSTEM IMPORT BYTE ;
 
 CONST
-   MaxRt  = 4096 ;
+   MaxRt  = 8192 ;
    (* MaxLbl and MaxFix were 64 and 400, and M/AddFix used to DROP once full.
       That limit does not announce itself: a dropped label leaves its bytes in
       place, so the runtime still has the right LENGTH and the only symptom is
@@ -99,7 +99,9 @@ CONST
    D_ASCSRC = 193 ;   (* 2 bytes: ascreal's source pointer *)
    D_IORES = 195 ;    (* 2 bytes: the last file-operation DOS status *)
    D_HEAP  = 197 ;    (* 2 bytes: the bump allocator's next free byte *)
-   D_END   = 199 ;    (* the block is padded to here *)
+   D_TXEOF = 199 ;    (* 1 byte: text Readln saw ^Z or physical EOF *)
+   D_TXCH  = 200 ;    (* 1 byte: one-byte INT 21h read scratch *)
+   D_END   = 201 ;    (* 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
@@ -156,7 +158,7 @@ VAR
    dataAt : CARDINAL ;
    rtBase : CARDINAL ;
    built  : BOOLEAN ;
-   entNm  : ARRAY [0..40] OF ARRAY [0..MaxNm] OF CHAR ;
+   entNm  : ARRAY [0..43] OF ARRAY [0..MaxNm] OF CHAR ;
 
 (* ---------------------------------------------------------------- *)
 (*  name helpers                                                     *)
@@ -3042,6 +3044,119 @@ BEGIN
    AddAxCx ;
    StDataAx (D_HEAP) ;
    PopDx ; PopCx ; PopBx ;
+   MovSpBp ; PopBp ; RetR ;
+
+   (* Eof(F): D_TXEOF, or DOS current position >= size. *)
+   M ("file_eof") ;
+   PushBp ; MovBpSp ;
+   PushBx ; PushCx ; PushDx ; PushSi ; PushDi ;
+   LdAlData (D_TXEOF) ; CmpAl0 ; Jne8 ("fe_yes") ;
+   MovDiBp4 ; LdAxDi ; CmpAxImm (0FFFFH) ; Je8 ("fe_yes") ;
+   B (89H) ; B (0C3H) ;               (* BX := handle *)
+   XorCxCx ; XorDxDx ; MovAxImm (4201H) ; Int21 ;
+   MovSiAx ; MovDiDx ;                (* current low/high *)
+   XorCxCx ; XorDxDx ; MovAxImm (4202H) ; Int21 ;
+   CmpDxDi ; Jb8 ("fe_yes_restore") ; Ja8 ("fe_no_restore") ;
+   B (39H) ; B (0F0H) ;               (* CMP AX,SI *)
+   Jb8 ("fe_yes_restore") ; Ja8 ("fe_no_restore") ;
+   M ("fe_yes_restore") ;
+   MovAxImm (1) ; Jmp8 ("fe_restore") ;
+   M ("fe_no_restore") ;
+   XorAxAx ;
+   M ("fe_restore") ;
+   PushAx ;
+   B (89H) ; B (0F9H) ;               (* MOV CX,DI: current high *)
+   B (89H) ; B (0F2H) ;               (* MOV DX,SI: current low *)
+   MovAxImm (4200H) ; Int21 ;
+   PopAx ;
+   Jmp8 ("fe_done") ;
+   M ("fe_yes") ;
+   MovAxImm (1) ;
+   M ("fe_done") ;
+   PopDi ; PopSi ; PopDx ; PopCx ; PopBx ;
+   MovSpBp ; PopBp ; RetR ;
+
+   (* Readln(F, S): read one line into the counted string at [BP+6].  CR is
+      skipped, LF terminates, ^Z or a zero-byte read marks text EOF. *)
+   M ("file_readln") ;
+   PushBp ; MovBpSp ;
+   PushBx ; PushCx ; PushDx ; PushSi ; PushDi ;
+   MovDiBp6 ;
+   B (0C6H) ; B (05H) ; B (0) ;      (* dest[0] := 0 *)
+   IncDi ;
+   XorCxCx ;                          (* CX := stored character count *)
+   MovSiBp4 ;                         (* SI := file block *)
+   M ("frl_get") ;
+   LdAxSi ;                           (* AX := handle *)
+   B (89H) ; B (0C3H) ;               (* BX := handle *)
+   MovDxVx (D_TXCH) ;
+   MovCxImm (1) ;
+   MovAh (3FH) ; Int21 ;
+   CmpAx0 ; Je8 ("frl_eof") ;
+   LdAlData (D_TXCH) ;
+   B (3CH) ; B (1AH) ; Je8 ("frl_eofset") ;   (* ^Z *)
+   B (3CH) ; B (0DH) ; Je8 ("frl_get") ;      (* ignore CR, wait for LF *)
+   B (3CH) ; B (0AH) ; Je8 ("frl_done") ;     (* LF ends the line *)
+   B (8BH) ; B (46H) ; B (8) ;        (* MOV AX,[BP+8]: capacity *)
+   B (39H) ; B (0C8H) ;               (* CMP AX,CX *)
+   Jbe8 ("frl_get") ;       (* full: consume the rest of the line *)
+   StDiAl ; IncDi ; IncCx ;
+   Jmp8 ("frl_get") ;
+   M ("frl_eof") ;
+   StDataByte (D_TXEOF, 1) ;
+   Jmp8 ("frl_done") ;
+   M ("frl_eofset") ;
+   StDataByte (D_TXEOF, 1) ;
+   M ("frl_done") ;
+   MovBxBp6 ;
+   B (88H) ; B (0FH) ;               (* MOV [BX],CL: dest[0] := length *)
+   XorAxAx ; StDataAx (D_IORES) ;
+   PopDi ; PopSi ; PopDx ; PopCx ; PopBx ;
+   MovSpBp ; PopBp ; RetR ;
+
+   (* IntFmt: decimal integer -> counted string, for Str(integer, S).
+      [BP+4]=dest, [BP+6]=value.  D_TXCH carries the sign flag. *)
+   M ("int_fmt") ;
+   PushBp ; MovBpSp ;
+   PushBx ; PushCx ; PushDx ; PushSi ; PushDi ;
+   MovDiBp4 ;
+   B (0C6H) ; B (05H) ; B (0) ;      (* dest[0] := 0 *)
+   IncDi ;
+   MovAxBp6 ;
+   StDataByte (D_TXCH, 0) ;
+   CmpAx0 ; Jge8 ("if_pos") ;
+   StDataByte (D_TXCH, 1) ;
+   NegAx ;
+   M ("if_pos") ;
+   MovCxImm (10) ;
+   MovBxVx (D_NUM + 8) ;
+   MovSiBx ;
+   M ("if_dig") ;
+   XorDxDx ;
+   DivCx ;
+   AddDl (ORD ("0")) ;
+   DecSi ; StSiDl ;
+   CmpAx0 ; Jne8 ("if_dig") ;
+   (* write the sign before the digits *)
+   LdAlData (D_TXCH) ;
+   CmpAl0 ; Je8 ("if_nosign") ;
+   B (0C6H) ; B (05H) ; B (2DH) ;    (* MOV byte [DI],'-' *)
+   IncDi ;
+   M ("if_nosign") ;
+   (* length := end - first, plus the sign *)
+   B (89H) ; B (0D9H) ;               (* MOV CX,BX *)
+   B (29H) ; B (0F1H) ;               (* SUB CX,SI *)
+   LdAlData (D_TXCH) ;
+   CmpAl0 ; Je8 ("if_len") ;
+   IncCx ;
+   M ("if_len") ;
+   MovDlCl ;
+   M ("if_copy") ;
+   LdAlSi ; StDiAl ; IncSi ; IncDi ;
+   Loop8 ("if_copy") ;
+   MovBxBp4 ;
+   B (88H) ; B (17H) ;               (* MOV [BX],DL: dest[0] := length *)
+   PopDi ; PopSi ; PopDx ; PopCx ; PopBx ;
    MovSpBp ; PopBp ; RetR
 END EmitFileOps ;
 
@@ -3186,6 +3301,14 @@ BEGIN
       HALT
    END ;
    B (0) ; B (0) ;                 (* the bump heap's next free byte *)
+   IF dataAt + D_TXEOF # rpos THEN
+      HALT
+   END ;
+   B (0) ;                         (* text EOF flag *)
+   IF dataAt + D_TXCH # rpos THEN
+      HALT
+   END ;
+   B (0) ;                         (* one-byte text read scratch *)
    WHILE rpos < dataAt + D_END DO
       B (0)
    END ;
@@ -3300,6 +3423,9 @@ BEGIN
    SetStr (entNm [38], "ioresult") ;
    SetStr (entNm [39], "io_store") ;
    SetStr (entNm [40], "heap_new") ;
+   SetStr (entNm [41], "file_eof") ;
+   SetStr (entNm [42], "file_readln") ;
+   SetStr (entNm [43], "int_fmt") ;
    built := TRUE
 END RT_Build ;
 
@@ -3327,7 +3453,7 @@ BEGIN
    IF NOT built THEN
       RT_Build (0)
    END ;
-   IF i > 40 THEN
+   IF i > 43 THEN
       RETURN 0
    END ;
    RETURN rtBase + LblOff (entNm [i])

+ 6 - 3
shell/tests/RtProbe.mod

@@ -108,7 +108,7 @@ END PENT ;
 
 PROCEDURE Main ;
 VAR i, n, base : CARDINAL ;
-    names : ARRAY [0..40] OF ARRAY [0..15] OF CHAR ;
+    names : ARRAY [0..43] 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 <= 40 DO
+   WHILE i <= 43 DO
       names [i] := "" ;
       INC (i)
    END ;
@@ -153,8 +153,11 @@ BEGIN
    names [38] := "ioresult" ;
    names [39] := "io_store" ;
    names [40] := "heap_new" ;
+   names [41] := "file_eof" ;
+   names [42] := "file_readln" ;
+   names [43] := "int_fmt" ;
    i := 0 ;
-   WHILE i <= 40 DO
+   WHILE i <= 43 DO
       PENT (i, names [i]) ;
       INC (i)
    END ;

+ 64 - 64
shell/tests/exec/rtdrv.s

@@ -92,73 +92,73 @@
 # 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, 0x0190
-	.set	HDR, 0x1100
-	.set	FMTDEST, 0x1430	# 64-byte destination for real_fmt
-	.set	ASCSRC, 0x1470	# ASCIIZ sources for real_val
-	.set	DATA, 0x1110
+	.set	HDR, 0x1300
+	.set	FMTDEST, 0x2430	# 64-byte destination for real_fmt
+	.set	ASCSRC, 0x2470	# ASCIIZ sources for real_val
+	.set	DATA, 0x2110
 	.set	DLEN, 32			# bytes of data area for initmem to clear
-	.set	STORE, 0x1140		# where a read entry's result is stored
-	.set	WSTR, 0x1150		# a string for the wrstr case: length + chars
-	.set	WSTR_EMPTY, 0x1158	# the same, with a length of 0
-	.set	CASE, 0x1160		# the case record
-	.set	D_DUMPLEN, 0x11A0	# the driver's own three words
-	.set	D_DUMPADR, 0x11A2
-	.set	D_CNT, 0x11A4
-	.set	D_AX, 0x11A6		# last call's AX, for the comparison cases
-	.set	RDSTR_DST, 0x11B0	# destination for the rdstr cases
-	.set	SST_HELLO, 0x11C0	# a short source string for strstore
-	.set	SST_LONG, 0x11D0	# a source longer than a small max
-	.set	SST_EMPTY, 0x11E0	# an empty source string
-	.set	SST_DST, 0x11F0		# destination for the strstore cases
-	.set	SST_CAT, 0x1200		# destination for the strcat cases, with a
+	.set	STORE, 0x2140		# where a read entry's result is stored
+	.set	WSTR, 0x2150		# a string for the wrstr case: length + chars
+	.set	WSTR_EMPTY, 0x2158	# the same, with a length of 0
+	.set	CASE, 0x2160		# the case record
+	.set	D_DUMPLEN, 0x21a0	# the driver's own three words
+	.set	D_DUMPADR, 0x21a2
+	.set	D_CNT, 0x21a4
+	.set	D_AX, 0x21a6		# last call's AX, for the comparison cases
+	.set	RDSTR_DST, 0x21b0	# destination for the rdstr cases
+	.set	SST_HELLO, 0x21c0	# a short source string for strstore
+	.set	SST_LONG, 0x21d0	# a source longer than a small max
+	.set	SST_EMPTY, 0x21e0	# an empty source string
+	.set	SST_DST, 0x21f0		# destination for the strstore cases
+	.set	SST_CAT, 0x2200		# destination for the strcat cases, with a
 					# length to append to -- unlike SST_DST,
 					# which strstore overwrites
-	.set	SST_CAT0, 0x1210	# ...and one that starts empty
-	.set	SST_WORLD, 0x1220	# a source distinct from SST_HELLO
-	.set	R_BLK1, 0x1230
-	.set	R_BLK2, 0x1240
-	.set	R_BLK3, 0x1250
-	.set	R_BLK4, 0x1260
-	.set	R_BLK5, 0x1270
-	.set	R_BLK6, 0x1280
-	.set	R_BLK7, 0x1290
-	.set	R_BLK8, 0x12A0
-	.set	R_BLK9, 0x12B0
-	.set	R_BLK10, 0x12C0
-	.set	R_BLK11, 0x12D0
-	.set	R_BLK12, 0x12E0
-	.set	R_BLK13, 0x12F0
-	.set	R_BLK14, 0x1300
-	.set	R_BLK15, 0x1310
-	.set	R_BLK16, 0x1320
-	.set	R_BLK17, 0x1330
-	.set	R_BLK18, 0x1340
-	.set	R_BLK19, 0x1350
-	.set	R_BLK20, 0x1360
-	.set	R_BLK21, 0x1370
-	.set	R_BLK22, 0x1380
-	.set	R_BLK23, 0x1390
-	.set	R_BLK24, 0x13A0
-	.set	R_BLK25, 0x13B0
-	.set	R_BLK26, 0x13C0
-	.set	R_BLK27, 0x13D0
-	.set	R_BLK28, 0x13E0
-	.set	R_BLK29, 0x13F0
-	.set	R_BLK30, 0x1400
-	.set	R_BLK31, 0x1410
-	.set	R_BLK32, 0x1500
-	.set	R_BLK33, 0x1510
-	.set	R_BLK34, 0x1520
-	.set	R_BLK35, 0x1530
-	.set	R_BLK36, 0x1540
-	.set	FILEBLK, 0x1A00	# the 132-byte file control block
-	.set	SETA, 0x1580
-	.set	SETB, 0x1590
-	.set	SETC, 0x15A0
-	.set	SETD, 0x15B0
-	.set	SET2A, 0x15C0
-	.set	SET2B, 0x15D0
-	.set	SET2D, 0x15E0
+	.set	SST_CAT0, 0x2210	# ...and one that starts empty
+	.set	SST_WORLD, 0x2220	# a source distinct from SST_HELLO
+	.set	R_BLK1, 0x2230
+	.set	R_BLK2, 0x2240
+	.set	R_BLK3, 0x2250
+	.set	R_BLK4, 0x2260
+	.set	R_BLK5, 0x2270
+	.set	R_BLK6, 0x2280
+	.set	R_BLK7, 0x2290
+	.set	R_BLK8, 0x22a0
+	.set	R_BLK9, 0x22b0
+	.set	R_BLK10, 0x22c0
+	.set	R_BLK11, 0x22d0
+	.set	R_BLK12, 0x22e0
+	.set	R_BLK13, 0x22f0
+	.set	R_BLK14, 0x2300
+	.set	R_BLK15, 0x2310
+	.set	R_BLK16, 0x2320
+	.set	R_BLK17, 0x2330
+	.set	R_BLK18, 0x2340
+	.set	R_BLK19, 0x2350
+	.set	R_BLK20, 0x2360
+	.set	R_BLK21, 0x2370
+	.set	R_BLK22, 0x2380
+	.set	R_BLK23, 0x2390
+	.set	R_BLK24, 0x23a0
+	.set	R_BLK25, 0x23b0
+	.set	R_BLK26, 0x23c0
+	.set	R_BLK27, 0x23d0
+	.set	R_BLK28, 0x23e0
+	.set	R_BLK29, 0x23f0
+	.set	R_BLK30, 0x2400
+	.set	R_BLK31, 0x2410
+	.set	R_BLK32, 0x2500
+	.set	R_BLK33, 0x2510
+	.set	R_BLK34, 0x2520
+	.set	R_BLK35, 0x2530
+	.set	R_BLK36, 0x2540
+	.set	FILEBLK, 0x2a00	# the 132-byte file control block
+	.set	SETA, 0x2580
+	.set	SETB, 0x2590
+	.set	SETC, 0x25a0
+	.set	SETD, 0x25b0
+	.set	SET2A, 0x25c0
+	.set	SET2B, 0x25d0
+	.set	SET2D, 0x25e0
 
 	.code16
 	.text

+ 9 - 8
shell/tests/fixtures/calc_ladder.tsv

@@ -25,11 +25,12 @@
 # positions shift — which is exactly why this must be a measured number, not a
 # remembered one.
 #
-# Current rung (2026-10-23): `Eof(H)' in Help.  UpCase, run-time set
-# membership, string fields through DI, the original memory layout, untyped-file
-# declarations, file control-block operations, VAR string parameters, Chr,
-# typed-file block I/O, text-file output, Str, and pointer types with
-# New/Dispose/dereference moved the ladder 15911 -> 18267 -> 19847 -> 20912 ->
-# 22253 -> 22280 -> 22706 -> 22859 -> 23700 -> 25674 -> 26066 -> 26924 ->
-# 27648.  The next blocker is EndOfFile on a text file (TP3 error 41).
-CALC.PAS	ERR	41	27648
+# Current rung (2026-10-23): `Val(Buffer^[0],EndOfFile,ErrorResult)' in Help.
+# UpCase, run-time set membership, string fields through DI, the original
+# memory layout, untyped-file declarations, file control-block operations, VAR
+# string parameters, Chr, typed-file block I/O, text-file output, Str,
+# pointers/New/dereference, text Eof/Readln and Str(integer) moved the ladder
+# 15911 -> 18267 -> 19847 -> 20912 -> 22253 -> 22280 -> 22706 -> 22859 ->
+# 23700 -> 25674 -> 26066 -> 26924 -> 27648 -> 28074.  The next blocker is Val
+# string-to-integer conversion (TP3 error 41).
+CALC.PAS	ERR	41	28074

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

@@ -669,3 +669,12 @@ t92_strreal	OK	247	36
 #                   start of Help and disposes after it).  The .out is derived
 #                   from the two assigned strings and the comparison.
 t93_pointer	OK	196	15
+
+#   t94_textread         text Eof/Readln into a pointer-indexed string, then
+#                   read a string element back.  Compile-only: no filesystem in
+#                   either harness.
+t94_textread	OK	206	147
+
+#   t95_strint           Str(integer, S) via int_fmt: positive, negative and
+#                   zero, all into a string[10].
+t95_strint	OK	133	18

+ 34 - 0
shell/tests/fixtures/t94_textread.pas

@@ -0,0 +1,34 @@
+program t94_textread;
+
+{ t94 -- text-file Eof and Readln.  CALC.INC's GetPages does
+
+      while not Eof(H) do
+        Readln(H, Buffer^[count]);
+
+  and then reads back string elements from the pointer.  Compile-only: the
+  boot harnesses have no filesystem, so a successful text read has no oracle
+  here. }
+
+type
+  Pages = array [0..2] of string[5];
+
+var
+  H : text;
+  P : ^Pages;
+  C : integer;
+  S : string[5];
+begin
+  New (P);
+  assign (H, 'T94.TXT');
+  reset (H);
+  C := 0;
+  while not Eof (H) do
+  begin
+    Readln (H, P^[C]);
+    C := C + 1
+  end;
+  close (H);
+  S := P^[0];
+  writeln (S);
+  Dispose (P)
+end.

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

@@ -0,0 +1,3 @@
+42
+-7
+0

+ 19 - 0
shell/tests/fixtures/t95_strint.pas

@@ -0,0 +1,19 @@
+program t95_strint;
+
+{ t95 -- Str(integer, S).  CALC.INC's Help does `Str(count,st)' after reading
+  the help file.  No width/decimals: TP3's default width for an integer is
+  zero, and st is a string[10]. }
+
+var
+  S : string[10];
+  I : integer;
+begin
+  I := 42;
+  Str (I, S);
+  writeln (S);
+  I := -7;
+  Str (I, S);
+  writeln (S);
+  Str (0, S);
+  writeln (S)
+end.

+ 59 - 58
shell/tests/rt_exec.py

@@ -63,26 +63,26 @@ SHELL = os.path.dirname(HERE)
 # 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 = 0x0190
-HDR = 0x1100
+HDR = 0x1300
 DLEN = 32
-DATA = 0x1110
-STORE = 0x1140
-WSTR = 0x1150
-WSTR_EMPTY = 0x1158
-CASE = 0x1160
+DATA = 0x2110
+STORE = 0x2140
+WSTR = 0x2150
+WSTR_EMPTY = 0x2158
+CASE = 0x2160
 CASE_SZ = 64
-RDSTR_DST = 0x11B0
-SST_HELLO = 0x11C0
-SST_LONG = 0x11D0
-SST_EMPTY = 0x11E0
-SST_DST = 0x11F0
-SST_CAT = 0x1200
-SST_CAT0 = 0x1210
-SST_WORLD = 0x1220
-AXOUT = 0x11A6          # the driver stores the last call's AX here
-FMTDEST = 0x1430        # a 64-byte string for the real_fmt cases
-ASCSRC = 0x1470          # the ASCIIZ strings for real_val
-FILEBLK = 0x1A00         # the 132-byte file control block
+RDSTR_DST = 0x21b0
+SST_HELLO = 0x21c0
+SST_LONG = 0x21d0
+SST_EMPTY = 0x21e0
+SST_DST = 0x21f0
+SST_CAT = 0x2200
+SST_CAT0 = 0x2210
+SST_WORLD = 0x2220
+AXOUT = 0x21a6          # the driver stores the last call's AX here
+FMTDEST = 0x2430        # a 64-byte string for the real_fmt cases
+ASCSRC = 0x2470          # the ASCIIZ strings for real_val
+FILEBLK = 0x2a00         # the 132-byte file control block
 REALDST = 0x0FA8
 
 # A .COM is loaded at CS:0100, and every address in the image is an image
@@ -113,7 +113,8 @@ ENTS = ["initmem", "progend", "stackchk", "wrint", "wrchar", "wrbool",
         "real_div", "real_cmp", "real_int", "real_fmt", "real_val",
         "real_write", "set_op", "set_cmp", "set_copy",
         "file_assign", "file_reset", "file_rewrite", "file_close",
-        "ioresult", "io_store", "heap_new"]
+        "ioresult", "io_store", "heap_new", "file_eof", "file_readln",
+        "int_fmt"]
 
 # A call slot's flags, as rtdrv.s reads them.
 F_STACK = 1     # the argument goes on the stack, popped by the caller
@@ -549,7 +550,7 @@ def build_cases():
               (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):
-        blk = 0x1230 + 16 * bi
+        blk = 0x2230 + 16 * bi
         add("real_add(%d,%d)" % (a, b),
             [s("real_add", blk + LOAD_BIAS)],
             dump=6, dumpbytes=mbf(a + b), dumpadr=blk,
@@ -582,7 +583,7 @@ def build_cases():
         if (a, b) in seen:
             continue
         seen.add((a, b))
-        blk = 0x1230 + 16 * bi
+        blk = 0x2230 + 16 * bi
         want = (a > b) - (a < b)
         add("real_cmp(%d,%d)" % (a, b),
             [s("real_cmp", blk + LOAD_BIAS)],
@@ -594,14 +595,14 @@ def build_cases():
             (-0.5, 0.5), (12345.75, 12345.5), (2.5, 0.0), (-2.5, 0.0),
             (0.99, 0.0), (1.9, 0.0)]
     for fi, (a, b) in enumerate(FRAC):
-        blk = 0x1370 + 16 * fi
+        blk = 0x2370 + 16 * fi
         want = (a > b) - (a < b)
         add("real_cmp(%g,%g)" % (a, b),
             [s("real_cmp", blk + LOAD_BIAS)],
             dump=2, dumpbytes=struct.pack("<H", want & 0xFFFF), dumpadr=AXOUT,
             note="fractional magnitudes: the mantissa decides")
     add("real_cmp(2^40,0)",
-        [s("real_cmp", 0x1410 + LOAD_BIAS)],
+        [s("real_cmp", 0x2410 + LOAD_BIAS)],
         dump=2, dumpbytes=struct.pack("<h", 1), dumpadr=AXOUT,
         note="the exponent alone decides")
 
@@ -611,20 +612,20 @@ def build_cases():
     # (TPSRC's xint pushes the six-byte result back).
     for bi, (a, b) in enumerate(BLOCKS):
         if a in (0, 1, -3, 32767):
-            blk = 0x1230 + 16 * bi
+            blk = 0x2230 + 16 * bi
             add("real_int(%d)" % a,
                 [s("real_int", blk + LOAD_BIAS)],
                 dump=6, dumpbytes=mbf(math.trunc(a)), dumpadr=blk,
                 note="the integer part as a real, the reference's reint")
     for fi, (a, b) in enumerate(FRAC):
-        blk = 0x1370 + 16 * fi
+        blk = 0x2370 + 16 * fi
         add("real_int(%g)" % a,
             [s("real_int", blk + LOAD_BIAS)],
             dump=6, dumpbytes=mbf(math.trunc(a)), dumpadr=blk,
             note="the fraction is masked away; the sign and exponent stay")
     add("real_int(2^40)",
-        [s("real_int", 0x1410 + LOAD_BIAS)],
-        dump=6, dumpbytes=bytes.fromhex("A90000000000"), dumpadr=0x1410,
+        [s("real_int", 0x2410 + LOAD_BIAS)],
+        dump=6, dumpbytes=bytes.fromhex("A90000000000"), dumpadr=0x2410,
         note="exponent >= 0A8h is already integral and returns unchanged")
 
     # --- fmtreal: real_fmt writes a length-prefixed, left-padded field -----
@@ -641,15 +642,15 @@ def build_cases():
          s2cx("real_fmt", STORE + LOAD_BIAS, FMTDEST + LOAD_BIAS, 0)],
         stdin=struct.pack("<h", 1), dump=2, dumpbytes=bytes([1]) + b"1",
         dumpadr=FMTDEST, note="a known-good 1.0 from real_from_int")
-    fmt("real_fmt(1:0:0)", 0x1230, 0, 0, b"1")
-    fmt("real_fmt(0:0:0)", 0x12B0, 0, 0, b"0")
-    fmt("real_fmt(3.7:0:2)", 0x1370, 0, 2, b"3.70")
-    fmt("real_fmt(12345.75:12:2)", 0x13C0, 12, 2, b"    12345.75")
-    fmt("real_fmt(0.5:6:3)", 0x13A0, 6, 3, b" 0.500")
-    fmt("real_fmt(-3.7:0:1)", 0x1390, 0, 1, b"-3.7")
-    fmt("real_fmt(0:5:2)", 0x12B0, 5, 2, b" 0.00")
-    fmt("real_fmt(2.5:0:0)", 0x13D0, 0, 0, b"3")
-    fmt("real_fmt(3.7:10:25)", 0x1370, 10, 25, b"3.7000E+00")
+    fmt("real_fmt(1:0:0)", 0x2230, 0, 0, b"1")
+    fmt("real_fmt(0:0:0)", 0x22b0, 0, 0, b"0")
+    fmt("real_fmt(3.7:0:2)", 0x2370, 0, 2, b"3.70")
+    fmt("real_fmt(12345.75:12:2)", 0x23c0, 12, 2, b"    12345.75")
+    fmt("real_fmt(0.5:6:3)", 0x23a0, 6, 3, b" 0.500")
+    fmt("real_fmt(-3.7:0:1)", 0x2390, 0, 1, b"-3.7")
+    fmt("real_fmt(0:5:2)", 0x22b0, 5, 2, b" 0.00")
+    fmt("real_fmt(2.5:0:0)", 0x23d0, 0, 0, b"3")
+    fmt("real_fmt(3.7:10:25)", 0x2370, 10, 25, b"3.7000E+00")
 
     # --- ascreal: real_val parses an ASCIIZ string ------------------------
     # A dump of AXOUT shows the returned offset, or FFFFh on a hard error.
@@ -680,13 +681,13 @@ def build_cases():
         off += len(txt)
 
     for bi, (a, b) in [(0, (12340, 5)), (1, (12340, 1))]:
-        blk = 0x1500 + 16 * bi
+        blk = 0x2500 + 16 * bi
         add("real_add(%d,%d)" % (a, b), [s("real_add", blk + LOAD_BIAS)],
             dump=6, dumpbytes=mbf(a + b), dumpadr=blk,
             note="a large value plus a small digit: the add core's alignment")
 
     for bi, a in [(2, 12341), (3, 12345), (4, 12340)]:
-        blk = 0x1500 + 16 * bi
+        blk = 0x2500 + 16 * bi
         add("real_mul(%d,1)" % a, [s("real_mul", blk + LOAD_BIAS)],
             dump=6, dumpbytes=mbf(a), dumpadr=blk,
             note="multiplying by 1.0 must be exact")
@@ -695,14 +696,14 @@ def build_cases():
     def wr(name, blk, width, dec, text):
         add(name, [s3("real_write", dec, width, blk + LOAD_BIAS)], out=text,
             note="fmtreal's field, padded and printed by the entry itself")
-    wr("real_write(3.7:0:2)", 0x1370, 0, 2, b"3.70")
-    wr("real_write(3.7:10:2)", 0x1370, 10, 2, b"      3.70")
-    wr("real_write(12345.75:12:2)", 0x13C0, 12, 2, b"    12345.75")
-    wr("real_write(0.5:0:3)", 0x13A0, 0, 3, b"0.500")
-    wr("real_write(-3.7:0:1)", 0x1390, 0, 1, b"-3.7")
-    wr("real_write(2.5:0:0)", 0x13D0, 0, 0, b"3")
-    wr("real_write(42:0:0)", 0x1290, 0, 0, b"42")
-    wr("real_write(3.7:18:FFFF)", 0x1370, 18, 0xFFFF,
+    wr("real_write(3.7:0:2)", 0x2370, 0, 2, b"3.70")
+    wr("real_write(3.7:10:2)", 0x2370, 10, 2, b"      3.70")
+    wr("real_write(12345.75:12:2)", 0x23c0, 12, 2, b"    12345.75")
+    wr("real_write(0.5:0:3)", 0x23a0, 0, 3, b"0.500")
+    wr("real_write(-3.7:0:1)", 0x2390, 0, 1, b"-3.7")
+    wr("real_write(2.5:0:0)", 0x23d0, 0, 0, b"3")
+    wr("real_write(42:0:0)", 0x2290, 0, 0, b"42")
+    wr("real_write(3.7:18:FFFF)", 0x2370, 18, 0xFFFF,
        b"  3.7000000000E+00")
 
     # --- set algebra ----------------------------------------------------
@@ -713,10 +714,10 @@ def build_cases():
                        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")
+    setop("set_op /", 0, 1, 0x25b0, 0x2590, 0x2580, b"\x08")
+    setop("set_op +", 1, 1, 0x25b0, 0x2590, 0x2580, b"\x1A")
+    setop("set_op -", 2, 1, 0x25b0, 0x2590, 0x2580, b"\x02")
+    setop("set_op / 2 bytes", 0, 2, 0x25e0, 0x25d0, 0x25c0, 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.
@@ -724,16 +725,16 @@ def build_cases():
         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)
+    setcmp("set_cmp size 0", 0, 0x2580, 0x2590, 1)
+    setcmp("set_cmp A=A", 1, 0x2580, 0x2580, 1)
+    setcmp("set_cmp A~B", 1, 0x2580, 0x2590, 0)
+    setcmp("set_cmp C<A", 1, 0x25a0, 0x2580, 2)
+    setcmp("set_cmp A>C", 1, 0x2580, 0x25a0, 4)
+    setcmp("set_cmp 2-byte incomparable", 2, 0x25c0, 0x25d0, 0)
 
     add("set_copy 2 bytes",
-        [s3("set_copy", 2, 0x15C0 + LOAD_BIAS, 0x15E0 + LOAD_BIAS)],
-        dump=2, dumpbytes=b"\x0A\x0F", dumpadr=0x15E0,
+        [s3("set_copy", 2, 0x25c0 + LOAD_BIAS, 0x25e0 + LOAD_BIAS)],
+        dump=2, dumpbytes=b"\x0A\x0F", dumpadr=0x25e0,
         note="[BP+4]=size, [BP+6]=src, [BP+8]=dest")
 
     add("wrchar('A')", [s("wrchar", ord("A"))], out=b"A")

+ 257 - 105
shell/tests/runtime.golden

@@ -22,7 +22,7 @@
 0015  39 CF       cmp di,cx
 0017  72 F5       jb 0eh
 0019  89 C8       mov ax,cx
-001B  A3 6C 10    mov word ptr [106ch],ax
+001B  A3 94 11    mov word ptr [1194h],ax
 001E  1E          push ds
 001F  07          pop es
 0020  C3          ret
@@ -43,7 +43,7 @@
 003B  58          pop ax
 003C  F7 D8       neg ax
 003E  B9 0A 00    mov cx,0ah
-0041  BB AF 0F    mov bx,0fafh
+0041  BB D7 10    mov bx,10d7h
 0044  89 DE       mov si,bx
 0046  31 D2       xor dx,dx
 0048  F7 F1       div ax,cx
@@ -95,7 +95,7 @@
 00A7  58          pop ax
 00A8  F7 D8       neg ax
 00AA  B9 0A 00    mov cx,0ah
-00AD  BB AF 0F    mov bx,0fafh
+00AD  BB D7 10    mov bx,10d7h
 00B0  89 DE       mov si,bx
 00B2  31 D2       xor dx,dx
 00B4  F7 F1       div ax,cx
@@ -127,18 +127,18 @@
 00E3  83 7E 04 00 cmp word ptr [bp+4h],0h
 00E7  89 EC       mov sp,bp
 00E9  75 05       jne 0f0h
-00EB  BA B4 0F    mov dx,0fb4h
+00EB  BA DC 10    mov dx,10dch
 00EE  EB 03       jmp 0f3h
-00F0  BA AF 0F    mov dx,0fafh
+00F0  BA D7 10    mov dx,10d7h
 00F3  B4 09       mov ah,9h
 00F5  CD 21       int 21h
 00F7  5D          pop bp
 00F8  C3          ret
-00F9  BA BD 0F    mov dx,0fbdh
+00F9  BA E5 10    mov dx,10e5h
 00FC  B4 09       mov ah,9h
 00FE  CD 21       int 21h
 0100  C3          ret
-0101  BA BA 0F    mov dx,0fbah
+0101  BA E2 10    mov dx,10e2h
 0104  B4 09       mov ah,9h
 0106  CD 21       int 21h
 0108  C3          ret
@@ -305,12 +305,12 @@
 021C  EB EF       jmp 20dh
 021E  58          pop ax
 021F  C3          ret
-0220  8B 1E C3 0F mov bx,word ptr [0fc3h]
+0220  8B 1E EB 10 mov bx,word ptr [10ebh]
 0224  83 FB 00    cmp bx,0h
 0227  74 09       je 232h
 0229  8A C3       mov al,bl
 022B  31 DB       xor bx,bx
-022D  89 1E C3 0F mov word ptr [0fc3h],bx
+022D  89 1E EB 10 mov word ptr [10ebh],bx
 0231  C3          ret
 0232  B4 08       mov ah,8h
 0234  CD 21       int 21h
@@ -318,7 +318,7 @@
 0237  88 C2       mov dl,al
 0239  BB 01 00    mov bx,1h
 023C  8A DA       mov bl,dl
-023E  89 1E C3 0F mov word ptr [0fc3h],bx
+023E  89 1E EB 10 mov word ptr [10ebh],bx
 0242  C3          ret
 0243  55          push bp
 0244  8B EC       mov bp,sp
@@ -545,7 +545,7 @@
 03C7  8B 4D 06    mov cx,word ptr [di+6h]
 03CA  8B 75 08    mov si,word ptr [di+8h]
 03CD  8B 7D 0A    mov di,word ptr [di+0ah]
-03D0  C7 06 C5 0F 00 00 mov word ptr [0fc5h],0h
+03D0  C7 06 ED 10 00 00 mov word ptr [10edh],0h
 03D6  E8 4D 00    call 426h
 03D9  5F          pop di
 03DA  89 05       mov word ptr [di],ax
@@ -574,7 +574,7 @@
 0403  8B 4D 06    mov cx,word ptr [di+6h]
 0406  8B 75 08    mov si,word ptr [di+8h]
 0409  8B 7D 0A    mov di,word ptr [di+0ah]
-040C  C7 06 C5 0F 00 80 mov word ptr [0fc5h],8000h
+040C  C7 06 ED 10 00 80 mov word ptr [10edh],8000h
 0412  E8 11 00    call 426h
 0415  5F          pop di
 0416  89 05       mov word ptr [di],ax
@@ -589,7 +589,7 @@
 0425  C3          ret
 0426  80 F9 00    cmp cl,0h
 0429  74 0E       je 439h
-042B  33 3E C5 0F xor di,word ptr [0fc5h]
+042B  33 3E ED 10 xor di,word ptr [10edh]
 042F  3C 00       cmp al,0h
 0431  75 07       jne 43ah
 0433  89 C8       mov ax,cx
@@ -601,16 +601,16 @@
 043E  91          xchg ax,cx
 043F  87 F3       xchg bx,si
 0441  87 FA       xchg dx,di
-0443  88 0E C9 0F mov byte ptr [0fc9h],cl
+0443  88 0E F1 10 mov byte ptr [10f1h],cl
 0447  28 C1       sub cl,al
 0449  80 F9 28    cmp cl,28h
 044C  72 06       jb 454h
-044E  8A 0E C9 0F mov cl,byte ptr [0fc9h]
+044E  8A 0E F1 10 mov cl,byte ptr [10f1h]
 0452  EB DF       jmp 433h
-0454  89 3E C5 0F mov word ptr [0fc5h],di
-0458  80 26 C6 0F 80 and byte ptr [0fc6h],80h
-045D  89 3E C7 0F mov word ptr [0fc7h],di
-0461  30 36 C8 0F xor byte ptr [0fc8h],dh
+0454  89 3E ED 10 mov word ptr [10edh],di
+0458  80 26 EE 10 80 and byte ptr [10eeh],80h
+045D  89 3E EF 10 mov word ptr [10efh],di
+0461  30 36 F0 10 xor byte ptr [10f0h],dh
 0465  81 CF 00 80 or di,8000h
 0469  80 CE 80    or dh,80h
 046C  80 F9 10    cmp cl,10h
@@ -635,8 +635,8 @@
 0497  D0 DC       rcr ah,1h
 0499  FE C9       dec cl
 049B  75 F6       jne 493h
-049D  A0 C9 0F    mov al,byte ptr [0fc9h]
-04A0  F6 06 C8 0F 80 test byte ptr [0fc8h],80h
+049D  A0 F1 10    mov al,byte ptr [10f1h]
+04A0  F6 06 F0 10 80 test byte ptr [10f0h],80h
 04A5  75 14       jne 4bbh
 04A7  00 EC       add ah,ch
 04A9  11 F3       adc bx,si
@@ -656,7 +656,7 @@
 04C3  19 F3       sbb bx,si
 04C5  19 FA       sbb dx,di
 04C7  73 14       jnb 4ddh
-04C9  80 36 C6 0F 80 xor byte ptr [0fc6h],80h
+04C9  80 36 EE 10 80 xor byte ptr [10eeh],80h
 04CE  F6 D4       not ah
 04D0  F7 D3       not bx
 04D2  F7 D2       not dx
@@ -688,7 +688,7 @@
 050B  31 D2       xor dx,dx
 050D  C3          ret
 050E  80 E6 7F    and dh,7fh
-0511  32 36 C6 0F xor dh,byte ptr [0fc6h]
+0511  32 36 EE 10 xor dh,byte ptr [10eeh]
 0515  C3          ret
 0516  55          push bp
 0517  8B EC       mov bp,sp
@@ -734,23 +734,23 @@
 056A  B0 01       mov al,1h
 056C  B4 4C       mov ah,4ch
 056E  CD 21       int 21h
-0570  89 0E D0 0F mov word ptr [0fd0h],cx
+0570  89 0E F8 10 mov word ptr [10f8h],cx
 0574  8B CA       mov cx,dx
 0576  31 F9       xor cx,di
 0578  F6 D5       not ch
 057A  80 E5 80    and ch,80h
-057D  88 2E C6 0F mov byte ptr [0fc6h],ch
+057D  88 2E EE 10 mov byte ptr [10eeh],ch
 0581  80 CE 80    or dh,80h
 0584  81 CF 00 80 or di,8000h
-0588  89 36 D2 0F mov word ptr [0fd2h],si
-058C  89 3E D4 0F mov word ptr [0fd4h],di
-0590  A3 CA 0F    mov word ptr [0fcah],ax
-0593  89 1E CC 0F mov word ptr [0fcch],bx
-0597  89 16 CE 0F mov word ptr [0fceh],dx
+0588  89 36 FA 10 mov word ptr [10fah],si
+058C  89 3E FC 10 mov word ptr [10fch],di
+0590  A3 F2 10    mov word ptr [10f2h],ax
+0593  89 1E F4 10 mov word ptr [10f4h],bx
+0597  89 16 F6 10 mov word ptr [10f6h],dx
 059B  30 E4       xor ah,ah
 059D  31 DB       xor bx,bx
 059F  31 D2       xor dx,dx
-05A1  BF D0 0F    mov di,0fd0h
+05A1  BF F8 10    mov di,10f8h
 05A4  B1 05       mov cl,5h
 05A6  47          inc di
 05A7  8A 2D       mov ch,byte ptr [di]
@@ -765,9 +765,9 @@
 05BA  BE 08 00    mov si,8h
 05BD  D0 DD       rcr ch,1h
 05BF  73 0C       jnb 5cdh
-05C1  02 26 CB 0F add ah,byte ptr [0fcbh]
-05C5  13 1E CC 0F adc bx,word ptr [0fcch]
-05C9  13 16 CE 0F adc dx,word ptr [0fceh]
+05C1  02 26 F3 10 add ah,byte ptr [10f3h]
+05C5  13 1E F4 10 adc bx,word ptr [10f4h]
+05C9  13 16 F6 10 adc dx,word ptr [10f6h]
 05CD  D1 DA       rcr dx,1h
 05CF  D1 DB       rcr bx,1h
 05D1  D0 DC       rcr ah,1h
@@ -787,7 +787,7 @@
 05EB  74 02       je 5efh
 05ED  FE C9       dec cl
 05EF  91          xchg ax,cx
-05F0  32 36 C6 0F xor dh,byte ptr [0fc6h]
+05F0  32 36 EE 10 xor dh,byte ptr [10eeh]
 05F4  3C 00       cmp al,0h
 05F6  75 06       jne 5feh
 05F8  31 C0       xor ax,ax
@@ -836,29 +836,29 @@
 064C  B0 01       mov al,1h
 064E  B4 4C       mov ah,4ch
 0650  CD 21       int 21h
-0652  89 0E D0 0F mov word ptr [0fd0h],cx
+0652  89 0E F8 10 mov word ptr [10f8h],cx
 0656  8B CA       mov cx,dx
 0658  31 F9       xor cx,di
 065A  F6 D5       not ch
 065C  80 E5 80    and ch,80h
-065F  88 2E C6 0F mov byte ptr [0fc6h],ch
+065F  88 2E EE 10 mov byte ptr [10eeh],ch
 0663  80 CE 80    or dh,80h
 0666  81 CF 00 80 or di,8000h
-066A  89 36 D2 0F mov word ptr [0fd2h],si
-066E  89 3E D4 0F mov word ptr [0fd4h],di
-0672  A2 CA 0F    mov byte ptr [0fcah],al
-0675  BF CF 0F    mov di,0fcfh
+066A  89 36 FA 10 mov word ptr [10fah],si
+066E  89 3E FC 10 mov word ptr [10fch],di
+0672  A2 F2 10    mov byte ptr [10f2h],al
+0675  BF F7 10    mov di,10f7h
 0678  B1 05       mov cl,5h
 067A  BE 08 00    mov si,8h
-067D  3B 16 D4 0F cmp dx,word ptr [0fd4h]
+067D  3B 16 FC 10 cmp dx,word ptr [10fch]
 0681  75 0A       jne 68dh
-0683  3B 1E D2 0F cmp bx,word ptr [0fd2h]
+0683  3B 1E FA 10 cmp bx,word ptr [10fah]
 0687  75 04       jne 68dh
-0689  3A 26 D1 0F cmp ah,byte ptr [0fd1h]
+0689  3A 26 F9 10 cmp ah,byte ptr [10f9h]
 068D  72 0C       jb 69bh
-068F  2A 26 D1 0F sub ah,byte ptr [0fd1h]
-0693  1B 1E D2 0F sbb bx,word ptr [0fd2h]
-0697  1B 16 D4 0F sbb dx,word ptr [0fd4h]
+068F  2A 26 F9 10 sub ah,byte ptr [10f9h]
+0693  1B 1E FA 10 sbb bx,word ptr [10fah]
+0697  1B 16 FC 10 sbb dx,word ptr [10fch]
 069B  F5          cmc
 069C  D0 D5       rcl ch,1h
 069E  4E          dec si
@@ -872,24 +872,24 @@
 06AD  D1 D3       rcl bx,1h
 06AF  D1 D2       rcl dx,1h
 06B1  73 CA       jnb 67dh
-06B3  2A 26 D1 0F sub ah,byte ptr [0fd1h]
-06B7  1B 1E D2 0F sbb bx,word ptr [0fd2h]
-06BB  1B 16 D4 0F sbb dx,word ptr [0fd4h]
+06B3  2A 26 F9 10 sub ah,byte ptr [10f9h]
+06B7  1B 1E FA 10 sbb bx,word ptr [10fah]
+06BB  1B 16 FC 10 sbb dx,word ptr [10fch]
 06BF  F8          clc
 06C0  EB D9       jmp 69bh
 06C2  D0 E4       shl ah,1h
 06C4  D1 D3       rcl bx,1h
 06C6  D1 D2       rcl dx,1h
 06C8  72 11       jb 6dbh
-06CA  3B 16 D4 0F cmp dx,word ptr [0fd4h]
+06CA  3B 16 FC 10 cmp dx,word ptr [10fch]
 06CE  75 0A       jne 6dah
-06D0  3B 1E D2 0F cmp bx,word ptr [0fd2h]
+06D0  3B 1E FA 10 cmp bx,word ptr [10fah]
 06D4  75 04       jne 6dah
-06D6  3A 26 D1 0F cmp ah,byte ptr [0fd1h]
+06D6  3A 26 F9 10 cmp ah,byte ptr [10f9h]
 06DA  F5          cmc
-06DB  8B 0E CA 0F mov cx,word ptr [0fcah]
-06DF  8B 1E CC 0F mov bx,word ptr [0fcch]
-06E3  8B 16 CE 0F mov dx,word ptr [0fceh]
+06DB  8B 0E F2 10 mov cx,word ptr [10f2h]
+06DF  8B 1E F4 10 mov bx,word ptr [10f4h]
+06E3  8B 16 F6 10 mov dx,word ptr [10f6h]
 06E7  9F          lahf
 06E8  F6 C6 80    test dh,80h
 06EB  75 09       jne 6f6h
@@ -1032,47 +1032,47 @@
 07F1  B5 00       mov ch,0h
 07F3  B6 00       mov dh,0h
 07F5  51          push cx
-07F6  BB 20 10    mov bx,1020h
+07F6  BB 48 11    mov bx,1148h
 07F9  E8 41 02    call 0a3dh
 07FC  59          pop cx
 07FD  89 D8       mov ax,bx
-07FF  BB 20 10    mov bx,1020h
+07FF  BB 48 11    mov bx,1148h
 0802  2B C3       sub ax,bx
-0804  A3 60 10    mov word ptr [1060h],ax
-0807  89 0E 62 10 mov word ptr [1062h],cx
-080B  8B 06 62 10 mov ax,word ptr [1062h]
-080F  8B 16 60 10 mov dx,word ptr [1060h]
+0804  A3 88 11    mov word ptr [1188h],ax
+0807  89 0E 8A 11 mov word ptr [118ah],cx
+080B  8B 06 8A 11 mov ax,word ptr [118ah]
+080F  8B 16 88 11 mov dx,word ptr [1188h]
 0813  2B C2       sub ax,dx
 0815  83 F8 00    cmp ax,0h
 0818  7D 02       jnl 81ch
 081A  31 C0       xor ax,ax
-081C  A3 64 10    mov word ptr [1064h],ax
-081F  8B 16 60 10 mov dx,word ptr [1060h]
+081C  A3 8C 11    mov word ptr [118ch],ax
+081F  8B 16 88 11 mov dx,word ptr [1188h]
 0823  03 C2       add ax,dx
 0825  3D FF 00    cmp ax,0ffh
 0828  77 03       jnbe 82dh
 082A  E9 03 00    jmp 830h
 082D  B8 FF 00    mov ax,0ffh
-0830  A3 66 10    mov word ptr [1066h],ax
+0830  A3 8E 11    mov word ptr [118eh],ax
 0833  8B 56 06    mov dx,word ptr [bp+6h]
 0836  89 D7       mov di,dx
 0838  88 05       mov byte ptr [di],al
 083A  47          inc di
-083B  8B 0E 64 10 mov cx,word ptr [1064h]
+083B  8B 0E 8C 11 mov cx,word ptr [118ch]
 083F  E3 07       jcxz 848h
 0841  B0 20       mov al,20h
 0843  88 05       mov byte ptr [di],al
 0845  47          inc di
 0846  E2 F9       loop 841h
-0848  BE 20 10    mov si,1020h
-084B  8B 0E 60 10 mov cx,word ptr [1060h]
+0848  BE 48 11    mov si,1148h
+084B  8B 0E 88 11 mov cx,word ptr [1188h]
 084F  E3 08       jcxz 859h
 0851  8A 04       mov al,byte ptr [si]
 0853  88 05       mov byte ptr [di],al
 0855  46          inc si
 0856  47          inc di
 0857  E2 F8       loop 851h
-0859  8B 06 66 10 mov ax,word ptr [1066h]
+0859  8B 06 8E 11 mov ax,word ptr [118eh]
 085D  5F          pop di
 085E  5E          pop si
 085F  5A          pop dx
@@ -1088,12 +1088,12 @@
 086B  57          push di
 086C  8B 5E 04    mov bx,word ptr [bp+4h]
 086F  8B 7E 06    mov di,word ptr [bp+6h]
-0872  89 1E 68 10 mov word ptr [1068h],bx
+0872  89 1E 90 11 mov word ptr [1190h],bx
 0876  E8 CF 02    call 0b48h
 0879  73 03       jnb 87eh
 087B  E9 0B 00    jmp 889h
 087E  89 D8       mov ax,bx
-0880  8B 16 68 10 mov dx,word ptr [1068h]
+0880  8B 16 90 11 mov dx,word ptr [1190h]
 0884  2B C2       sub ax,dx
 0886  E9 03 00    jmp 88ch
 0889  B8 FF FF    mov ax,0ffffh
@@ -1142,7 +1142,7 @@
 08D3  52          push dx
 08D4  53          push bx
 08D5  50          push ax
-08D6  88 0E E2 0F mov byte ptr [0fe2h],cl
+08D6  88 0E 0A 11 mov byte ptr [110ah],cl
 08DA  80 F9 00    cmp cl,0h
 08DD  78 03       js 8e2h
 08DF  E9 02 00    jmp 8e4h
@@ -1153,7 +1153,7 @@
 08EB  D0 EB       shr bl,1h
 08ED  00 FB       add bl,bh
 08EF  30 FF       xor bh,bh
-08F1  8D BF E4 0F lea di,[bx+0fe4h]
+08F1  8D BF 0C 11 lea di,[bx+110ch]
 08F5  8B 05       mov ax,word ptr [di]
 08F7  8B 5D 02    mov bx,word ptr [di+2h]
 08FA  8B 55 04    mov dx,word ptr [di+4h]
@@ -1170,7 +1170,7 @@
 0915  58          pop ax
 0916  5B          pop bx
 0917  5A          pop dx
-0918  F6 06 E2 0F 80 test byte ptr [0fe2h],80h
+0918  F6 06 0A 11 80 test byte ptr [110ah],80h
 091D  74 03       je 922h
 091F  E9 03 00    jmp 925h
 0922  E9 27 FC    jmp 54ch
@@ -1197,11 +1197,11 @@
 094C  3C 00       cmp al,0h
 094E  74 03       je 953h
 0950  E9 16 00    jmp 969h
-0953  BE D6 0F    mov si,0fd6h
+0953  BE FE 10    mov si,10feh
 0956  C7 04 30 30 mov word ptr [si],3030h
 095A  46          inc si
 095B  46          inc si
-095C  81 FE E2 0F cmp si,0fe2h
+095C  81 FE 0A 11 cmp si,110ah
 0960  74 03       je 965h
 0962  E9 F1 FF    jmp 956h
 0965  B9 00 00    mov cx,0h
@@ -1245,7 +1245,7 @@
 09B4  FE C9       dec cl
 09B6  74 03       je 9bbh
 09B8  E9 F3 FF    jmp 9aeh
-09BB  BE D6 0F    mov si,0fd6h
+09BB  BE FE 10    mov si,10feh
 09BE  88 F5       mov ch,dh
 09C0  B1 04       mov cl,4h
 09C2  D2 ED       shr ch,cl
@@ -1271,13 +1271,13 @@
 09E6  D1 D3       rcl bx,1h
 09E8  D1 D2       rcl dx,1h
 09EA  46          inc si
-09EB  81 FE E2 0F cmp si,0fe2h
+09EB  81 FE 0A 11 cmp si,110ah
 09EF  74 03       je 9f4h
 09F1  E9 CA FF    jmp 9beh
 09F4  59          pop cx
 09F5  C3          ret
 09F6  30 E4       xor ah,ah
-09F8  BB D6 0F    mov bx,0fd6h
+09F8  BB FE 10    mov bx,10feh
 09FB  03 D8       add bx,ax
 09FD  80 3F 35    cmp byte ptr [bx],35h
 0A00  C6 07 00    mov byte ptr [bx],0h
@@ -1348,7 +1348,7 @@
 0A97  00 C8       add al,cl
 0A99  78 03       js 0a9eh
 0A9B  E9 08 00    jmp 0aa6h
-0A9E  C6 06 D6 0F 00 mov byte ptr [0fd6h],0h
+0A9E  C6 06 FE 10 00 mov byte ptr [10feh],0h
 0AA3  E9 0C 00    jmp 0ab2h
 0AA6  3C 0C       cmp al,0ch
 0AA8  73 03       jnb 0aadh
@@ -1356,7 +1356,7 @@
 0AAD  B0 0B       mov al,0bh
 0AAF  E8 44 FF    call 9f6h
 0AB2  5B          pop bx
-0AB3  BE D6 0F    mov si,0fd6h
+0AB3  BE FE 10    mov si,10feh
 0AB6  F6 C5 80    test ch,80h
 0AB9  75 03       jne 0abeh
 0ABB  E9 05 00    jmp 0ac3h
@@ -1442,7 +1442,7 @@
 0B7A  31 DB       xor bx,bx
 0B7C  31 D2       xor dx,dx
 0B7E  31 C9       xor cx,cx
-0B80  C6 06 E3 0F 00 mov byte ptr [0fe3h],0h
+0B80  C6 06 0B 11 00 mov byte ptr [110bh],0h
 0B85  8A 0C       mov cl,byte ptr [si]
 0B87  80 F9 61    cmp cl,61h
 0B8A  73 03       jnb 0b8fh
@@ -1471,7 +1471,7 @@
 0BBA  58          pop ax
 0BBB  5B          pop bx
 0BBC  5A          pop dx
-0BBD  C7 06 C5 0F 00 00 mov word ptr [0fc5h],0h
+0BBD  C7 06 ED 10 00 00 mov word ptr [10edh],0h
 0BC3  E8 60 F8    call 426h
 0BC6  59          pop cx
 0BC7  5E          pop si
@@ -1479,7 +1479,7 @@
 0BC9  F6 C5 40    test ch,40h
 0BCC  75 03       jne 0bd1h
 0BCE  E9 04 00    jmp 0bd5h
-0BD1  FE 0E E3 0F dec byte ptr [0fe3h]
+0BD1  FE 0E 0B 11 dec byte ptr [110bh]
 0BD5  46          inc si
 0BD6  E9 AC FF    jmp 0b85h
 0BD9  80 F9 2E    cmp cl,2eh
@@ -1491,7 +1491,7 @@
 0BE9  80 CD 40    or ch,40h
 0BEC  E9 E6 FF    jmp 0bd5h
 0BEF  80 F9 45    cmp cl,45h
-0BF2  8A 0E E3 0F mov cl,byte ptr [0fe3h]
+0BF2  8A 0E 0B 11 mov cl,byte ptr [110bh]
 0BF6  74 03       je 0bfbh
 0BF8  E9 4D 00    jmp 0c48h
 0BFB  E8 2A FD    call 928h
@@ -1557,31 +1557,31 @@
 0C7C  56          push si
 0C7D  57          push di
 0C7E  8B 46 06    mov ax,word ptr [bp+6h]
-0C81  A3 62 10    mov word ptr [1062h],ax
+0C81  A3 8A 11    mov word ptr [118ah],ax
 0C84  8B 56 04    mov dx,word ptr [bp+4h]
 0C87  8B 4E 06    mov cx,word ptr [bp+6h]
 0C8A  8B 7E 08    mov di,word ptr [bp+8h]
-0C8D  BB 20 10    mov bx,1020h
+0C8D  BB 48 11    mov bx,1148h
 0C90  E8 AA FD    call 0a3dh
 0C93  89 D8       mov ax,bx
-0C95  BB 20 10    mov bx,1020h
+0C95  BB 48 11    mov bx,1148h
 0C98  2B C3       sub ax,bx
-0C9A  A3 60 10    mov word ptr [1060h],ax
-0C9D  8B 06 62 10 mov ax,word ptr [1062h]
-0CA1  8B 16 60 10 mov dx,word ptr [1060h]
+0C9A  A3 88 11    mov word ptr [1188h],ax
+0C9D  8B 06 8A 11 mov ax,word ptr [118ah]
+0CA1  8B 16 88 11 mov dx,word ptr [1188h]
 0CA5  2B C2       sub ax,dx
 0CA7  83 F8 00    cmp ax,0h
 0CAA  7D 02       jnl 0caeh
 0CAC  31 C0       xor ax,ax
-0CAE  A3 64 10    mov word ptr [1064h],ax
-0CB1  8B 0E 64 10 mov cx,word ptr [1064h]
+0CAE  A3 8C 11    mov word ptr [118ch],ax
+0CB1  8B 0E 8C 11 mov cx,word ptr [118ch]
 0CB5  E3 08       jcxz 0cbfh
 0CB7  B0 20       mov al,20h
 0CB9  B4 02       mov ah,2h
 0CBB  CD 21       int 21h
 0CBD  E2 F8       loop 0cb7h
-0CBF  BE 20 10    mov si,1020h
-0CC2  8B 0E 60 10 mov cx,word ptr [1060h]
+0CBF  BE 48 11    mov si,1148h
+0CC2  8B 0E 88 11 mov cx,word ptr [1188h]
 0CC6  E3 09       jcxz 0cd1h
 0CC8  8A 04       mov al,byte ptr [si]
 0CCA  B4 02       mov ah,2h
@@ -1752,14 +1752,14 @@
 0DE9  B8 01 00    mov ax,1h
 0DEC  89 45 02    mov word ptr [di+2h],ax
 0DEF  31 C0       xor ax,ax
-0DF1  A3 6A 10    mov word ptr [106ah],ax
+0DF1  A3 92 11    mov word ptr [1192h],ax
 0DF4  EB 10       jmp 0e06h
 0DF6  89 C3       mov bx,ax
 0DF8  B8 FF FF    mov ax,0ffffh
 0DFB  89 05       mov word ptr [di],ax
 0DFD  31 C0       xor ax,ax
 0DFF  89 45 02    mov word ptr [di+2h],ax
-0E02  89 1E 6A 10 mov word ptr [106ah],bx
+0E02  89 1E 92 11 mov word ptr [1192h],bx
 0E06  5F          pop di
 0E07  5A          pop dx
 0E08  59          pop cx
@@ -1783,14 +1783,14 @@
 0E26  B8 02 00    mov ax,2h
 0E29  89 45 02    mov word ptr [di+2h],ax
 0E2C  31 C0       xor ax,ax
-0E2E  A3 6A 10    mov word ptr [106ah],ax
+0E2E  A3 92 11    mov word ptr [1192h],ax
 0E31  EB 10       jmp 0e43h
 0E33  89 C3       mov bx,ax
 0E35  B8 FF FF    mov ax,0ffffh
 0E38  89 05       mov word ptr [di],ax
 0E3A  31 C0       xor ax,ax
 0E3C  89 45 02    mov word ptr [di+2h],ax
-0E3F  89 1E 6A 10 mov word ptr [106ah],bx
+0E3F  89 1E 92 11 mov word ptr [1192h],bx
 0E43  5F          pop di
 0E44  5A          pop dx
 0E45  59          pop cx
@@ -1815,33 +1815,185 @@
 0E66  89 05       mov word ptr [di],ax
 0E68  31 C0       xor ax,ax
 0E6A  89 45 02    mov word ptr [di+2h],ax
-0E6D  89 1E 6A 10 mov word ptr [106ah],bx
+0E6D  89 1E 92 11 mov word ptr [1192h],bx
 0E71  5F          pop di
 0E72  5A          pop dx
 0E73  5B          pop bx
 0E74  89 EC       mov sp,bp
 0E76  5D          pop bp
 0E77  C3          ret
-0E78  8B 06 6A 10 mov ax,word ptr [106ah]
-0E7C  C7 06 6A 10 00 00 mov word ptr [106ah],0h
+0E78  8B 06 92 11 mov ax,word ptr [1192h]
+0E7C  C7 06 92 11 00 00 mov word ptr [1192h],0h
 0E82  C3          ret
-0E83  A3 6A 10    mov word ptr [106ah],ax
+0E83  A3 92 11    mov word ptr [1192h],ax
 0E86  C3          ret
 0E87  55          push bp
 0E88  8B EC       mov bp,sp
 0E8A  53          push bx
 0E8B  51          push cx
 0E8C  52          push dx
-0E8D  8B 1E 6C 10 mov bx,word ptr [106ch]
+0E8D  8B 1E 94 11 mov bx,word ptr [1194h]
 0E91  8B 56 04    mov dx,word ptr [bp+4h]
 0E94  89 1A       mov word ptr [bp+si],bx
 0E96  8B 4E 06    mov cx,word ptr [bp+6h]
 0E99  89 D8       mov ax,bx
 0E9B  03 C1       add ax,cx
-0E9D  A3 6C 10    mov word ptr [106ch],ax
+0E9D  A3 94 11    mov word ptr [1194h],ax
 0EA0  5A          pop dx
 0EA1  59          pop cx
 0EA2  5B          pop bx
 0EA3  89 EC       mov sp,bp
 0EA5  5D          pop bp
 0EA6  C3          ret
+0EA7  55          push bp
+0EA8  8B EC       mov bp,sp
+0EAA  53          push bx
+0EAB  51          push cx
+0EAC  52          push dx
+0EAD  56          push si
+0EAE  57          push di
+0EAF  A0 96 11    mov al,byte ptr [1196h]
+0EB2  3C 00       cmp al,0h
+0EB4  75 42       jne 0ef8h
+0EB6  8B 7E 04    mov di,word ptr [bp+4h]
+0EB9  8B 05       mov ax,word ptr [di]
+0EBB  3D FF FF    cmp ax,0ffffh
+0EBE  74 38       je 0ef8h
+0EC0  89 C3       mov bx,ax
+0EC2  31 C9       xor cx,cx
+0EC4  31 D2       xor dx,dx
+0EC6  B8 01 42    mov ax,4201h
+0EC9  CD 21       int 21h
+0ECB  8B F0       mov si,ax
+0ECD  89 D7       mov di,dx
+0ECF  31 C9       xor cx,cx
+0ED1  31 D2       xor dx,dx
+0ED3  B8 02 42    mov ax,4202h
+0ED6  CD 21       int 21h
+0ED8  39 FA       cmp dx,di
+0EDA  72 08       jb 0ee4h
+0EDC  77 0B       jnbe 0ee9h
+0EDE  39 F0       cmp ax,si
+0EE0  72 02       jb 0ee4h
+0EE2  77 05       jnbe 0ee9h
+0EE4  B8 01 00    mov ax,1h
+0EE7  EB 02       jmp 0eebh
+0EE9  31 C0       xor ax,ax
+0EEB  50          push ax
+0EEC  89 F9       mov cx,di
+0EEE  89 F2       mov dx,si
+0EF0  B8 00 42    mov ax,4200h
+0EF3  CD 21       int 21h
+0EF5  58          pop ax
+0EF6  EB 03       jmp 0efbh
+0EF8  B8 01 00    mov ax,1h
+0EFB  5F          pop di
+0EFC  5E          pop si
+0EFD  5A          pop dx
+0EFE  59          pop cx
+0EFF  5B          pop bx
+0F00  89 EC       mov sp,bp
+0F02  5D          pop bp
+0F03  C3          ret
+0F04  55          push bp
+0F05  8B EC       mov bp,sp
+0F07  53          push bx
+0F08  51          push cx
+0F09  52          push dx
+0F0A  56          push si
+0F0B  57          push di
+0F0C  8B 7E 06    mov di,word ptr [bp+6h]
+0F0F  C6 05 00    mov byte ptr [di],0h
+0F12  47          inc di
+0F13  31 C9       xor cx,cx
+0F15  8B 76 04    mov si,word ptr [bp+4h]
+0F18  8B 04       mov ax,word ptr [si]
+0F1A  89 C3       mov bx,ax
+0F1C  BA 97 11    mov dx,1197h
+0F1F  B9 01 00    mov cx,1h
+0F22  B4 3F       mov ah,3fh
+0F24  CD 21       int 21h
+0F26  83 F8 00    cmp ax,0h
+0F29  74 1C       je 0f47h
+0F2B  A0 97 11    mov al,byte ptr [1197h]
+0F2E  3C 1A       cmp al,1ah
+0F30  74 1C       je 0f4eh
+0F32  3C 0D       cmp al,0dh
+0F34  74 E2       je 0f18h
+0F36  3C 0A       cmp al,0ah
+0F38  74 19       je 0f53h
+0F3A  8B 46 08    mov ax,word ptr [bp+8h]
+0F3D  39 C8       cmp ax,cx
+0F3F  76 D7       jbe 0f18h
+0F41  88 05       mov byte ptr [di],al
+0F43  47          inc di
+0F44  41          inc cx
+0F45  EB D1       jmp 0f18h
+0F47  C6 06 96 11 01 mov byte ptr [1196h],1h
+0F4C  EB 05       jmp 0f53h
+0F4E  C6 06 96 11 01 mov byte ptr [1196h],1h
+0F53  8B 5E 06    mov bx,word ptr [bp+6h]
+0F56  88 0F       mov byte ptr [bx],cl
+0F58  31 C0       xor ax,ax
+0F5A  A3 92 11    mov word ptr [1192h],ax
+0F5D  5F          pop di
+0F5E  5E          pop si
+0F5F  5A          pop dx
+0F60  59          pop cx
+0F61  5B          pop bx
+0F62  89 EC       mov sp,bp
+0F64  5D          pop bp
+0F65  C3          ret
+0F66  55          push bp
+0F67  8B EC       mov bp,sp
+0F69  53          push bx
+0F6A  51          push cx
+0F6B  52          push dx
+0F6C  56          push si
+0F6D  57          push di
+0F6E  8B 7E 04    mov di,word ptr [bp+4h]
+0F71  C6 05 00    mov byte ptr [di],0h
+0F74  47          inc di
+0F75  8B 46 06    mov ax,word ptr [bp+6h]
+0F78  C6 06 97 11 00 mov byte ptr [1197h],0h
+0F7D  83 F8 00    cmp ax,0h
+0F80  7D 07       jnl 0f89h
+0F82  C6 06 97 11 01 mov byte ptr [1197h],1h
+0F87  F7 D8       neg ax
+0F89  B9 0A 00    mov cx,0ah
+0F8C  BB D7 10    mov bx,10d7h
+0F8F  89 DE       mov si,bx
+0F91  31 D2       xor dx,dx
+0F93  F7 F1       div ax,cx
+0F95  80 C2 30    add dl,30h
+0F98  4E          dec si
+0F99  88 14       mov byte ptr [si],dl
+0F9B  83 F8 00    cmp ax,0h
+0F9E  75 F1       jne 0f91h
+0FA0  A0 97 11    mov al,byte ptr [1197h]
+0FA3  3C 00       cmp al,0h
+0FA5  74 04       je 0fabh
+0FA7  C6 05 2D    mov byte ptr [di],2dh
+0FAA  47          inc di
+0FAB  89 D9       mov cx,bx
+0FAD  29 F1       sub cx,si
+0FAF  A0 97 11    mov al,byte ptr [1197h]
+0FB2  3C 00       cmp al,0h
+0FB4  74 01       je 0fb7h
+0FB6  41          inc cx
+0FB7  8A D1       mov dl,cl
+0FB9  8A 04       mov al,byte ptr [si]
+0FBB  88 05       mov byte ptr [di],al
+0FBD  46          inc si
+0FBE  47          inc di
+0FBF  E2 F8       loop 0fb9h
+0FC1  8B 5E 04    mov bx,word ptr [bp+4h]
+0FC4  88 17       mov byte ptr [bx],dl
+0FC6  5F          pop di
+0FC7  5E          pop si
+0FC8  5A          pop dx
+0FC9  59          pop cx
+0FCA  5B          pop bx
+0FCB  89 EC       mov sp,bp
+0FCD  5D          pop bp
+0FCE  C3          ret