Browse Source

calc: file control-block operations (ladder 22706)

Exist's body now compiles: Assign, Reset, Rewrite, Close and IOResult are
builtins, backed by runtime entries 34..38.  The file variable grows to 132
bytes (handle, mode, 128-byte NUL-terminated name); Assign copies the counted
filename into it, Reset/Rewrite issue DOS AH=3Dh/3Ch, Close issues AH=3Eh, and
IOResult returns and clears the last status.

The boot floppy and Exec86 have no filesystem.  Both now answer AH=3Dh with
CF=1 and AX=2, the DOS "file not found" result, so t88_fileops (assign,
reset, IOResult, close) runs under qemu and Exec86.  rt_exec gets a
file_assign case that checks the copied name; the runtime golden is
re-blessed for the new entries and data offsets.  Eof and data read/write are
still refused (next file increment), and are not on this rung's ladder path.

The CALC ladder moves 22280 -> 22706; the next blocker is `var Line :
AnyString' in GetFileName, a VAR string parameter.  Runtime is now 3907 bytes
(39 entries), 45 bytes below the probe's HDR, so the next runtime addition
must move that scaffold.

Verified: compile matrix 89/89, ladder 1/1, 80 .COM linked, 78 executed under
both qemu and Exec86, rt_exec 276/276, nonvacuity 121/121, run_all ALL PASS.
Eric Streit 1 day ago
parent
commit
ab7cced34a

+ 49 - 39
CALC-COMPILE.md

@@ -97,7 +97,7 @@ Current rung (measured today, normalised position):
 
 
 | position | blocker |
 | position | blocker |
 |---|---|
 |---|---|
-| **22280** | `assign(F, FileN)` in `Exist` — file operations (`ERR 41`) |
+| **22706** | `var Line : AnyString` in `GetFileName` — VAR string parameters (`ERR 102`) |
 
 
 Rungs behind it (now passed):
 Rungs behind it (now passed):
 
 
@@ -133,7 +133,8 @@ Rungs ahead:
 
 
 | position | blocker |
 | position | blocker |
 |---|---|
 |---|---|
-| 22280 | file operations (`Assign`, `Reset`, `Rewrite`, `Close`, `IoResult`, `EndOfFile`) |
+| 22280 | file operations (`Assign`, `Reset`, `Rewrite`, `Close`, `IoResult`) - done by the file control-block rung |
+| 22706 | `var Line : AnyString` - a by-reference string parameter |
 
 
 Corrections the measurements force, worth stating plainly because the stage list
 Corrections the measurements force, worth stating plainly because the stage list
 below was written before them:
 below was written before them:
@@ -342,7 +343,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
    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.
    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.**
 2. **`MaxCode = 24,000` is not the binding constraint for the compile goal.**
-   16,560 + 3,667 (our current runtime) = 20,227, comfortably inside 24,000.
+   16,560 + 3,907 (our current runtime) = 20,467, comfortably inside 24,000.
    The old `dataBase` alone had to move; `t43_codewindow` was the fixture that
    The old `dataBase` alone had to move; `t43_codewindow` was the fixture that
    policed it and has been re-baselined (§3.2).
    policed it and has been re-baselined (§3.2).
 3. **The §3 data budget is confirmed, not inferred.** Reported data is
 3. **The §3 data budget is confirmed, not inferred.** Reported data is
@@ -355,7 +356,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
    **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
    `A000h` as the maximum (640 KiB, in paragraphs). A `.COM` still uses
    separate CS/DS segments; the original proves it.
    separate CS/DS segments; the original proves it.
-5. **The runtime is 11,341 bytes** in the original. Ours is 3,667 B. It
+5. **The runtime is 11,341 bytes** in the original. Ours is 3,907 B. It
    explains where the original's fixed `pc := $2D7C` / `dc := $0240` came
    explains where the original's fixed `pc := $2D7C` / `dc := $0240` came
    from, and why `TPSRC7:81-82` looks the way it does.
    from, and why `TPSRC7:81-82` looks the way it does.
 
 
@@ -422,7 +423,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
 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
 separate DS described by the inline parameters. Our CALC image will be smaller
-in runtime (3,667 B instead of 11,341 B) but has the same code-only, high-data
+in runtime (3,907 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
 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.
 not layout but the untyped `file` declaration; that is fixed in the next rung.
 
 
@@ -453,9 +454,10 @@ calling convention and string value parameters, `Length`, the CRT identifiers,
 subscripts, write field widths, WITH with n-dimensional subscripts, set-field
 subscripts, write field widths, WITH with n-dimensional subscripts, set-field
 assignment, string fields through DI, REAL constants, UpCase, run-time set
 assignment, string fields through DI, REAL constants, UpCase, run-time set
 membership, string fields in WRITE, real output, run-time set algebra,
 membership, string fields in WRITE, real output, run-time set algebra,
-`Succ`/`Pred`, the original memory layout, and the untyped file type). The
-ladder has moved from the first typed constant at 7,791 to **22,280**, where
-`assign(F, FileN)` is the first file operation.
+`Succ`/`Pred`, the original memory layout, the untyped file type, and the
+file control-block operations). The
+ladder has moved from the first typed constant at 7,791 to **22,706**, where
+`var Line : AnyString` is the first by-reference string parameter.
 
 
 The rung commits and their tags, in order (each is one rung with its own
 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
 fixture, red proof, and — where the harness allows — execution under qemu and
@@ -491,7 +493,8 @@ Exec86):
 | `17f7f7c` | `v-TP3-CALC-UPCASE` | **`ERR 102 18267`** (real output) |
 | `17f7f7c` | `v-TP3-CALC-UPCASE` | **`ERR 102 18267`** (real output) |
 | `203f77e` | `v-TP3-CALC-SETOPS` | `ERR 98 20912` (layout limit reached) |
 | `203f77e` | `v-TP3-CALC-SETOPS` | `ERR 98 20912` (layout limit reached) |
 | `ff05141` | `v-TP3-CALC-LAYOUT` | `ERR 1 22253` (untyped file, initially misread as a function) |
 | `ff05141` | `v-TP3-CALC-LAYOUT` | `ERR 1 22253` (untyped file, initially misread as a function) |
-| *(this commit)* | `v-TP3-CALC-UNTYPEDFILE` | **`ERR 41 22280`** (`assign`) |
+| `ed9e790` | `v-TP3-CALC-UNTYPEDFILE` | `ERR 41 22280` (`assign`) |
+| *(this commit)* | `v-TP3-CALC-FILEOPS` | **`ERR 102 22706`** (VAR string parameter) |
 
 
 - **Code HEAD** is the layout rung (`v-TP3-CALC-LAYOUT`).  Nothing is pushed.
 - **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
   The terminal-config work (`v-TP3-TERMCFG`) and the editor key map
@@ -533,13 +536,16 @@ Exec86):
   Fixture `t64_arrays` (compile-only because it has no `.out`; its ~16 KB
   Fixture `t64_arrays` (compile-only because it has no `.out`; its ~16 KB
   image now fits the raised 0x7000-byte read). `t14` re-baselined: the array
   image now fits the raised 0x7000-byte read). `t14` re-baselined: the array
   DECLARES now; the refusal moved to element access.
   DECLARES now; the refusal moved to element access.
-- **File TYPES are landed (Stage 13, first half).** `text` and `file of T`; a
-  file variable is our control block (`FileVarSize` = 4). Fixture `t66_files`.
-  This is the step that carried the compiler **inside `CALC.INC`**: the whole
+- **File TYPES and the control-block OPERATIONS are landed (Stage 13).**
+  `text`, `file of T`, and untyped `file`; a file variable is our control block
+  (`FileVarSize` = 132: handle, mode, 128-byte NUL-terminated name).  The
+  operations `Assign`/`Reset`/`Rewrite`/`Close`/`IoResult` are runtime entries
+  using real DOS `INT 21h`; `t88_fileops` runs the missing-file path under both
+  qemu and Exec86, and `rt_exec` pins the name copy.  Data `Read`/`Write` with
+  a leading file argument is the remaining file increment and is still loud.
+  File types were what carried the compiler **inside `CALC.INC`**: the whole
   `var` block passed and the `{$I}` expanded, so the rung jumped from 9202 to
   `var` block passed and the `{$I}` expanded, so the rung jumped from 9202 to
-  **10350**, where the first blocker is a string VALUE parameter in a nested
-  procedure. File OPERATIONS (`Assign`/`Reset`/…, read/write with a file
-  argument) are the next increment and are loud until then.
+  **10350**.
 - **String VALUE parameters are landed** (TP3's whole-slot copy).  Three
 - **String VALUE parameters are landed** (TP3's whole-slot copy).  Three
   commits: slot sizes (`v-TP3-CALC-PARAMSLOTS`), the parameter list on the proc
   commits: slot sizes (`v-TP3-CALC-PARAMSLOTS`), the parameter list on the proc
   symbol (`v-TP3-CALC-PARAMLIST`), and the copy + `size > 2` for strings
   symbol (`v-TP3-CALC-PARAMLIST`), and the copy + `size > 2` for strings
@@ -599,7 +605,7 @@ Exec86):
   `ERR 1 22253`, terminal config **4/4**, 78 `.COM` linked and **76 executed
   `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
   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
   has no `.out`).  `tests/nonvacuity.sh`: **121 ok, 0 failed**.  The runtime is
-  3,667 bytes (wrintw, real_from_int, real_add, real_sub, real_mul, real_div,
+  3,907 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,
   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
   set_copy; the golden was re-blessed) and `tests/rt_exec.py` passes
   **275/275**, including the MBF arithmetic/output/parse cases and eleven
   **275/275**, including the MBF arithmetic/output/parse cases and eleven
@@ -662,10 +668,11 @@ commit.
 2. **The rest of the declaration part**, if the rung is still there: local
 2. **The rest of the declaration part**, if the rung is still there: local
    `type`/`const`/`var` inside a nested function (`CALC.INC:767-778`, the
    `type`/`const`/`var` inside a nested function (`CALC.INC:767-778`, the
    enum-indexed array of strings), `Succ`/`Pred`/`Ord`/`Chr`.
    enum-indexed array of strings), `Succ`/`Pred`/`Ord`/`Chr`.
-3. **File OPERATIONS** (`Assign`, `Reset`, `Rewrite`, `Close`, `EndOfFile`,
-   `IoResult`; `read`/`write` with a leading file argument).  Runtime entries
-   doing `INT 21h` open/create/read/write/close, text-mode newline and `^Z`.
-   The file *types* and variables are already in place (`FileVarSize`).
+3. **File OPERATIONS — control block DONE** (`v-TP3-CALC-FILEOPS`):
+   `Assign`, `Reset`, `Rewrite`, `Close`, `IoResult` are runtime entries over
+   real DOS `INT 21h`; `t88_fileops` checks the missing-file path under both
+   oracles.  **Still open:** `EndOfFile` and `read`/`write` with a leading file
+   argument, which need text-mode newline/`^Z` and typed-file block I/O.
 4. **Array subscripts and `with` — DONE** (`v-TP3-CALC-ARRVAR`,
 4. **Array subscripts and `with` — DONE** (`v-TP3-CALC-ARRVAR`,
    `v-TP3-CALC-WITH`): n-dimensional subscripts use per-dimension strides
    `v-TP3-CALC-WITH`): n-dimensional subscripts use per-dimension strides
    (the last varies fastest), the element's address rides in DI, and `with`
    (the last varies fastest), the element's address rides in DI, and `with`
@@ -816,11 +823,11 @@ Then the two that are *outside* the ladder and gate the goal as stated:
       * **STILL TO COME:** function declarations/returns, then `Str`/`Val`
       * **STILL TO COME:** function declarations/returns, then `Str`/`Val`
         wiring, real expressions (a 6-byte temporary/value model), real
         wiring, real expressions (a 6-byte temporary/value model), real
         comparisons and real function results.
         comparisons and real function results.
-      * **HEADROOM:** the runtime is 3,667 bytes and the probe's scaffold
+      * **HEADROOM:** the runtime is 3,907 bytes and the probe's scaffold
         starts at HDR=0x1100 with RT_BASE=0x0190, so the ceiling is 3,952
         starts at HDR=0x1100 with RT_BASE=0x0190, so the ceiling is 3,952
-        bytes - about 285 bytes left.  The boot read allows a .COM up to
-        0x6F00, so the next additions can move HDR again (e.g. 0x2000) with
-        plenty of room below the input at 0x7000.
+        bytes - only about 45 bytes left.  The next runtime addition must move
+        HDR (and the probe's data block with it); the boot read allows a .COM
+        up to 0x6F00, so there is room below the input at 0x7000.
       * **Exec86** needed the FE group (INC/DEC r/m8) and CMC/CLC/STC/LAHF/
       * **Exec86** needed the FE group (INC/DEC r/m8) and CMC/CLC/STC/LAHF/
         SAHF for the formatter; t84 is the first fixture that executes the
         SAHF for the formatter; t84 is the first fixture that executes the
         real conversion under the interpreter, and it cross-checks qemu.
         real conversion under the interpreter, and it cross-checks qemu.
@@ -1090,20 +1097,23 @@ to the operand, or reused.
 **Stage 13 — files. Types DONE, including untyped `file`; operations next.**
 **Stage 13 — files. Types DONE, including untyped `file`; operations next.**
 
 
 Done: `text`, `file of T`, and untyped `file` (`t87_untypedfile`).  A file
 Done: `text`, `file of T`, and untyped `file` (`t87_untypedfile`).  A file
-variable is our own control block (`FileVarSize = 4`: the DOS handle word and a
-mode word), because this runtime
-does unbuffered `INT 21h` I/O where TP3 keeps a 128-byte buffer inside the
-variable - a recorded divergence.  `file of T` parses its element type so the
-RECORD size a Read/Write must move is known.  Fixture `t66_files`; this let the
-whole `var` block pass and the `{$I CALC.INC}` expand, which is why the ladder
-moved from `9202` to **`10350` - inside the include**.
-
-Not yet, and loud (unknown identifier): `Assign`, `Reset`, `Rewrite`, `Close`,
-`EndOfFile`, `IoResult`, and `read`/`write` with a leading file argument
-(`writeln (MCFile, Line)`, `Readln (H, Buffer^[count])`).  These need runtime
-entries doing `INT 21h` open/create/read/write/close, with text-mode newline
-and `^Z` semantics (`RESUME-TP3.md` §2).  `{$I-}`/`{$I+}` (Stage 2) already
-gate the checking that `IoResult` reports.
+variable is our own control block (`FileVarSize = 132`: the DOS handle word, a
+mode word, and a 128-byte NUL-terminated filename), because this runtime does
+unbuffered `INT 21h` I/O where TP3 keeps a 128-byte buffer inside the variable
+- a recorded divergence.  `file of T` parses its element type so the RECORD
+size a Read/Write must move is known.  Fixture `t66_files`.
+
+Control-block OPERATIONS are done (`t88_fileops`): `Assign` copies the counted
+filename, `Reset`/`Rewrite`/`Close` issue DOS `INT 21h` open/create/close, and
+`IoResult` reads and clears the status.  The boot harnesses have no filesystem,
+so both answer `AH=3Dh` with `CF=1, AX=2`; the fixture checks that error path
+under qemu and Exec86, and `rt_exec` pins the name copy.
+
+Not yet: `EndOfFile`, and `read`/`write` with a leading file argument
+(`writeln (MCFile, Line)`, `Readln (H, Buffer^[count])`).  These need
+text-mode newline/`^Z` semantics and typed-file block I/O (`RESUME-TP3.md`
+§2).  The next ladder blocker is not file data I/O, though: it is `var Line :
+AnyString`, a by-reference string parameter.
 
 
 **Stage 14 — the CRT identifiers.** `GotoXY` (25), `LowVideo`/`NormVideo`
 **Stage 14 — the CRT identifiers.** `GotoXY` (25), `LowVideo`/`NormVideo`
 (16 + 16), `ClrEol` (10), `ClrScr` (6), `KeyPressed` (3), `Delay` (1),
 (16 + 16), `ClrEol` (10), `ClrScr` (6), `KeyPressed` (3), `Delay` (1),
@@ -1147,7 +1157,7 @@ remaining run-time capacity note.
 | limit | value | CALC needs | verdict |
 | limit | value | CALC needs | verdict |
 |---|---|---|---|
 |---|---|---|---|
 | `TextLimit` (source buffer) | 62,903 | `CALC.PAS` + `CALC.INC`, normalised = **62,415** | **488 bytes of slack** |
 | `TextLimit` (source buffer) | 62,903 | `CALC.PAS` + `CALC.INC`, normalised = **62,415** | **488 bytes of slack** |
-| `MaxCode` | 24,000 | 16,560 B program + 3,667 B runtime = **20,227 B** | **OK, 3,773 B spare** (§3.2) |
+| `MaxCode` | 24,000 | 16,560 B program + 3,907 B runtime = **20,467 B** | **OK, 3,533 B spare** (§3.2) |
 | code window | `CodeMax = 6F00h`, capped by `MaxCode` | 20,227 B | **OK**; no data gap (§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) |
 | 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` |
 | stack | 16,384 min / 655,360 max | 16,384 min | matches the original's `minstk`/`maxstk` |

+ 11 - 9
SUMMARY.md

@@ -2041,9 +2041,10 @@ census of what `CALC.PAS` actually needs and the reference measurements from
 the original `TURBO.COM`. Two tracks run in parallel: the ladder (front-end,
 the original `TURBO.COM`. Two tracks run in parallel: the ladder (front-end,
 verifiable on small fixtures) and the layout (§3, the only thing that stops
 verifiable on small fixtures) and the layout (§3, the only thing that stops
 the compiler *emitting* a 16,560-byte program). The ratchet and front-end
 the compiler *emitting* a 16,560-byte program). The ratchet and front-end
-features through **run-time set membership** are landed: the ladder
-(`tests/calc_ladder.sh` + `tests/fixtures/calc_ladder.tsv`, run by `run_all.sh`;
-CALC.PAS now stops at `ERR 102` at pos 18267, `Write(Value:FW:DEC)` in `GotoCell`), the `{$I}` include,
+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 102` at pos 22706, `var Line : AnyString` in `GetFileName`), the `{$I}` include,
 `^X`/`#nn`, scalar typed constants, sets, enums, records (CellRec = 80),
 `^X`/`#nn`, scalar typed constants, sets, enums, records (CellRec = 80),
 subranges, arrays, element/field access, file types, string value parameters,
 subranges, arrays, element/field access, file types, string value parameters,
 `Length`, the CRT identifiers (`ClrScr`/`GotoXY`/`ClrEol`/`LowVideo`/
 `Length`, the CRT identifiers (`ClrScr`/`GotoXY`/`ClrEol`/`LowVideo`/
@@ -2055,12 +2056,13 @@ WITH and n-dimensional subscripts (`t77_with`), set-field assignment and
 run-time `in` (`t78_setfield`), string fields through DI (`t79_strfield`),
 run-time `in` (`t78_setfield`), string fields through DI (`t79_strfield`),
 the measured 6-byte REAL constants (`t80_realconst`, with a byte-level check),
 the measured 6-byte REAL constants (`t80_realconst`, with a byte-level check),
 `UpCase` and run-time set membership (`t81_upcase`, `t82_setin`), and
 `UpCase` and run-time set membership (`t81_upcase`, `t82_setin`), and
-`INT 10h`+`C6`+`D0-D3` in Exec86 (fixtures through `t82_setin`). The next rung
-is REAL output/arithmetic (the MBF core has started: `real_from_int`, entry
-21, is in the runtime and checked by 13 rt_exec cases); then the remaining string
-builtins, file operations, variable-index subscripts + `with`, pointers, `var`
-params, reals, recursion, and the layout change. Items 1-4 below are
-independent of both.
+real output (`t84_realwrite`), run-time set algebra and `Succ`/`Pred`
+(`t85`/`t86`), the original code-only `.COM` layout (§3.2), the untyped `file`
+type (`t87`), and file control-block operations (`t88`: `Assign`/`Reset`/
+`Rewrite`/`Close`/`IoResult`; data I/O is still refused). The next rung is a
+`var` string parameter. 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.
 
 
 1. The rest of the string language. `v-TP3-STRVAR`/`v-TP3-STRREAD-ASSIGN` cover
 1. The rest of the string language. `v-TP3-STRVAR`/`v-TP3-STRREAD-ASSIGN` cover
    string variables, `s := 'literal'`, `writeln (s)`, `readln (s)`/`read (s)`
    string variables, `s := 'literal'`, `writeln (s)`, `readln (s)`/`read (s)`

+ 104 - 4
shell/Compiler.mod

@@ -94,10 +94,13 @@ CONST
                                   field is scoped to its record, not global *)
                                   field is scoped to its record, not global *)
    MaxArrs   = 1000 ;          (* array SHAPES, likewise: a symbol points at
    MaxArrs   = 1000 ;          (* array SHAPES, likewise: a symbol points at
                                   one, and 2-D indexing needs both ranges *)
                                   one, and 2-D indexing needs both ranges *)
-   FileVarSize = 4 ;           (* a file variable is our control block: the DOS
-                                  handle (word) and a mode word (0 closed, 1
-                                  read, 2 write).  TP3 keeps a buffer here too;
-                                  we do unbuffered INT 21h I/O. *)
+   FileVarSize = 132 ;         (* a file variable is our control block: the DOS
+                                  handle (word), a mode word (0 closed, 1 read,
+                                  2 write), then a 128-byte NUL-terminated
+                                  filename.  TP3 keeps its own name buffer and
+                                  a 128-byte data buffer here; we keep the name
+                                  and do unbuffered INT 21h I/O, with the data
+                                  buffer supplied by the caller. *)
 
 
    (* type codes (TP3 vartp) *)
    (* type codes (TP3 vartp) *)
    TNone    = 0 ;  TArray  = 1 ;  TRecord = 2 ;  TSet  = 3 ;
    TNone    = 0 ;  TArray  = 1 ;  TRecord = 2 ;  TSet  = 3 ;
@@ -132,6 +135,12 @@ CONST
    BI_ClrScr  = 6 ;  BI_GotoXY = 7 ;  BI_LowVideo = 8 ;
    BI_ClrScr  = 6 ;  BI_GotoXY = 7 ;  BI_LowVideo = 8 ;
    BI_NormVideo = 9 ; BI_ClrEol = 10 ; BI_Delay = 11 ;
    BI_NormVideo = 9 ; BI_ClrEol = 10 ; BI_Delay = 11 ;
    BI_KeyPressed = 12 ; BI_UpCase = 13 ; BI_Succ = 14 ; BI_Pred = 15 ;
    BI_KeyPressed = 12 ; BI_UpCase = 13 ; BI_Succ = 14 ; BI_Pred = 15 ;
+   (* File operations.  TP3 has these as standard procedures/functions; our
+      control block is Compiler.FileVarSize, so Assign stores the name for
+      the later Reset/Rewrite.  IOResult is an expression; EndOfFile is the
+      next file increment. *)
+   BI_Assign = 16 ; BI_Reset = 17 ; BI_Rewrite = 18 ;
+   BI_Close = 19 ; BI_IoResult = 20 ;
    (* the sub-codes EmCrtSeq takes *)
    (* the sub-codes EmCrtSeq takes *)
    CrtClr = 0 ; CrtDl = 1 ; CrtDh = 2 ; CrtCaret = 3 ; CrtEol = 4 ;
    CrtClr = 0 ; CrtDl = 1 ; CrtDh = 2 ; CrtCaret = 3 ; CrtEol = 4 ;
    CrtLow = 5 ; CrtNorm = 6 ; CrtDelay = 7 ; CrtKey = 8 ;
    CrtLow = 5 ; CrtNorm = 6 ; CrtDelay = 7 ; CrtKey = 8 ;
@@ -390,6 +399,11 @@ VAR
    TU_SetOp    : CARDINAL ;  (* runtime set operations, entries 31..33 *)
    TU_SetOp    : CARDINAL ;  (* runtime set operations, entries 31..33 *)
    TU_SetCmp   : CARDINAL ;
    TU_SetCmp   : CARDINAL ;
    TU_SetCopy  : CARDINAL ;
    TU_SetCopy  : CARDINAL ;
+   TU_FileAssign  : CARDINAL ;  (* file control block operations, entries 34..38 *)
+   TU_FileReset   : CARDINAL ;
+   TU_FileRewrite : CARDINAL ;
+   TU_FileClose   : CARDINAL ;
+   TU_IoResult    : CARDINAL ;
    TU_CmpStr   : CARDINAL ;  (* string comparison; two addresses on the stack,
    TU_CmpStr   : CARDINAL ;  (* string comparison; two addresses on the stack,
                                 signed -1/0/+1 in AX *)
                                 signed -1/0/+1 in AX *)
    TU_StrCat   : CARDINAL ;  (* string concatenation; dest and source addresses
    TU_StrCat   : CARDINAL ;  (* string concatenation; dest and source addresses
@@ -3905,6 +3919,17 @@ BEGIN
          fixture had ever exercised the fold. *)
          fixture had ever exercised the fold. *)
       ParseVar (r) ;
       ParseVar (r) ;
       RETURN
       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. *)
+      IF MatchDelim ('(') THEN
+         ExpectDelim (')', ENoSemi)
+      END ;
+      DropC (EmCall (TU_IoResult)) ;
+      r.kind := 2 ;
+      r.cls := TScalar ;
+      r.chr := FALSE ;
+      RETURN
    ELSIF (symtab [idx].tag = KBuiltin) AND (symtab [idx].cls = BI_UpCase) THEN
    ELSIF (symtab [idx].tag = KBuiltin) AND (symtab [idx].cls = BI_UpCase) THEN
       (* UpCase(c): a CHAR function.  A constant folds; otherwise AL is
       (* UpCase(c): a CHAR function.  A constant folds; otherwise AL is
          mapped 'a'..'z' -> 'A'..'Z' and left alone outside that range.  The
          mapped 'a'..'z' -> 'A'..'Z' and left alone outside that range.  The
@@ -4795,6 +4820,64 @@ BEGIN
       END ;
       END ;
       RETURN
       RETURN
    END ;
    END ;
+   IF which = BI_Assign THEN
+      (* Assign(F, Name): the file variable's address and the counted
+         string's address.  The runtime copies the characters into the file
+         control block and marks it closed; Reset/Rewrite do the DOS open.
+         Name is pushed first, so the runtime sees F at [BP+4] and Name at
+         [BP+6]. *)
+      IF MatchDelim ('(') THEN
+         ParseExpr (arg) ;
+         IF OK () AND (arg.kind = 1) AND
+            ((arg.cls = TFile) OR (arg.cls = TText) OR (arg.cls = TUntyp)) THEN
+            ExpectDelim (',', ENoSemi) ;
+            ParseExpr (dummy) ;
+            IF OK () THEN
+               IF dummy.cls = TString THEN
+                  EmPushStrAddr (dummy) ;
+                  EmPushVarAddr (symtab [arg.idx].local,
+                                 (symtab [arg.idx].off + arg.boff) MOD 10000H) ;
+                  DropC (EmCall (TU_FileAssign)) ;
+                  EmAddSp (4)
+               ELSE
+                  Err (ETypeErr)
+               END
+            END
+         ELSIF OK () THEN
+            Err (ETypeErr)
+         END ;
+         ExpectDelim (')', ENoSemi)
+      ELSE
+         Err (ENoSemi)
+      END ;
+      RETURN
+   END ;
+   IF (which = BI_Reset) OR (which = BI_Rewrite) OR (which = BI_Close) THEN
+      IF MatchDelim ('(') THEN
+         ParseExpr (arg) ;
+         IF OK () THEN
+            IF (arg.kind = 1) AND
+               ((arg.cls = TFile) OR (arg.cls = TText) OR (arg.cls = TUntyp)) THEN
+               EmPushVarAddr (symtab [arg.idx].local,
+                              (symtab [arg.idx].off + arg.boff) MOD 10000H) ;
+               IF which = BI_Reset THEN
+                  DropC (EmCall (TU_FileReset))
+               ELSIF which = BI_Rewrite THEN
+                  DropC (EmCall (TU_FileRewrite))
+               ELSE
+                  DropC (EmCall (TU_FileClose))
+               END ;
+               EmAddSp (2)
+            ELSE
+               Err (ETypeErr)
+            END
+         END ;
+         ExpectDelim (')', ENoSemi)
+      ELSE
+         Err (ENoSemi)
+      END ;
+      RETURN
+   END ;
    reading := (which = BI_Read) OR (which = BI_ReadLn) ;
    reading := (which = BI_Read) OR (which = BI_ReadLn) ;
    nArgs := 0 ;
    nArgs := 0 ;
    IF MatchDelim ('(') THEN
    IF MatchDelim ('(') THEN
@@ -6633,6 +6716,18 @@ BEGIN
    i := NewSym ("SUCC", KBuiltin, BI_Succ, 0, 0, 0, 0, FALSE) ;
    i := NewSym ("SUCC", KBuiltin, BI_Succ, 0, 0, 0, 0, FALSE) ;
    i := NewSym ("PRED", KBuiltin, BI_Pred, 0, 0, 0, 0, FALSE) ;
    i := NewSym ("PRED", KBuiltin, BI_Pred, 0, 0, 0, 0, FALSE) ;
    symtab [i].defnd := TRUE ;
    symtab [i].defnd := TRUE ;
+   (* File operations.  These are the names CALC actually uses; Eof, not
+      EndOfFile, because CALC declares a variable called EndOfFile. *)
+   i := NewSym ("ASSIGN", KBuiltin, BI_Assign, 0, 0, 0, 0, FALSE) ;
+   symtab [i].defnd := TRUE ;
+   i := NewSym ("RESET", KBuiltin, BI_Reset, 0, 0, 0, 0, FALSE) ;
+   symtab [i].defnd := TRUE ;
+   i := NewSym ("REWRITE", KBuiltin, BI_Rewrite, 0, 0, 0, 0, FALSE) ;
+   symtab [i].defnd := TRUE ;
+   i := NewSym ("CLOSE", KBuiltin, BI_Close, 0, 0, 0, 0, FALSE) ;
+   symtab [i].defnd := TRUE ;
+   i := NewSym ("IORESULT", KBuiltin, BI_IoResult, 0, 0, 0, 0, FALSE) ;
+   symtab [i].defnd := TRUE ;
    (* KBD: the console keyboard as a TEXT file.  This runtime's read entries
    (* KBD: the console keyboard as a TEXT file.  This runtime's read entries
       already read the console, so `Read(Kbd, Ch)' drops the file argument and
       already read the console, so `Read(Kbd, Ch)' drops the file argument and
       reads a character exactly as `Read(Ch)' does. *)
       reads a character exactly as `Read(Ch)' does. *)
@@ -6789,6 +6884,11 @@ BEGIN
    TU_SetOp    := RT_Entry (31) ;
    TU_SetOp    := RT_Entry (31) ;
    TU_SetCmp   := RT_Entry (32) ;
    TU_SetCmp   := RT_Entry (32) ;
    TU_SetCopy  := RT_Entry (33) ;
    TU_SetCopy  := RT_Entry (33) ;
+   TU_FileAssign  := RT_Entry (34) ;
+   TU_FileReset   := RT_Entry (35) ;
+   TU_FileRewrite := RT_Entry (36) ;
+   TU_FileClose   := RT_Entry (37) ;
+   TU_IoResult    := RT_Entry (38) ;
    TU_WrStr    := RT_Entry (15) ;      (* a string variable is written through
    TU_WrStr    := RT_Entry (15) ;      (* a string variable is written through
                                           the address on the stack *)
                                           the address on the stack *)
    TU_RdStr    := RT_Entry (16) ;      (* readln(s)/read(s): TPSRC8 prdstr,
    TU_RdStr    := RT_Entry (16) ;      (* readln(s)/read(s): TPSRC8 prdstr,

+ 11 - 2
shell/Exec86.mod

@@ -596,8 +596,10 @@ PROCEDURE DoInt21 ;
 (* The five services bootcom.s provides and the compiler emits, and nothing
 (* The five services bootcom.s provides and the compiler emits, and nothing
    else.  Anything else faults, because the alternative is inventing DOS.
    else.  Anything else faults, because the alternative is inventing DOS.
 
 
-   No flag is touched anywhere in here: IRET restores the caller's FLAGS, so
-   neither this code nor bootcom's CLC/STC is visible to the guest. *)
+   The console services leave the flags alone, matching an IRET that restores
+   the caller's FLAGS.  AH=3Dh is different: the runtime reads CF as the DOS
+   error flag, so the file-service path sets (or clears) it explicitly.  This
+   interpreter executes INT inline rather than modelling the pushed FLAGS. *)
 VAR ah, b, a, n, lim, stop : CARDINAL ;
 VAR ah, b, a, n, lim, stop : CARDINAL ;
     c : CHAR ;
     c : CHAR ;
     running : BOOLEAN ;
     running : BOOLEAN ;
@@ -662,6 +664,13 @@ BEGIN
       END ;
       END ;
       AX := (AX DIV 256) * 256 + b
       AX := (AX DIV 256) * 256 + b
 
 
+   | 3DH :                                   (* open file: no filesystem *)
+      (* The runtime uses real DOS AH=3Dh.  This interpreter has no
+         filesystem either; answer "File not found" the way DOS does:
+         CF=1 and AX=2.  The file-operation fixture checks that path. *)
+      AX := 2 ;
+      CF := TRUE
+
    | 04CH :                                  (* terminate *)
    | 04CH :                                  (* terminate *)
       halted := TRUE ;
       halted := TRUE ;
       haltCode := AX MOD 256
       haltCode := AX MOD 256

+ 10 - 0
shell/Runtime.def

@@ -71,6 +71,16 @@ CONST
                                bit2 superset *)
                                bit2 superset *)
    E_SetCopy = 33 ;         (* set copy: [BP+4]=size, [BP+6]=src,
    E_SetCopy = 33 ;         (* set copy: [BP+4]=size, [BP+6]=src,
                                [BP+8]=dest *)
                                [BP+8]=dest *)
+   E_FileAssign = 34 ;      (* [BP+4]=file control block, [BP+6]=
+                               <length><filename>; copy the name and close *)
+   E_FileReset = 35 ;       (* [BP+4]=file; DOS open read-only *)
+   E_FileRewrite = 36 ;     (* [BP+4]=file; DOS create/truncate *)
+   E_FileClose = 37 ;       (* [BP+4]=file; DOS close if open *)
+   E_IoResult = 38 ;        (* AX = last DOS status, then clear it *)
+
+   (* File control block, mirrored by Compiler.FileVarSize. *)
+   F_NameOff = 4 ;           (* handle word, mode word, then the name *)
+   F_NameMax = 127 ;
 
 
    (* Where a .COM's first byte ends up.  DOS loads a .COM at CS:0100 (the
    (* Where a .COM's first byte ends up.  DOS loads a .COM at CS:0100 (the
       100 bytes below are the PSP), and CS = DS, so an image offset K is at
       100 bytes below are the PSP), and CS = DS, so an image offset K is at

+ 132 - 3
shell/Runtime.mod

@@ -30,6 +30,11 @@ IMPLEMENTATION MODULE Runtime ;
      WrLn/RdLn/StackChk          nothing
      WrLn/RdLn/StackChk          nothing
      InitMem                     AX = offset of the program header word block
      InitMem                     AX = offset of the program header word block
      ProgEnd/Halt                nothing; exits with code 0
      ProgEnd/Halt                nothing; exits with code 0
+     FileAssign                  [BP+4]=file block, [BP+6]=<len><name>
+     FileReset/Rewrite/Close     [BP+4]=file block
+     IoResult                    no argument; AX = last DOS status, cleared
+   The file operations use real DOS INT 21h calls and leave their status in
+   the runtime's D_IORES word.
    All entries preserve BP and SP, and every register except the documented
    All entries preserve BP and SP, and every register except the documented
    result, so they can be called from the middle of an expression. *)
    result, so they can be called from the middle of an expression. *)
 
 
@@ -92,7 +97,8 @@ CONST
    D_FMTPAD = 189 ;   (* 2 bytes: left padding *)
    D_FMTPAD = 189 ;   (* 2 bytes: left padding *)
    D_FMTTOT = 191 ;   (* 2 bytes: pad + length *)
    D_FMTTOT = 191 ;   (* 2 bytes: pad + length *)
    D_ASCSRC = 193 ;   (* 2 bytes: ascreal's source pointer *)
    D_ASCSRC = 193 ;   (* 2 bytes: ascreal's source pointer *)
-   D_END   = 195 ;    (* the block is padded to here *)
+   D_IORES = 195 ;    (* 2 bytes: the last file-operation DOS status *)
+   D_END   = 197 ;    (* the block is padded to here *)
 
 
    (* THE LOAD BIAS.  Everything above is an offset into the image as this
    (* 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
       compiler numbers it: the entry JMP is at image 0.  But a DOS .COM is
@@ -149,7 +155,7 @@ VAR
    dataAt : CARDINAL ;
    dataAt : CARDINAL ;
    rtBase : CARDINAL ;
    rtBase : CARDINAL ;
    built  : BOOLEAN ;
    built  : BOOLEAN ;
-   entNm  : ARRAY [0..33] OF ARRAY [0..MaxNm] OF CHAR ;
+   entNm  : ARRAY [0..38] OF ARRAY [0..MaxNm] OF CHAR ;
 
 
 (* ---------------------------------------------------------------- *)
 (* ---------------------------------------------------------------- *)
 (*  name helpers                                                     *)
 (*  name helpers                                                     *)
@@ -2902,6 +2908,119 @@ BEGIN
 END EmitSetOps ;
 END EmitSetOps ;
 
 
 
 
+PROCEDURE EmitFileOps ;
+(* File control-block operations.  The block is Compiler.FileVarSize:
+      +0  DOS handle (FFFFh when closed)
+      +2  mode (0 closed, 1 read, 2 write)
+      +4  128-byte NUL-terminated filename
+   Assign copies the counted string into +4; Reset/Rewrite/Close issue the DOS
+   calls and leave their status in D_IORES.  IOResult reads and clears that
+   word.  Eof is a later increment: it needs position/size arithmetic, and the
+   compile ladder has not reached it yet.
+
+   The caller pushes arguments left-to-right before the CALL, so [BP+4] is the
+   last push.  assign takes the filename first and the file block last:
+   [BP+4]=file, [BP+6]=<length><filename>.  The one-argument entries take the
+   file block at [BP+4]. *)
+BEGIN
+   (* Assign(F, Name) *)
+   M ("file_assign") ;
+   PushBp ; MovBpSp ;
+   PushBx ; PushCx ; PushDx ; PushSi ; PushDi ;
+   MovDiBp4 ;                         (* DI = file block *)
+   MovAxImm (0FFFFH) ; StDiAx ;       (* handle := invalid *)
+   XorAxAx ;
+   B (89H) ; B (45H) ; B (2) ;        (* MOV [DI+2],AX: mode := closed *)
+   MovSiBp6 ;                         (* SI = counted filename *)
+   MovAlSi ;                          (* AL := length byte *)
+   IncSi ;
+   B (3CH) ; B (7FH) ;                (* CMP AL,127 *)
+   Jbe8 ("fa_len") ;
+   MovAlD (127) ;                     (* clamp to the name buffer *)
+   M ("fa_len") ;
+   MovClAl ;                          (* CL := length *)
+   B (30H) ; B (0EDH) ;               (* XOR CH,CH: CX := length *)
+   B (83H) ; B (0C7H) ; B (4) ;       (* ADD DI,4: name buffer *)
+   Jcxz8 ("fa_nul") ;
+   M ("fa_copy") ;
+   LdAlSi ; StDiAl ;                  (* copy one byte, no string instr *)
+   IncSi ;
+   B (47H) ;                          (* INC DI *)
+   Loop8 ("fa_copy") ;
+   M ("fa_nul") ;
+   B (0C6H) ; B (05H) ; B (0) ;       (* MOV byte [DI],0: NUL *)
+   PopDi ; PopSi ; PopDx ; PopCx ; PopBx ;
+   MovSpBp ; PopBp ; RetR ;
+
+   (* Reset(F): AX=3D00h, DS:DX=name *)
+   M ("file_reset") ;
+   PushBp ; MovBpSp ;
+   PushBx ; PushCx ; PushDx ; PushDi ;
+   MovDiBp4 ;
+   B (8DH) ; B (55H) ; B (4) ;        (* LEA DX,[DI+4] *)
+   MovAxImm (3D00H) ; Int21 ;
+   Jb8 ("fr_err") ;
+   StDiAx ;                           (* handle := AX *)
+   MovAxImm (1) ; B (89H) ; B (45H) ; B (2) ;   (* mode := read *)
+   XorAxAx ; StDataAx (D_IORES) ;
+   Jmp8 ("fr_out") ;
+   M ("fr_err") ;
+   B (89H) ; B (0C3H) ;               (* MOV BX,AX: keep the DOS status *)
+   MovAxImm (0FFFFH) ; StDiAx ;
+   XorAxAx ; B (89H) ; B (45H) ; B (2) ;        (* mode := closed *)
+   StDataBx (D_IORES) ;
+   M ("fr_out") ;
+   PopDi ; PopDx ; PopCx ; PopBx ;
+   MovSpBp ; PopBp ; RetR ;
+
+   (* Rewrite(F): AX=3C00h, CX=0, DS:DX=name *)
+   M ("file_rewrite") ;
+   PushBp ; MovBpSp ;
+   PushBx ; PushCx ; PushDx ; PushDi ;
+   MovDiBp4 ;
+   B (8DH) ; B (55H) ; B (4) ;        (* LEA DX,[DI+4] *)
+   XorCxCx ;
+   MovAxImm (3C00H) ; Int21 ;
+   Jb8 ("fw_err") ;
+   StDiAx ;
+   MovAxImm (2) ; B (89H) ; B (45H) ; B (2) ;   (* mode := write *)
+   XorAxAx ; StDataAx (D_IORES) ;
+   Jmp8 ("fw_out") ;
+   M ("fw_err") ;
+   B (89H) ; B (0C3H) ;
+   MovAxImm (0FFFFH) ; StDiAx ;
+   XorAxAx ; B (89H) ; B (45H) ; B (2) ;
+   StDataBx (D_IORES) ;
+   M ("fw_out") ;
+   PopDi ; PopDx ; PopCx ; PopBx ;
+   MovSpBp ; PopBp ; RetR ;
+
+   (* Close(F): AX=3E00h, BX=handle; a closed block needs no DOS call *)
+   M ("file_close") ;
+   PushBp ; MovBpSp ;
+   PushBx ; PushDx ; PushDi ;
+   MovDiBp4 ;
+   LdAxDi ;
+   CmpAxImm (0FFFFH) ;
+   Je8 ("fc_out") ;
+   B (89H) ; B (0C3H) ;               (* BX := handle *)
+   MovAh (3EH) ; Int21 ;
+   B (89H) ; B (0C3H) ;               (* BX := status *)
+   MovAxImm (0FFFFH) ; StDiAx ;
+   XorAxAx ; B (89H) ; B (45H) ; B (2) ;
+   StDataBx (D_IORES) ;
+   M ("fc_out") ;
+   PopDi ; PopDx ; PopBx ;
+   MovSpBp ; PopBp ; RetR ;
+
+   (* IOResult: AX := D_IORES; D_IORES := 0 *)
+   M ("ioresult") ;
+   MovAxData (D_IORES) ;
+   StDataImm (D_IORES, 0) ;
+   RetR ;
+
+END EmitFileOps ;
+
 PROCEDURE EmitData ;
 PROCEDURE EmitData ;
 (* The runtime's data block.  The D_ constants name the offsets in it and are
 (* The runtime's data block.  The D_ constants name the offsets in it and are
    ASSERTED against what is emitted here, three ways: the starting offset of
    ASSERTED against what is emitted here, three ways: the starting offset of
@@ -3035,6 +3154,10 @@ BEGIN
       HALT
       HALT
    END ;
    END ;
    B (0) ; B (0) ;
    B (0) ; B (0) ;
+   IF dataAt + D_IORES # rpos THEN
+      HALT
+   END ;
+   B (0) ; B (0) ;                 (* the last file-operation status *)
    WHILE rpos < dataAt + D_END DO
    WHILE rpos < dataAt + D_END DO
       B (0)
       B (0)
    END ;
    END ;
@@ -3105,6 +3228,7 @@ BEGIN
    EmitRdStr ; EmitStrStore ; EmitCmpStr ; EmitStrCat ;
    EmitRdStr ; EmitStrStore ; EmitCmpStr ; EmitStrCat ;
    EmitRealFromInt ; EmitRealAddSub ; EmitRealMul ;
    EmitRealFromInt ; EmitRealAddSub ; EmitRealMul ;
    EmitRealCmp ; EmitRealInt ; EmitRealConv ; EmitSetOps ;
    EmitRealCmp ; EmitRealInt ; EmitRealConv ; EmitSetOps ;
+   EmitFileOps ;
    EmitData ;
    EmitData ;
    FixUp ;
    FixUp ;
    SetStr (entNm [0], "initmem") ;
    SetStr (entNm [0], "initmem") ;
@@ -3141,6 +3265,11 @@ BEGIN
    SetStr (entNm [31], "set_op") ;
    SetStr (entNm [31], "set_op") ;
    SetStr (entNm [32], "set_cmp") ;
    SetStr (entNm [32], "set_cmp") ;
    SetStr (entNm [33], "set_copy") ;
    SetStr (entNm [33], "set_copy") ;
+   SetStr (entNm [34], "file_assign") ;
+   SetStr (entNm [35], "file_reset") ;
+   SetStr (entNm [36], "file_rewrite") ;
+   SetStr (entNm [37], "file_close") ;
+   SetStr (entNm [38], "ioresult") ;
    built := TRUE
    built := TRUE
 END RT_Build ;
 END RT_Build ;
 
 
@@ -3168,7 +3297,7 @@ BEGIN
    IF NOT built THEN
    IF NOT built THEN
       RT_Build (0)
       RT_Build (0)
    END ;
    END ;
-   IF i > 33 THEN
+   IF i > 38 THEN
       RETURN 0
       RETURN 0
    END ;
    END ;
    RETURN rtBase + LblOff (entNm [i])
    RETURN rtBase + LblOff (entNm [i])

+ 8 - 3
shell/tests/RtProbe.mod

@@ -108,7 +108,7 @@ END PENT ;
 
 
 PROCEDURE Main ;
 PROCEDURE Main ;
 VAR i, n, base : CARDINAL ;
 VAR i, n, base : CARDINAL ;
-    names : ARRAY [0..33] OF ARRAY [0..15] OF CHAR ;
+    names : ARRAY [0..38] OF ARRAY [0..15] OF CHAR ;
 BEGIN
 BEGIN
    base := GetBase () ;
    base := GetBase () ;
    RT_Build (base) ;
    RT_Build (base) ;
@@ -121,7 +121,7 @@ BEGIN
    PCARD (RT_Size ()) ; PS (" bytes") ; NL ;
    PCARD (RT_Size ()) ; PS (" bytes") ; NL ;
    PS ("code ends at ") ; PCARD (RT_CodeEnd ()) ; NL ;
    PS ("code ends at ") ; PCARD (RT_CodeEnd ()) ; NL ;
    i := 0 ;
    i := 0 ;
-   WHILE i <= 33 DO
+   WHILE i <= 38 DO
       names [i] := "" ;
       names [i] := "" ;
       INC (i)
       INC (i)
    END ;
    END ;
@@ -146,8 +146,13 @@ BEGIN
    names [31] := "set_op" ;
    names [31] := "set_op" ;
    names [32] := "set_cmp" ;
    names [32] := "set_cmp" ;
    names [33] := "set_copy" ;
    names [33] := "set_copy" ;
+   names [34] := "file_assign" ;
+   names [35] := "file_reset" ;
+   names [36] := "file_rewrite" ;
+   names [37] := "file_close" ;
+   names [38] := "ioresult" ;
    i := 0 ;
    i := 0 ;
-   WHILE i <= 33 DO
+   WHILE i <= 38 DO
       PENT (i, names [i]) ;
       PENT (i, names [i]) ;
       INC (i)
       INC (i)
    END ;
    END ;

+ 7 - 2
shell/tests/audit_helpers.py

@@ -151,6 +151,11 @@ NON_ONE_LINE = {
         "SubAl": PARAM, "CmpAl": PARAM, "AddDl": PARAM, "J8": COMP,
         "SubAl": PARAM, "CmpAl": PARAM, "AddDl": PARAM, "J8": COMP,
         "Jcc": COMP, "CmpCxV": PARAM,
         "Jcc": COMP, "CmpCxV": PARAM,
         "B": DATA, "C8": DATA,
         "B": DATA, "C8": DATA,
+        # File control-block operations: a multi-instruction routine with
+        # labels and raw DOS sequences, not a one-line ModRM helper.  Its
+        # bytes are pinned by rt_exec's file_assign case and the runtime
+        # golden; the name grammar cannot read a whole routine.
+        "EmitFileOps": COMP,
     },
     },
     "Compiler.mod": {
     "Compiler.mod": {
         "AddSp": PARAM, "SubSp": PARAM, "Setcc": PARAM,
         "AddSp": PARAM, "SubSp": PARAM, "Setcc": PARAM,
@@ -751,7 +756,7 @@ def sweep(src, mod, verbose):
     # Its D_ offsets are asserted against this block by check_runtime.py's
     # Its D_ offsets are asserted against this block by check_runtime.py's
     # golden, so "excluded from the name audit" is not "unchecked": the bytes
     # golden, so "excluded from the name audit" is not "unchecked": the bytes
     # are pinned, only the name-to-opcode correspondence does not apply.
     # are pinned, only the name-to-opcode correspondence does not apply.
-    excluded = {"EmitData"}
+    excluded = {"EmitData", "EmitFileOps"}
     if verbose:
     if verbose:
         print("-- %s" % mod)
         print("-- %s" % mod)
         print("name                 bytes            FCML decode")
         print("name                 bytes            FCML decode")
@@ -960,7 +965,7 @@ def sweep(src, mod, verbose):
     # Its D_ offsets are asserted against this block by check_runtime.py's
     # Its D_ offsets are asserted against this block by check_runtime.py's
     # golden, so "excluded from the name audit" is not "unchecked": the bytes
     # golden, so "excluded from the name audit" is not "unchecked": the bytes
     # are pinned, only the name-to-opcode correspondence does not apply.
     # are pinned, only the name-to-opcode correspondence does not apply.
-    excluded = {"EmitData"}
+    excluded = {"EmitData", "EmitFileOps"}
     strip = (lambda s: s[2:]) if mod != "Runtime.mod" else (lambda s: s)
     strip = (lambda s: s[2:]) if mod != "Runtime.mod" else (lambda s: s)
     # The table is written in the names the audit uses (Runtime.mod's own
     # The table is written in the names the audit uses (Runtime.mod's own
     # names, Compiler.mod's with the Em prefix already removed), so it is NOT
     # names, Compiler.mod's with the Em prefix already removed), so it is NOT

+ 40 - 0
shell/tests/exec/bootcom.s

@@ -211,6 +211,8 @@ handler:
 	je	.Lh08
 	je	.Lh08
 	cmpb	$0x0b, %ah
 	cmpb	$0x0b, %ah
 	je	.Lh0b
 	je	.Lh0b
+	cmpb	$0x3d, %ah
+	je	.Lh3d
 	cmpb	$0x4c, %ah
 	cmpb	$0x4c, %ah
 	je	.Lh4c
 	je	.Lh4c
 	stc				# unknown function
 	stc				# unknown function
@@ -277,6 +279,16 @@ handler:
 	clc
 	clc
 	jmp	.Ldone8
 	jmp	.Ldone8
 
 
+.Lh3d:					# open file: no filesystem in this harness
+	# The runtime uses real DOS AH=3Dh.  A boot floppy has no DOS and no
+	# filesystem driver, so answer the one question the file-operation
+	# fixture asks - "the file is absent" - the way DOS does: CF=1,
+	# AX=2 (File not found).  The result must survive the epilogue, and
+	# CF must be visible to the guest, so this uses .LdoneFile.
+	movw	$2, %ax
+	stc
+	jmp	.LdoneFile
+
 .Lh4c:					# terminate: exit with AL as the code
 .Lh4c:					# terminate: exit with AL as the code
 	movw	$0x0501, %dx		# isa-debug-exit
 	movw	$0x0501, %dx		# isa-debug-exit
 	outb	%al, %dx
 	outb	%al, %dx
@@ -311,6 +323,34 @@ handler:
 #
 #
 # AX is therefore popped only on the paths where it is not a result, and
 # AX is therefore popped only on the paths where it is not a result, and
 # AH=02h/09h (which also leave AL alone in DOS) keep using .Ldone.
 # AH=02h/09h (which also leave AL alone in DOS) keep using .Ldone.
+.LdoneFile:
+	# AX is the result and CF is the DOS error flag.  POP does not change
+	# CF, so restore the saved registers first, then copy CF into the saved
+	# FLAGS word before dropping the saved AX and IRETing.  The 16-bit ADD
+	# used to discard AX would clobber CF, so set FLAGS before it.
+	popw	%es
+	popw	%ds
+	popw	%di
+	popw	%si
+	popw	%dx
+	popw	%cx
+	popw	%bx
+	# 16-bit addressing has no [SP] form.  Borrow BX as the frame pointer
+	# for two instructions; POP does not affect CF, so the branch still sees
+	# the handler's result.  After the push, SP points at the saved BX, so
+	# saved AX is +2 and saved FLAGS are +8.
+	pushw	%bx
+	movw	%sp, %bx
+	jnc	.Ldf_ok
+	orw	$1, 8(%bx)		# saved FLAGS: set CF
+	jmp	.Ldf_drop
+.Ldf_ok:
+	andw	$0xfffe, 8(%bx)		# saved FLAGS: clear CF
+.Ldf_drop:
+	popw	%bx
+	addw	$2, %sp		# drop the saved AX, keep the result
+	iret
+
 .Ldone8:
 .Ldone8:
 	popw	%es
 	popw	%es
 	popw	%ds
 	popw	%ds

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

@@ -151,6 +151,7 @@
 	.set	R_BLK34, 0x1520
 	.set	R_BLK34, 0x1520
 	.set	R_BLK35, 0x1530
 	.set	R_BLK35, 0x1530
 	.set	R_BLK36, 0x1540
 	.set	R_BLK36, 0x1540
+	.set	FILEBLK, 0x1A00	# the 132-byte file control block
 	.set	SETA, 0x1580
 	.set	SETA, 0x1580
 	.set	SETB, 0x1590
 	.set	SETB, 0x1590
 	.set	SETC, 0x15A0
 	.set	SETC, 0x15A0
@@ -617,3 +618,7 @@ HDR:
 	.byte	0x18, 0x03
 	.byte	0x18, 0x03
 	.org	SET2D
 	.org	SET2D
 	.byte	0x00, 0x00
 	.byte	0x00, 0x00
+
+# File control block for the file_assign case.
+	.org	FILEBLK
+	.zero	132

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

@@ -25,12 +25,12 @@
 # positions shift — which is exactly why this must be a measured number, not a
 # positions shift — which is exactly why this must be a measured number, not a
 # remembered one.
 # remembered one.
 #
 #
-# Current rung (2026-10-22): the untyped `file' type in CALC.INC's Exist
-# (`var F : file;').  UpCase, run-time set membership, string fields through
-# DI, the original memory layout and now untyped-file declarations moved the
-# ladder 15911 -> 18267 -> 19847 -> 20912 -> 22253 -> 22280.  The function
-# declaration itself was never the blocker: the parser required `of T' after
-# FILE and reported ENoSemi at the semicolon inside Exist's var block.  The
-# next blocker is the file-operation call `assign(F, FileN)', which is not a
-# builtin yet (TP3 error 41).
-CALC.PAS	ERR	41	22280
+# Current rung (2026-10-22): `var Line : AnyString' on CALC.INC's GetFileName.
+# UpCase, run-time set membership, string fields through DI, the original
+# memory layout, untyped-file declarations and the file control-block
+# operations moved the ladder 15911 -> 18267 -> 19847 -> 20912 -> 22253 ->
+# 22280 -> 22706.  The function declaration itself was never the blocker;
+# `file' required an OF, and then Assign/Reset/IOResult/Close were missing.
+# The next blocker is a VAR parameter of string type, which ProcFunc refuses
+# with ENoLib (TP3 error 102).
+CALC.PAS	ERR	102	22706

+ 10 - 2
shell/tests/fixtures/expected.tsv

@@ -519,7 +519,7 @@ t65_array_access	OK	106	17
 #                   element type for the record size a Read/Write moves.
 #                   element type for the record size a Read/Write moves.
 #                   data=12 = two file variables (4 each) + the two @@T
 #                   data=12 = two file variables (4 each) + the two @@T
 #                   temporaries.  File OPERATIONS are the next increment.
 #                   temporaries.  File OPERATIONS are the next increment.
-t66_files	OK	55	13
+t66_files	OK	55	269
 #   t67_strparam           a STRING VALUE parameter - CALC.INC:17.  TP3 puts a
 #   t67_strparam           a STRING VALUE parameter - CALC.INC:17.  TP3 puts a
 #                   value parameter's whole size on the stack, so a string[20]
 #                   value parameter's whole size on the stack, so a string[20]
 #                   parameter is 21 bytes and the caller COPIES <len><chars>
 #                   parameter is 21 bytes and the caller COPIES <len><chars>
@@ -628,4 +628,12 @@ t86_succ	OK	115	8
 #                   variable is the same four-byte control block as a typed
 #                   variable is the same four-byte control block as a typed
 #                   file but carries no element size; data Read/Write through
 #                   file but carries no element size; data Read/Write through
 #                   it remains refused.
 #                   it remains refused.
-t87_untypedfile	OK	62	9
+t87_untypedfile	OK	62	137
+
+#   t88_fileops          file control-block operations: assign copies the
+#                   counted name, reset calls DOS AH=3Dh, IOResult reads and
+#                   clears the status, close releases the handle.  The
+#                   boot harnesses have no filesystem, so the fixture exercises
+#                   the missing-file path (CF=1, AX=2) in both oracles; the
+#                   success path needs real DOS.
+t88_fileops	OK	109	137

+ 1 - 0
shell/tests/fixtures/t88_fileops.out

@@ -0,0 +1 @@
+TRUE

+ 26 - 0
shell/tests/fixtures/t88_fileops.pas

@@ -0,0 +1,26 @@
+program t88_fileops;
+
+{ t88 -- the file control-block operations CALC.INC's Exist uses:
+
+      assign(F, 'T88.DAT');
+      reset(F);       (with I/O checking disabled)
+      if IOResult <> 0 then ...
+      close(F)
+
+  Assign copies the counted filename into the file variable, Reset asks DOS
+  to open it, IOResult returns the DOS status and clears it, and Close closes
+  the handle.  The boot harnesses have no filesystem, so this fixture checks
+  the missing-file path: both oracles answer AH=3Dh with CF set and AX=2,
+  exactly as DOS does when the file is absent.  The success path needs a real
+  filesystem and is not executed here. }
+
+var
+  F : file;
+begin
+  assign (F, 'T88.DAT') ;
+  {$I-}
+  reset (F) ;
+  {$I+}
+  writeln (IOResult <> 0) ;
+  close (F)
+end.

+ 4 - 4
shell/tests/nonvacuity.sh

@@ -1804,20 +1804,20 @@ cp "$SAVED_C" Compiler.mod
 
 
 # --- the file variable's size ---------------------------------------------
 # --- the file variable's size ---------------------------------------------
 # Our file control block is FileVarSize bytes; shrink it and every file
 # Our file control block is FileVarSize bytes; shrink it and every file
-# variable's slot moves, so t66's `data=12' becomes `data=8'.  Visible at
+# variable's slot moves, so t66's `data=269' becomes `data=265'.  Visible at
 # compile time, so the matrix carries it.
 # compile time, so the matrix carries it.
 cp "$SAVED_C" Compiler.mod
 cp "$SAVED_C" Compiler.mod
 if python3 - <<'PYX'
 if python3 - <<'PYX'
 p = 'Compiler.mod'
 p = 'Compiler.mod'
 s = open(p).read()
 s = open(p).read()
-old = 'FileVarSize = 4 ;'
+old = 'FileVarSize = 132 ;'
 assert s.count(old) == 1, 'the file variable size found %d times -- update this mutation' % s.count(old)
 assert s.count(old) == 1, 'the file variable size found %d times -- update this mutation' % s.count(old)
-open(p, 'w').write(s.replace(old, 'FileVarSize = 2 ;'))
+open(p, 'w').write(s.replace(old, 'FileVarSize = 130 ;'))
 PYX
 PYX
 then
 then
     if rebuild_compiler; then
     if rebuild_compiler; then
         expect_red "t66 red when the file variable is the wrong size" \
         expect_red "t66 red when the file variable is the wrong size" \
-            "expected: OK 55 13" tests/run_compile_tests.sh
+            "expected: OK 55 269" tests/run_compile_tests.sh
     else
     else
         echo "  FAIL: the compiler would not rebuild with the file size changed"
         echo "  FAIL: the compiler would not rebuild with the file size changed"
         fail=$((fail + 1))
         fail=$((fail + 1))

+ 10 - 1
shell/tests/rt_exec.py

@@ -82,6 +82,7 @@ SST_WORLD = 0x1220
 AXOUT = 0x11A6          # the driver stores the last call's AX here
 AXOUT = 0x11A6          # the driver stores the last call's AX here
 FMTDEST = 0x1430        # a 64-byte string for the real_fmt cases
 FMTDEST = 0x1430        # a 64-byte string for the real_fmt cases
 ASCSRC = 0x1470          # the ASCIIZ strings for real_val
 ASCSRC = 0x1470          # the ASCIIZ strings for real_val
+FILEBLK = 0x1A00         # the 132-byte file control block
 REALDST = 0x0FA8
 REALDST = 0x0FA8
 
 
 # A .COM is loaded at CS:0100, and every address in the image is an image
 # A .COM is loaded at CS:0100, and every address in the image is an image
@@ -110,7 +111,9 @@ ENTS = ["initmem", "progend", "stackchk", "wrint", "wrchar", "wrbool",
         "wrtinl", "rdbyte", "wrstr", "rdstr", "strstore", "cmpstr", "strcat",
         "wrtinl", "rdbyte", "wrstr", "rdstr", "strstore", "cmpstr", "strcat",
         "wrintw", "real_from_int", "real_add", "real_sub", "real_mul",
         "wrintw", "real_from_int", "real_add", "real_sub", "real_mul",
         "real_div", "real_cmp", "real_int", "real_fmt", "real_val",
         "real_div", "real_cmp", "real_int", "real_fmt", "real_val",
-        "real_write", "set_op", "set_cmp", "set_copy"]
+        "real_write", "set_op", "set_cmp", "set_copy",
+        "file_assign", "file_reset", "file_rewrite", "file_close",
+        "ioresult"]
 
 
 # A call slot's flags, as rtdrv.s reads them.
 # A call slot's flags, as rtdrv.s reads them.
 F_STACK = 1     # the argument goes on the stack, popped by the caller
 F_STACK = 1     # the argument goes on the stack, popped by the caller
@@ -482,6 +485,12 @@ def build_cases():
         dumpbytes=b"\x00" * DLEN,
         dumpbytes=b"\x00" * DLEN,
         note="the data area is poisoned to AA first, so a zero is a result")
         note="the data area is poisoned to AA first, so a zero is a result")
 
 
+    add("file_assign copies the name",
+        [s2("file_assign", FILEBLK + LOAD_BIAS, SST_HELLO + LOAD_BIAS)],
+        dump=10, dumpbytes=b"\xff\xff\x00\x00hello\x00",
+        dumpadr=FILEBLK,
+        note="handle=FFFF, mode=0, then the NUL-terminated name")
+
     for v, why in [(0, "the one value where a signed/unsigned slip is invisible"),
     for v, why in [(0, "the one value where a signed/unsigned slip is invisible"),
                    (1, ""), (-1, ""), (7, ""), (10, ""), (42, ""),
                    (1, ""), (-1, ""), (7, ""), (10, ""), (42, ""),
                    (100, ""), (12345, ""), (-32768, "the sign bit"), (32767, "")]:
                    (100, ""), (12345, ""), (-32768, "the sign bit"), (32767, "")]:

+ 218 - 94
shell/tests/runtime.golden

@@ -41,7 +41,7 @@
 0036  58          pop ax
 0036  58          pop ax
 0037  F7 D8       neg ax
 0037  F7 D8       neg ax
 0039  B9 0A 00    mov cx,0ah
 0039  B9 0A 00    mov cx,0ah
-003C  BB 98 0E    mov bx,0e98h
+003C  BB 86 0F    mov bx,0f86h
 003F  89 DE       mov si,bx
 003F  89 DE       mov si,bx
 0041  31 D2       xor dx,dx
 0041  31 D2       xor dx,dx
 0043  F7 F1       div ax,cx
 0043  F7 F1       div ax,cx
@@ -93,7 +93,7 @@
 00A2  58          pop ax
 00A2  58          pop ax
 00A3  F7 D8       neg ax
 00A3  F7 D8       neg ax
 00A5  B9 0A 00    mov cx,0ah
 00A5  B9 0A 00    mov cx,0ah
-00A8  BB 98 0E    mov bx,0e98h
+00A8  BB 86 0F    mov bx,0f86h
 00AB  89 DE       mov si,bx
 00AB  89 DE       mov si,bx
 00AD  31 D2       xor dx,dx
 00AD  31 D2       xor dx,dx
 00AF  F7 F1       div ax,cx
 00AF  F7 F1       div ax,cx
@@ -125,18 +125,18 @@
 00DE  83 7E 04 00 cmp word ptr [bp+4h],0h
 00DE  83 7E 04 00 cmp word ptr [bp+4h],0h
 00E2  89 EC       mov sp,bp
 00E2  89 EC       mov sp,bp
 00E4  75 05       jne 0ebh
 00E4  75 05       jne 0ebh
-00E6  BA 9D 0E    mov dx,0e9dh
+00E6  BA 8B 0F    mov dx,0f8bh
 00E9  EB 03       jmp 0eeh
 00E9  EB 03       jmp 0eeh
-00EB  BA 98 0E    mov dx,0e98h
+00EB  BA 86 0F    mov dx,0f86h
 00EE  B4 09       mov ah,9h
 00EE  B4 09       mov ah,9h
 00F0  CD 21       int 21h
 00F0  CD 21       int 21h
 00F2  5D          pop bp
 00F2  5D          pop bp
 00F3  C3          ret
 00F3  C3          ret
-00F4  BA A6 0E    mov dx,0ea6h
+00F4  BA 94 0F    mov dx,0f94h
 00F7  B4 09       mov ah,9h
 00F7  B4 09       mov ah,9h
 00F9  CD 21       int 21h
 00F9  CD 21       int 21h
 00FB  C3          ret
 00FB  C3          ret
-00FC  BA A3 0E    mov dx,0ea3h
+00FC  BA 91 0F    mov dx,0f91h
 00FF  B4 09       mov ah,9h
 00FF  B4 09       mov ah,9h
 0101  CD 21       int 21h
 0101  CD 21       int 21h
 0103  C3          ret
 0103  C3          ret
@@ -303,12 +303,12 @@
 0217  EB EF       jmp 208h
 0217  EB EF       jmp 208h
 0219  58          pop ax
 0219  58          pop ax
 021A  C3          ret
 021A  C3          ret
-021B  8B 1E AC 0E mov bx,word ptr [0each]
+021B  8B 1E 9A 0F mov bx,word ptr [0f9ah]
 021F  83 FB 00    cmp bx,0h
 021F  83 FB 00    cmp bx,0h
 0222  74 09       je 22dh
 0222  74 09       je 22dh
 0224  8A C3       mov al,bl
 0224  8A C3       mov al,bl
 0226  31 DB       xor bx,bx
 0226  31 DB       xor bx,bx
-0228  89 1E AC 0E mov word ptr [0each],bx
+0228  89 1E 9A 0F mov word ptr [0f9ah],bx
 022C  C3          ret
 022C  C3          ret
 022D  B4 08       mov ah,8h
 022D  B4 08       mov ah,8h
 022F  CD 21       int 21h
 022F  CD 21       int 21h
@@ -316,7 +316,7 @@
 0232  88 C2       mov dl,al
 0232  88 C2       mov dl,al
 0234  BB 01 00    mov bx,1h
 0234  BB 01 00    mov bx,1h
 0237  8A DA       mov bl,dl
 0237  8A DA       mov bl,dl
-0239  89 1E AC 0E mov word ptr [0each],bx
+0239  89 1E 9A 0F mov word ptr [0f9ah],bx
 023D  C3          ret
 023D  C3          ret
 023E  55          push bp
 023E  55          push bp
 023F  8B EC       mov bp,sp
 023F  8B EC       mov bp,sp
@@ -543,7 +543,7 @@
 03C2  8B 4D 06    mov cx,word ptr [di+6h]
 03C2  8B 4D 06    mov cx,word ptr [di+6h]
 03C5  8B 75 08    mov si,word ptr [di+8h]
 03C5  8B 75 08    mov si,word ptr [di+8h]
 03C8  8B 7D 0A    mov di,word ptr [di+0ah]
 03C8  8B 7D 0A    mov di,word ptr [di+0ah]
-03CB  C7 06 AE 0E 00 00 mov word ptr [0eaeh],0h
+03CB  C7 06 9C 0F 00 00 mov word ptr [0f9ch],0h
 03D1  E8 4D 00    call 421h
 03D1  E8 4D 00    call 421h
 03D4  5F          pop di
 03D4  5F          pop di
 03D5  89 05       mov word ptr [di],ax
 03D5  89 05       mov word ptr [di],ax
@@ -572,7 +572,7 @@
 03FE  8B 4D 06    mov cx,word ptr [di+6h]
 03FE  8B 4D 06    mov cx,word ptr [di+6h]
 0401  8B 75 08    mov si,word ptr [di+8h]
 0401  8B 75 08    mov si,word ptr [di+8h]
 0404  8B 7D 0A    mov di,word ptr [di+0ah]
 0404  8B 7D 0A    mov di,word ptr [di+0ah]
-0407  C7 06 AE 0E 00 80 mov word ptr [0eaeh],8000h
+0407  C7 06 9C 0F 00 80 mov word ptr [0f9ch],8000h
 040D  E8 11 00    call 421h
 040D  E8 11 00    call 421h
 0410  5F          pop di
 0410  5F          pop di
 0411  89 05       mov word ptr [di],ax
 0411  89 05       mov word ptr [di],ax
@@ -587,7 +587,7 @@
 0420  C3          ret
 0420  C3          ret
 0421  80 F9 00    cmp cl,0h
 0421  80 F9 00    cmp cl,0h
 0424  74 0E       je 434h
 0424  74 0E       je 434h
-0426  33 3E AE 0E xor di,word ptr [0eaeh]
+0426  33 3E 9C 0F xor di,word ptr [0f9ch]
 042A  3C 00       cmp al,0h
 042A  3C 00       cmp al,0h
 042C  75 07       jne 435h
 042C  75 07       jne 435h
 042E  89 C8       mov ax,cx
 042E  89 C8       mov ax,cx
@@ -599,16 +599,16 @@
 0439  91          xchg ax,cx
 0439  91          xchg ax,cx
 043A  87 F3       xchg bx,si
 043A  87 F3       xchg bx,si
 043C  87 FA       xchg dx,di
 043C  87 FA       xchg dx,di
-043E  88 0E B2 0E mov byte ptr [0eb2h],cl
+043E  88 0E A0 0F mov byte ptr [0fa0h],cl
 0442  28 C1       sub cl,al
 0442  28 C1       sub cl,al
 0444  80 F9 28    cmp cl,28h
 0444  80 F9 28    cmp cl,28h
 0447  72 06       jb 44fh
 0447  72 06       jb 44fh
-0449  8A 0E B2 0E mov cl,byte ptr [0eb2h]
+0449  8A 0E A0 0F mov cl,byte ptr [0fa0h]
 044D  EB DF       jmp 42eh
 044D  EB DF       jmp 42eh
-044F  89 3E AE 0E mov word ptr [0eaeh],di
-0453  80 26 AF 0E 80 and byte ptr [0eafh],80h
-0458  89 3E B0 0E mov word ptr [0eb0h],di
-045C  30 36 B1 0E xor byte ptr [0eb1h],dh
+044F  89 3E 9C 0F mov word ptr [0f9ch],di
+0453  80 26 9D 0F 80 and byte ptr [0f9dh],80h
+0458  89 3E 9E 0F mov word ptr [0f9eh],di
+045C  30 36 9F 0F xor byte ptr [0f9fh],dh
 0460  81 CF 00 80 or di,8000h
 0460  81 CF 00 80 or di,8000h
 0464  80 CE 80    or dh,80h
 0464  80 CE 80    or dh,80h
 0467  80 F9 10    cmp cl,10h
 0467  80 F9 10    cmp cl,10h
@@ -633,8 +633,8 @@
 0492  D0 DC       rcr ah,1h
 0492  D0 DC       rcr ah,1h
 0494  FE C9       dec cl
 0494  FE C9       dec cl
 0496  75 F6       jne 48eh
 0496  75 F6       jne 48eh
-0498  A0 B2 0E    mov al,byte ptr [0eb2h]
-049B  F6 06 B1 0E 80 test byte ptr [0eb1h],80h
+0498  A0 A0 0F    mov al,byte ptr [0fa0h]
+049B  F6 06 9F 0F 80 test byte ptr [0f9fh],80h
 04A0  75 14       jne 4b6h
 04A0  75 14       jne 4b6h
 04A2  00 EC       add ah,ch
 04A2  00 EC       add ah,ch
 04A4  11 F3       adc bx,si
 04A4  11 F3       adc bx,si
@@ -654,7 +654,7 @@
 04BE  19 F3       sbb bx,si
 04BE  19 F3       sbb bx,si
 04C0  19 FA       sbb dx,di
 04C0  19 FA       sbb dx,di
 04C2  73 14       jnb 4d8h
 04C2  73 14       jnb 4d8h
-04C4  80 36 AF 0E 80 xor byte ptr [0eafh],80h
+04C4  80 36 9D 0F 80 xor byte ptr [0f9dh],80h
 04C9  F6 D4       not ah
 04C9  F6 D4       not ah
 04CB  F7 D3       not bx
 04CB  F7 D3       not bx
 04CD  F7 D2       not dx
 04CD  F7 D2       not dx
@@ -686,7 +686,7 @@
 0506  31 D2       xor dx,dx
 0506  31 D2       xor dx,dx
 0508  C3          ret
 0508  C3          ret
 0509  80 E6 7F    and dh,7fh
 0509  80 E6 7F    and dh,7fh
-050C  32 36 AF 0E xor dh,byte ptr [0eafh]
+050C  32 36 9D 0F xor dh,byte ptr [0f9dh]
 0510  C3          ret
 0510  C3          ret
 0511  55          push bp
 0511  55          push bp
 0512  8B EC       mov bp,sp
 0512  8B EC       mov bp,sp
@@ -732,23 +732,23 @@
 0565  B0 01       mov al,1h
 0565  B0 01       mov al,1h
 0567  B4 4C       mov ah,4ch
 0567  B4 4C       mov ah,4ch
 0569  CD 21       int 21h
 0569  CD 21       int 21h
-056B  89 0E B9 0E mov word ptr [0eb9h],cx
+056B  89 0E A7 0F mov word ptr [0fa7h],cx
 056F  8B CA       mov cx,dx
 056F  8B CA       mov cx,dx
 0571  31 F9       xor cx,di
 0571  31 F9       xor cx,di
 0573  F6 D5       not ch
 0573  F6 D5       not ch
 0575  80 E5 80    and ch,80h
 0575  80 E5 80    and ch,80h
-0578  88 2E AF 0E mov byte ptr [0eafh],ch
+0578  88 2E 9D 0F mov byte ptr [0f9dh],ch
 057C  80 CE 80    or dh,80h
 057C  80 CE 80    or dh,80h
 057F  81 CF 00 80 or di,8000h
 057F  81 CF 00 80 or di,8000h
-0583  89 36 BB 0E mov word ptr [0ebbh],si
-0587  89 3E BD 0E mov word ptr [0ebdh],di
-058B  A3 B3 0E    mov word ptr [0eb3h],ax
-058E  89 1E B5 0E mov word ptr [0eb5h],bx
-0592  89 16 B7 0E mov word ptr [0eb7h],dx
+0583  89 36 A9 0F mov word ptr [0fa9h],si
+0587  89 3E AB 0F mov word ptr [0fabh],di
+058B  A3 A1 0F    mov word ptr [0fa1h],ax
+058E  89 1E A3 0F mov word ptr [0fa3h],bx
+0592  89 16 A5 0F mov word ptr [0fa5h],dx
 0596  30 E4       xor ah,ah
 0596  30 E4       xor ah,ah
 0598  31 DB       xor bx,bx
 0598  31 DB       xor bx,bx
 059A  31 D2       xor dx,dx
 059A  31 D2       xor dx,dx
-059C  BF B9 0E    mov di,0eb9h
+059C  BF A7 0F    mov di,0fa7h
 059F  B1 05       mov cl,5h
 059F  B1 05       mov cl,5h
 05A1  47          inc di
 05A1  47          inc di
 05A2  8A 2D       mov ch,byte ptr [di]
 05A2  8A 2D       mov ch,byte ptr [di]
@@ -763,9 +763,9 @@
 05B5  BE 08 00    mov si,8h
 05B5  BE 08 00    mov si,8h
 05B8  D0 DD       rcr ch,1h
 05B8  D0 DD       rcr ch,1h
 05BA  73 0C       jnb 5c8h
 05BA  73 0C       jnb 5c8h
-05BC  02 26 B4 0E add ah,byte ptr [0eb4h]
-05C0  13 1E B5 0E adc bx,word ptr [0eb5h]
-05C4  13 16 B7 0E adc dx,word ptr [0eb7h]
+05BC  02 26 A2 0F add ah,byte ptr [0fa2h]
+05C0  13 1E A3 0F adc bx,word ptr [0fa3h]
+05C4  13 16 A5 0F adc dx,word ptr [0fa5h]
 05C8  D1 DA       rcr dx,1h
 05C8  D1 DA       rcr dx,1h
 05CA  D1 DB       rcr bx,1h
 05CA  D1 DB       rcr bx,1h
 05CC  D0 DC       rcr ah,1h
 05CC  D0 DC       rcr ah,1h
@@ -785,7 +785,7 @@
 05E6  74 02       je 5eah
 05E6  74 02       je 5eah
 05E8  FE C9       dec cl
 05E8  FE C9       dec cl
 05EA  91          xchg ax,cx
 05EA  91          xchg ax,cx
-05EB  32 36 AF 0E xor dh,byte ptr [0eafh]
+05EB  32 36 9D 0F xor dh,byte ptr [0f9dh]
 05EF  3C 00       cmp al,0h
 05EF  3C 00       cmp al,0h
 05F1  75 06       jne 5f9h
 05F1  75 06       jne 5f9h
 05F3  31 C0       xor ax,ax
 05F3  31 C0       xor ax,ax
@@ -834,29 +834,29 @@
 0647  B0 01       mov al,1h
 0647  B0 01       mov al,1h
 0649  B4 4C       mov ah,4ch
 0649  B4 4C       mov ah,4ch
 064B  CD 21       int 21h
 064B  CD 21       int 21h
-064D  89 0E B9 0E mov word ptr [0eb9h],cx
+064D  89 0E A7 0F mov word ptr [0fa7h],cx
 0651  8B CA       mov cx,dx
 0651  8B CA       mov cx,dx
 0653  31 F9       xor cx,di
 0653  31 F9       xor cx,di
 0655  F6 D5       not ch
 0655  F6 D5       not ch
 0657  80 E5 80    and ch,80h
 0657  80 E5 80    and ch,80h
-065A  88 2E AF 0E mov byte ptr [0eafh],ch
+065A  88 2E 9D 0F mov byte ptr [0f9dh],ch
 065E  80 CE 80    or dh,80h
 065E  80 CE 80    or dh,80h
 0661  81 CF 00 80 or di,8000h
 0661  81 CF 00 80 or di,8000h
-0665  89 36 BB 0E mov word ptr [0ebbh],si
-0669  89 3E BD 0E mov word ptr [0ebdh],di
-066D  A2 B3 0E    mov byte ptr [0eb3h],al
-0670  BF B8 0E    mov di,0eb8h
+0665  89 36 A9 0F mov word ptr [0fa9h],si
+0669  89 3E AB 0F mov word ptr [0fabh],di
+066D  A2 A1 0F    mov byte ptr [0fa1h],al
+0670  BF A6 0F    mov di,0fa6h
 0673  B1 05       mov cl,5h
 0673  B1 05       mov cl,5h
 0675  BE 08 00    mov si,8h
 0675  BE 08 00    mov si,8h
-0678  3B 16 BD 0E cmp dx,word ptr [0ebdh]
+0678  3B 16 AB 0F cmp dx,word ptr [0fabh]
 067C  75 0A       jne 688h
 067C  75 0A       jne 688h
-067E  3B 1E BB 0E cmp bx,word ptr [0ebbh]
+067E  3B 1E A9 0F cmp bx,word ptr [0fa9h]
 0682  75 04       jne 688h
 0682  75 04       jne 688h
-0684  3A 26 BA 0E cmp ah,byte ptr [0ebah]
+0684  3A 26 A8 0F cmp ah,byte ptr [0fa8h]
 0688  72 0C       jb 696h
 0688  72 0C       jb 696h
-068A  2A 26 BA 0E sub ah,byte ptr [0ebah]
-068E  1B 1E BB 0E sbb bx,word ptr [0ebbh]
-0692  1B 16 BD 0E sbb dx,word ptr [0ebdh]
+068A  2A 26 A8 0F sub ah,byte ptr [0fa8h]
+068E  1B 1E A9 0F sbb bx,word ptr [0fa9h]
+0692  1B 16 AB 0F sbb dx,word ptr [0fabh]
 0696  F5          cmc
 0696  F5          cmc
 0697  D0 D5       rcl ch,1h
 0697  D0 D5       rcl ch,1h
 0699  4E          dec si
 0699  4E          dec si
@@ -870,24 +870,24 @@
 06A8  D1 D3       rcl bx,1h
 06A8  D1 D3       rcl bx,1h
 06AA  D1 D2       rcl dx,1h
 06AA  D1 D2       rcl dx,1h
 06AC  73 CA       jnb 678h
 06AC  73 CA       jnb 678h
-06AE  2A 26 BA 0E sub ah,byte ptr [0ebah]
-06B2  1B 1E BB 0E sbb bx,word ptr [0ebbh]
-06B6  1B 16 BD 0E sbb dx,word ptr [0ebdh]
+06AE  2A 26 A8 0F sub ah,byte ptr [0fa8h]
+06B2  1B 1E A9 0F sbb bx,word ptr [0fa9h]
+06B6  1B 16 AB 0F sbb dx,word ptr [0fabh]
 06BA  F8          clc
 06BA  F8          clc
 06BB  EB D9       jmp 696h
 06BB  EB D9       jmp 696h
 06BD  D0 E4       shl ah,1h
 06BD  D0 E4       shl ah,1h
 06BF  D1 D3       rcl bx,1h
 06BF  D1 D3       rcl bx,1h
 06C1  D1 D2       rcl dx,1h
 06C1  D1 D2       rcl dx,1h
 06C3  72 11       jb 6d6h
 06C3  72 11       jb 6d6h
-06C5  3B 16 BD 0E cmp dx,word ptr [0ebdh]
+06C5  3B 16 AB 0F cmp dx,word ptr [0fabh]
 06C9  75 0A       jne 6d5h
 06C9  75 0A       jne 6d5h
-06CB  3B 1E BB 0E cmp bx,word ptr [0ebbh]
+06CB  3B 1E A9 0F cmp bx,word ptr [0fa9h]
 06CF  75 04       jne 6d5h
 06CF  75 04       jne 6d5h
-06D1  3A 26 BA 0E cmp ah,byte ptr [0ebah]
+06D1  3A 26 A8 0F cmp ah,byte ptr [0fa8h]
 06D5  F5          cmc
 06D5  F5          cmc
-06D6  8B 0E B3 0E mov cx,word ptr [0eb3h]
-06DA  8B 1E B5 0E mov bx,word ptr [0eb5h]
-06DE  8B 16 B7 0E mov dx,word ptr [0eb7h]
+06D6  8B 0E A1 0F mov cx,word ptr [0fa1h]
+06DA  8B 1E A3 0F mov bx,word ptr [0fa3h]
+06DE  8B 16 A5 0F mov dx,word ptr [0fa5h]
 06E2  9F          lahf
 06E2  9F          lahf
 06E3  F6 C6 80    test dh,80h
 06E3  F6 C6 80    test dh,80h
 06E6  75 09       jne 6f1h
 06E6  75 09       jne 6f1h
@@ -1030,47 +1030,47 @@
 07EC  B5 00       mov ch,0h
 07EC  B5 00       mov ch,0h
 07EE  B6 00       mov dh,0h
 07EE  B6 00       mov dh,0h
 07F0  51          push cx
 07F0  51          push cx
-07F1  BB 09 0F    mov bx,0f09h
+07F1  BB F7 0F    mov bx,0ff7h
 07F4  E8 41 02    call 0a38h
 07F4  E8 41 02    call 0a38h
 07F7  59          pop cx
 07F7  59          pop cx
 07F8  89 D8       mov ax,bx
 07F8  89 D8       mov ax,bx
-07FA  BB 09 0F    mov bx,0f09h
+07FA  BB F7 0F    mov bx,0ff7h
 07FD  2B C3       sub ax,bx
 07FD  2B C3       sub ax,bx
-07FF  A3 49 0F    mov word ptr [0f49h],ax
-0802  89 0E 4B 0F mov word ptr [0f4bh],cx
-0806  8B 06 4B 0F mov ax,word ptr [0f4bh]
-080A  8B 16 49 0F mov dx,word ptr [0f49h]
+07FF  A3 37 10    mov word ptr [1037h],ax
+0802  89 0E 39 10 mov word ptr [1039h],cx
+0806  8B 06 39 10 mov ax,word ptr [1039h]
+080A  8B 16 37 10 mov dx,word ptr [1037h]
 080E  2B C2       sub ax,dx
 080E  2B C2       sub ax,dx
 0810  83 F8 00    cmp ax,0h
 0810  83 F8 00    cmp ax,0h
 0813  7D 02       jnl 817h
 0813  7D 02       jnl 817h
 0815  31 C0       xor ax,ax
 0815  31 C0       xor ax,ax
-0817  A3 4D 0F    mov word ptr [0f4dh],ax
-081A  8B 16 49 0F mov dx,word ptr [0f49h]
+0817  A3 3B 10    mov word ptr [103bh],ax
+081A  8B 16 37 10 mov dx,word ptr [1037h]
 081E  03 C2       add ax,dx
 081E  03 C2       add ax,dx
 0820  3D FF 00    cmp ax,0ffh
 0820  3D FF 00    cmp ax,0ffh
 0823  77 03       jnbe 828h
 0823  77 03       jnbe 828h
 0825  E9 03 00    jmp 82bh
 0825  E9 03 00    jmp 82bh
 0828  B8 FF 00    mov ax,0ffh
 0828  B8 FF 00    mov ax,0ffh
-082B  A3 4F 0F    mov word ptr [0f4fh],ax
+082B  A3 3D 10    mov word ptr [103dh],ax
 082E  8B 56 06    mov dx,word ptr [bp+6h]
 082E  8B 56 06    mov dx,word ptr [bp+6h]
 0831  89 D7       mov di,dx
 0831  89 D7       mov di,dx
 0833  88 05       mov byte ptr [di],al
 0833  88 05       mov byte ptr [di],al
 0835  47          inc di
 0835  47          inc di
-0836  8B 0E 4D 0F mov cx,word ptr [0f4dh]
+0836  8B 0E 3B 10 mov cx,word ptr [103bh]
 083A  E3 07       jcxz 843h
 083A  E3 07       jcxz 843h
 083C  B0 20       mov al,20h
 083C  B0 20       mov al,20h
 083E  88 05       mov byte ptr [di],al
 083E  88 05       mov byte ptr [di],al
 0840  47          inc di
 0840  47          inc di
 0841  E2 F9       loop 83ch
 0841  E2 F9       loop 83ch
-0843  BE 09 0F    mov si,0f09h
-0846  8B 0E 49 0F mov cx,word ptr [0f49h]
+0843  BE F7 0F    mov si,0ff7h
+0846  8B 0E 37 10 mov cx,word ptr [1037h]
 084A  E3 08       jcxz 854h
 084A  E3 08       jcxz 854h
 084C  8A 04       mov al,byte ptr [si]
 084C  8A 04       mov al,byte ptr [si]
 084E  88 05       mov byte ptr [di],al
 084E  88 05       mov byte ptr [di],al
 0850  46          inc si
 0850  46          inc si
 0851  47          inc di
 0851  47          inc di
 0852  E2 F8       loop 84ch
 0852  E2 F8       loop 84ch
-0854  8B 06 4F 0F mov ax,word ptr [0f4fh]
+0854  8B 06 3D 10 mov ax,word ptr [103dh]
 0858  5F          pop di
 0858  5F          pop di
 0859  5E          pop si
 0859  5E          pop si
 085A  5A          pop dx
 085A  5A          pop dx
@@ -1086,12 +1086,12 @@
 0866  57          push di
 0866  57          push di
 0867  8B 5E 04    mov bx,word ptr [bp+4h]
 0867  8B 5E 04    mov bx,word ptr [bp+4h]
 086A  8B 7E 06    mov di,word ptr [bp+6h]
 086A  8B 7E 06    mov di,word ptr [bp+6h]
-086D  89 1E 51 0F mov word ptr [0f51h],bx
+086D  89 1E 3F 10 mov word ptr [103fh],bx
 0871  E8 CF 02    call 0b43h
 0871  E8 CF 02    call 0b43h
 0874  73 03       jnb 879h
 0874  73 03       jnb 879h
 0876  E9 0B 00    jmp 884h
 0876  E9 0B 00    jmp 884h
 0879  89 D8       mov ax,bx
 0879  89 D8       mov ax,bx
-087B  8B 16 51 0F mov dx,word ptr [0f51h]
+087B  8B 16 3F 10 mov dx,word ptr [103fh]
 087F  2B C2       sub ax,dx
 087F  2B C2       sub ax,dx
 0881  E9 03 00    jmp 887h
 0881  E9 03 00    jmp 887h
 0884  B8 FF FF    mov ax,0ffffh
 0884  B8 FF FF    mov ax,0ffffh
@@ -1140,7 +1140,7 @@
 08CE  52          push dx
 08CE  52          push dx
 08CF  53          push bx
 08CF  53          push bx
 08D0  50          push ax
 08D0  50          push ax
-08D1  88 0E CB 0E mov byte ptr [0ecbh],cl
+08D1  88 0E B9 0F mov byte ptr [0fb9h],cl
 08D5  80 F9 00    cmp cl,0h
 08D5  80 F9 00    cmp cl,0h
 08D8  78 03       js 8ddh
 08D8  78 03       js 8ddh
 08DA  E9 02 00    jmp 8dfh
 08DA  E9 02 00    jmp 8dfh
@@ -1151,7 +1151,7 @@
 08E6  D0 EB       shr bl,1h
 08E6  D0 EB       shr bl,1h
 08E8  00 FB       add bl,bh
 08E8  00 FB       add bl,bh
 08EA  30 FF       xor bh,bh
 08EA  30 FF       xor bh,bh
-08EC  8D BF CD 0E lea di,[bx+0ecdh]
+08EC  8D BF BB 0F lea di,[bx+0fbbh]
 08F0  8B 05       mov ax,word ptr [di]
 08F0  8B 05       mov ax,word ptr [di]
 08F2  8B 5D 02    mov bx,word ptr [di+2h]
 08F2  8B 5D 02    mov bx,word ptr [di+2h]
 08F5  8B 55 04    mov dx,word ptr [di+4h]
 08F5  8B 55 04    mov dx,word ptr [di+4h]
@@ -1168,7 +1168,7 @@
 0910  58          pop ax
 0910  58          pop ax
 0911  5B          pop bx
 0911  5B          pop bx
 0912  5A          pop dx
 0912  5A          pop dx
-0913  F6 06 CB 0E 80 test byte ptr [0ecbh],80h
+0913  F6 06 B9 0F 80 test byte ptr [0fb9h],80h
 0918  74 03       je 91dh
 0918  74 03       je 91dh
 091A  E9 03 00    jmp 920h
 091A  E9 03 00    jmp 920h
 091D  E9 27 FC    jmp 547h
 091D  E9 27 FC    jmp 547h
@@ -1195,11 +1195,11 @@
 0947  3C 00       cmp al,0h
 0947  3C 00       cmp al,0h
 0949  74 03       je 94eh
 0949  74 03       je 94eh
 094B  E9 16 00    jmp 964h
 094B  E9 16 00    jmp 964h
-094E  BE BF 0E    mov si,0ebfh
+094E  BE AD 0F    mov si,0fadh
 0951  C7 04 30 30 mov word ptr [si],3030h
 0951  C7 04 30 30 mov word ptr [si],3030h
 0955  46          inc si
 0955  46          inc si
 0956  46          inc si
 0956  46          inc si
-0957  81 FE CB 0E cmp si,0ecbh
+0957  81 FE B9 0F cmp si,0fb9h
 095B  74 03       je 960h
 095B  74 03       je 960h
 095D  E9 F1 FF    jmp 951h
 095D  E9 F1 FF    jmp 951h
 0960  B9 00 00    mov cx,0h
 0960  B9 00 00    mov cx,0h
@@ -1243,7 +1243,7 @@
 09AF  FE C9       dec cl
 09AF  FE C9       dec cl
 09B1  74 03       je 9b6h
 09B1  74 03       je 9b6h
 09B3  E9 F3 FF    jmp 9a9h
 09B3  E9 F3 FF    jmp 9a9h
-09B6  BE BF 0E    mov si,0ebfh
+09B6  BE AD 0F    mov si,0fadh
 09B9  88 F5       mov ch,dh
 09B9  88 F5       mov ch,dh
 09BB  B1 04       mov cl,4h
 09BB  B1 04       mov cl,4h
 09BD  D2 ED       shr ch,cl
 09BD  D2 ED       shr ch,cl
@@ -1269,13 +1269,13 @@
 09E1  D1 D3       rcl bx,1h
 09E1  D1 D3       rcl bx,1h
 09E3  D1 D2       rcl dx,1h
 09E3  D1 D2       rcl dx,1h
 09E5  46          inc si
 09E5  46          inc si
-09E6  81 FE CB 0E cmp si,0ecbh
+09E6  81 FE B9 0F cmp si,0fb9h
 09EA  74 03       je 9efh
 09EA  74 03       je 9efh
 09EC  E9 CA FF    jmp 9b9h
 09EC  E9 CA FF    jmp 9b9h
 09EF  59          pop cx
 09EF  59          pop cx
 09F0  C3          ret
 09F0  C3          ret
 09F1  30 E4       xor ah,ah
 09F1  30 E4       xor ah,ah
-09F3  BB BF 0E    mov bx,0ebfh
+09F3  BB AD 0F    mov bx,0fadh
 09F6  03 D8       add bx,ax
 09F6  03 D8       add bx,ax
 09F8  80 3F 35    cmp byte ptr [bx],35h
 09F8  80 3F 35    cmp byte ptr [bx],35h
 09FB  C6 07 00    mov byte ptr [bx],0h
 09FB  C6 07 00    mov byte ptr [bx],0h
@@ -1346,7 +1346,7 @@
 0A92  00 C8       add al,cl
 0A92  00 C8       add al,cl
 0A94  78 03       js 0a99h
 0A94  78 03       js 0a99h
 0A96  E9 08 00    jmp 0aa1h
 0A96  E9 08 00    jmp 0aa1h
-0A99  C6 06 BF 0E 00 mov byte ptr [0ebfh],0h
+0A99  C6 06 AD 0F 00 mov byte ptr [0fadh],0h
 0A9E  E9 0C 00    jmp 0aadh
 0A9E  E9 0C 00    jmp 0aadh
 0AA1  3C 0C       cmp al,0ch
 0AA1  3C 0C       cmp al,0ch
 0AA3  73 03       jnb 0aa8h
 0AA3  73 03       jnb 0aa8h
@@ -1354,7 +1354,7 @@
 0AA8  B0 0B       mov al,0bh
 0AA8  B0 0B       mov al,0bh
 0AAA  E8 44 FF    call 9f1h
 0AAA  E8 44 FF    call 9f1h
 0AAD  5B          pop bx
 0AAD  5B          pop bx
-0AAE  BE BF 0E    mov si,0ebfh
+0AAE  BE AD 0F    mov si,0fadh
 0AB1  F6 C5 80    test ch,80h
 0AB1  F6 C5 80    test ch,80h
 0AB4  75 03       jne 0ab9h
 0AB4  75 03       jne 0ab9h
 0AB6  E9 05 00    jmp 0abeh
 0AB6  E9 05 00    jmp 0abeh
@@ -1440,7 +1440,7 @@
 0B75  31 DB       xor bx,bx
 0B75  31 DB       xor bx,bx
 0B77  31 D2       xor dx,dx
 0B77  31 D2       xor dx,dx
 0B79  31 C9       xor cx,cx
 0B79  31 C9       xor cx,cx
-0B7B  C6 06 CC 0E 00 mov byte ptr [0ecch],0h
+0B7B  C6 06 BA 0F 00 mov byte ptr [0fbah],0h
 0B80  8A 0C       mov cl,byte ptr [si]
 0B80  8A 0C       mov cl,byte ptr [si]
 0B82  80 F9 61    cmp cl,61h
 0B82  80 F9 61    cmp cl,61h
 0B85  73 03       jnb 0b8ah
 0B85  73 03       jnb 0b8ah
@@ -1469,7 +1469,7 @@
 0BB5  58          pop ax
 0BB5  58          pop ax
 0BB6  5B          pop bx
 0BB6  5B          pop bx
 0BB7  5A          pop dx
 0BB7  5A          pop dx
-0BB8  C7 06 AE 0E 00 00 mov word ptr [0eaeh],0h
+0BB8  C7 06 9C 0F 00 00 mov word ptr [0f9ch],0h
 0BBE  E8 60 F8    call 421h
 0BBE  E8 60 F8    call 421h
 0BC1  59          pop cx
 0BC1  59          pop cx
 0BC2  5E          pop si
 0BC2  5E          pop si
@@ -1477,7 +1477,7 @@
 0BC4  F6 C5 40    test ch,40h
 0BC4  F6 C5 40    test ch,40h
 0BC7  75 03       jne 0bcch
 0BC7  75 03       jne 0bcch
 0BC9  E9 04 00    jmp 0bd0h
 0BC9  E9 04 00    jmp 0bd0h
-0BCC  FE 0E CC 0E dec byte ptr [0ecch]
+0BCC  FE 0E BA 0F dec byte ptr [0fbah]
 0BD0  46          inc si
 0BD0  46          inc si
 0BD1  E9 AC FF    jmp 0b80h
 0BD1  E9 AC FF    jmp 0b80h
 0BD4  80 F9 2E    cmp cl,2eh
 0BD4  80 F9 2E    cmp cl,2eh
@@ -1489,7 +1489,7 @@
 0BE4  80 CD 40    or ch,40h
 0BE4  80 CD 40    or ch,40h
 0BE7  E9 E6 FF    jmp 0bd0h
 0BE7  E9 E6 FF    jmp 0bd0h
 0BEA  80 F9 45    cmp cl,45h
 0BEA  80 F9 45    cmp cl,45h
-0BED  8A 0E CC 0E mov cl,byte ptr [0ecch]
+0BED  8A 0E BA 0F mov cl,byte ptr [0fbah]
 0BF1  74 03       je 0bf6h
 0BF1  74 03       je 0bf6h
 0BF3  E9 4D 00    jmp 0c43h
 0BF3  E9 4D 00    jmp 0c43h
 0BF6  E8 2A FD    call 923h
 0BF6  E8 2A FD    call 923h
@@ -1555,31 +1555,31 @@
 0C77  56          push si
 0C77  56          push si
 0C78  57          push di
 0C78  57          push di
 0C79  8B 46 06    mov ax,word ptr [bp+6h]
 0C79  8B 46 06    mov ax,word ptr [bp+6h]
-0C7C  A3 4B 0F    mov word ptr [0f4bh],ax
+0C7C  A3 39 10    mov word ptr [1039h],ax
 0C7F  8B 56 04    mov dx,word ptr [bp+4h]
 0C7F  8B 56 04    mov dx,word ptr [bp+4h]
 0C82  8B 4E 06    mov cx,word ptr [bp+6h]
 0C82  8B 4E 06    mov cx,word ptr [bp+6h]
 0C85  8B 7E 08    mov di,word ptr [bp+8h]
 0C85  8B 7E 08    mov di,word ptr [bp+8h]
-0C88  BB 09 0F    mov bx,0f09h
+0C88  BB F7 0F    mov bx,0ff7h
 0C8B  E8 AA FD    call 0a38h
 0C8B  E8 AA FD    call 0a38h
 0C8E  89 D8       mov ax,bx
 0C8E  89 D8       mov ax,bx
-0C90  BB 09 0F    mov bx,0f09h
+0C90  BB F7 0F    mov bx,0ff7h
 0C93  2B C3       sub ax,bx
 0C93  2B C3       sub ax,bx
-0C95  A3 49 0F    mov word ptr [0f49h],ax
-0C98  8B 06 4B 0F mov ax,word ptr [0f4bh]
-0C9C  8B 16 49 0F mov dx,word ptr [0f49h]
+0C95  A3 37 10    mov word ptr [1037h],ax
+0C98  8B 06 39 10 mov ax,word ptr [1039h]
+0C9C  8B 16 37 10 mov dx,word ptr [1037h]
 0CA0  2B C2       sub ax,dx
 0CA0  2B C2       sub ax,dx
 0CA2  83 F8 00    cmp ax,0h
 0CA2  83 F8 00    cmp ax,0h
 0CA5  7D 02       jnl 0ca9h
 0CA5  7D 02       jnl 0ca9h
 0CA7  31 C0       xor ax,ax
 0CA7  31 C0       xor ax,ax
-0CA9  A3 4D 0F    mov word ptr [0f4dh],ax
-0CAC  8B 0E 4D 0F mov cx,word ptr [0f4dh]
+0CA9  A3 3B 10    mov word ptr [103bh],ax
+0CAC  8B 0E 3B 10 mov cx,word ptr [103bh]
 0CB0  E3 08       jcxz 0cbah
 0CB0  E3 08       jcxz 0cbah
 0CB2  B0 20       mov al,20h
 0CB2  B0 20       mov al,20h
 0CB4  B4 02       mov ah,2h
 0CB4  B4 02       mov ah,2h
 0CB6  CD 21       int 21h
 0CB6  CD 21       int 21h
 0CB8  E2 F8       loop 0cb2h
 0CB8  E2 F8       loop 0cb2h
-0CBA  BE 09 0F    mov si,0f09h
-0CBD  8B 0E 49 0F mov cx,word ptr [0f49h]
+0CBA  BE F7 0F    mov si,0ff7h
+0CBD  8B 0E 37 10 mov cx,word ptr [1037h]
 0CC1  E3 09       jcxz 0ccch
 0CC1  E3 09       jcxz 0ccch
 0CC3  8A 04       mov al,byte ptr [si]
 0CC3  8A 04       mov al,byte ptr [si]
 0CC5  B4 02       mov ah,2h
 0CC5  B4 02       mov ah,2h
@@ -1699,3 +1699,127 @@
 0D8C  89 EC       mov sp,bp
 0D8C  89 EC       mov sp,bp
 0D8E  5D          pop bp
 0D8E  5D          pop bp
 0D8F  C3          ret
 0D8F  C3          ret
+0D90  55          push bp
+0D91  8B EC       mov bp,sp
+0D93  53          push bx
+0D94  51          push cx
+0D95  52          push dx
+0D96  56          push si
+0D97  57          push di
+0D98  8B 7E 04    mov di,word ptr [bp+4h]
+0D9B  B8 FF FF    mov ax,0ffffh
+0D9E  89 05       mov word ptr [di],ax
+0DA0  31 C0       xor ax,ax
+0DA2  89 45 02    mov word ptr [di+2h],ax
+0DA5  8B 76 06    mov si,word ptr [bp+6h]
+0DA8  8A 04       mov al,byte ptr [si]
+0DAA  46          inc si
+0DAB  3C 7F       cmp al,7fh
+0DAD  76 02       jbe 0db1h
+0DAF  B0 7F       mov al,7fh
+0DB1  88 C1       mov cl,al
+0DB3  30 ED       xor ch,ch
+0DB5  83 C7 04    add di,4h
+0DB8  E3 08       jcxz 0dc2h
+0DBA  8A 04       mov al,byte ptr [si]
+0DBC  88 05       mov byte ptr [di],al
+0DBE  46          inc si
+0DBF  47          inc di
+0DC0  E2 F8       loop 0dbah
+0DC2  C6 05 00    mov byte ptr [di],0h
+0DC5  5F          pop di
+0DC6  5E          pop si
+0DC7  5A          pop dx
+0DC8  59          pop cx
+0DC9  5B          pop bx
+0DCA  89 EC       mov sp,bp
+0DCC  5D          pop bp
+0DCD  C3          ret
+0DCE  55          push bp
+0DCF  8B EC       mov bp,sp
+0DD1  53          push bx
+0DD2  51          push cx
+0DD3  52          push dx
+0DD4  57          push di
+0DD5  8B 7E 04    mov di,word ptr [bp+4h]
+0DD8  8D 55 04    lea dx,[di+4h]
+0DDB  B8 00 3D    mov ax,3d00h
+0DDE  CD 21       int 21h
+0DE0  72 0F       jb 0df1h
+0DE2  89 05       mov word ptr [di],ax
+0DE4  B8 01 00    mov ax,1h
+0DE7  89 45 02    mov word ptr [di+2h],ax
+0DEA  31 C0       xor ax,ax
+0DEC  A3 41 10    mov word ptr [1041h],ax
+0DEF  EB 10       jmp 0e01h
+0DF1  89 C3       mov bx,ax
+0DF3  B8 FF FF    mov ax,0ffffh
+0DF6  89 05       mov word ptr [di],ax
+0DF8  31 C0       xor ax,ax
+0DFA  89 45 02    mov word ptr [di+2h],ax
+0DFD  89 1E 41 10 mov word ptr [1041h],bx
+0E01  5F          pop di
+0E02  5A          pop dx
+0E03  59          pop cx
+0E04  5B          pop bx
+0E05  89 EC       mov sp,bp
+0E07  5D          pop bp
+0E08  C3          ret
+0E09  55          push bp
+0E0A  8B EC       mov bp,sp
+0E0C  53          push bx
+0E0D  51          push cx
+0E0E  52          push dx
+0E0F  57          push di
+0E10  8B 7E 04    mov di,word ptr [bp+4h]
+0E13  8D 55 04    lea dx,[di+4h]
+0E16  31 C9       xor cx,cx
+0E18  B8 00 3C    mov ax,3c00h
+0E1B  CD 21       int 21h
+0E1D  72 0F       jb 0e2eh
+0E1F  89 05       mov word ptr [di],ax
+0E21  B8 02 00    mov ax,2h
+0E24  89 45 02    mov word ptr [di+2h],ax
+0E27  31 C0       xor ax,ax
+0E29  A3 41 10    mov word ptr [1041h],ax
+0E2C  EB 10       jmp 0e3eh
+0E2E  89 C3       mov bx,ax
+0E30  B8 FF FF    mov ax,0ffffh
+0E33  89 05       mov word ptr [di],ax
+0E35  31 C0       xor ax,ax
+0E37  89 45 02    mov word ptr [di+2h],ax
+0E3A  89 1E 41 10 mov word ptr [1041h],bx
+0E3E  5F          pop di
+0E3F  5A          pop dx
+0E40  59          pop cx
+0E41  5B          pop bx
+0E42  89 EC       mov sp,bp
+0E44  5D          pop bp
+0E45  C3          ret
+0E46  55          push bp
+0E47  8B EC       mov bp,sp
+0E49  53          push bx
+0E4A  52          push dx
+0E4B  57          push di
+0E4C  8B 7E 04    mov di,word ptr [bp+4h]
+0E4F  8B 05       mov ax,word ptr [di]
+0E51  3D FF FF    cmp ax,0ffffh
+0E54  74 16       je 0e6ch
+0E56  89 C3       mov bx,ax
+0E58  B4 3E       mov ah,3eh
+0E5A  CD 21       int 21h
+0E5C  89 C3       mov bx,ax
+0E5E  B8 FF FF    mov ax,0ffffh
+0E61  89 05       mov word ptr [di],ax
+0E63  31 C0       xor ax,ax
+0E65  89 45 02    mov word ptr [di+2h],ax
+0E68  89 1E 41 10 mov word ptr [1041h],bx
+0E6C  5F          pop di
+0E6D  5A          pop dx
+0E6E  5B          pop bx
+0E6F  89 EC       mov sp,bp
+0E71  5D          pop bp
+0E72  C3          ret
+0E73  8B 06 41 10 mov ax,word ptr [1041h]
+0E77  C7 06 41 10 00 00 mov word ptr [1041h],0h
+0E7D  C3          ret