Replace the partial mechanics transcriptions with a separate, readable C11 reconstruction of the complete Win16 image while preserving the original raw Ghidra export as immutable evidence. Cover all ordinary and overlapping entry points, Borland runtime behavior, Win16 imports, segmented data, callbacks, resources, indirect control flow, physics, rendering, persistence, and startup/shutdown lifecycles. Add deterministic extraction and audit tooling plus address-linked ledgers for functions, imports, DGROUP ranges and objects, relocations, resources, and callbacks. The final gate records zero raw, partial, restored, unknown, blocked, or unclassified required units. Keep the semantic-fidelity boundary explicit: the portable C is not claimed to reproduce a byte-identical Borland NE build. Add strict focused harnesses for every reconstructed C unit, exact resource round-trip checks, and a 16-bit Borland Real48 reference probe. No Rust source or Cargo metadata is changed in this phase. Test Plan: - `bash original/tools/test_reconstructed_c.sh` -- passed - `bash original/tools/probe_real48_reference.sh` -- passed bit-for-bit - `python3 original/tools/audit_reconstruction.py --require-complete` -- passed - `git diff --cached --check` -- passed - `git diff HEAD -- '*.rs' Cargo.toml Cargo.lock` -- empty
400 lines
11 KiB
NASM
400 lines
11 KiB
NASM
; Differential probe for the unmodified Borland Real48 core in TDKPIN.EXE.
|
|
; Assemble from original/ so INCBIN addresses the authoritative target bytes.
|
|
|
|
bits 16
|
|
org 0x100
|
|
|
|
jmp main
|
|
|
|
integer_inputs:
|
|
dd 0, 1, -1, 2, 0x7fffffff, 0x80000000, 123456789, -123456789
|
|
integer_input_count equ ($ - integer_inputs) / 4
|
|
|
|
round_inputs:
|
|
db 0x80,0,0,0,0,0 ; +0.5
|
|
db 0x80,0,0,0,0,0x80 ; -0.5
|
|
db 0x7f,0xff,0xff,0xff,0xff,0x7f ; largest value below +0.5
|
|
db 0x81,0,0,0,0,0x40 ; +1.5
|
|
db 0x81,0xff,0xff,0xff,0xff,0x3f ; largest value below +1.5
|
|
db 0xa0,0,0,0,0,0 ; +2^31, overflow
|
|
db 0xa0,0,0,0,0,0x80 ; -2^31
|
|
db 0xa0,0,1,0,0,0x80 ; below -2^31, overflow
|
|
round_input_count equ ($ - round_inputs) / 6
|
|
|
|
arithmetic_pairs:
|
|
db 0x81,0,0,0,0,0, 0x81,0,0,0,0,0 ; 1, 1
|
|
db 0x81,0,0,0,0,0x40, 0x80,0,0,0,0,0 ; 1.5, 0.5
|
|
db 0x81,0,0,0,0,0x40, 0x80,0,0,0,0,0x80 ; 1.5, -0.5
|
|
db 0x01,0,0,0,0,0, 0x80,0,0,0,0,0 ; minimum, 0.5
|
|
db 0xff,0xff,0xff,0xff,0xff,0x7f, 0xff,0xff,0xff,0xff,0xff,0x7f
|
|
db 0x81,0,0,0,0,0x40, 0x82,0,0,0,0,0 ; 1.5, 2
|
|
arithmetic_pair_count equ ($ - arithmetic_pairs) / 12
|
|
|
|
part_inputs:
|
|
db 0x80,0,0,0,0,0 ; +0.5
|
|
db 0x81,0,0,0,0,0x60 ; +1.75
|
|
db 0x81,0,0,0,0,0xe0 ; -1.75
|
|
db 0x01,0,0,0,0,0 ; minimum positive
|
|
db 0xa8,0x55,0xaa,0x55,0xaa,0x55 ; already wholly integral
|
|
part_input_count equ ($ - part_inputs) / 6
|
|
|
|
sqrt_inputs:
|
|
db 0,0,0,0,0,0
|
|
db 0x81,0,0,0,0,0 ; 1
|
|
db 0x82,0,0,0,0,0 ; 2
|
|
db 0x83,0,0,0,0,0 ; 4
|
|
db 0x81,0,0,0,0,0x40 ; 1.5
|
|
sqrt_input_count equ ($ - sqrt_inputs) / 6
|
|
|
|
atan_series_inputs:
|
|
db 0,0,0,0,0,0
|
|
db 0x7f,0,0,0,0,0 ; 0.25
|
|
db 0x80,0,0,0,0,0 ; 0.5
|
|
db 0x7f,0xe7,0xcf,0xcc,0x13,0x54 ; sqrt(2)-1
|
|
atan_series_input_count equ ($ - atan_series_inputs) / 6
|
|
|
|
arctan_inputs:
|
|
db 0,0,0,0,0,0
|
|
db 0x7e,0,0,0,0,0 ; 0.125
|
|
db 0x80,0,0,0,0,0 ; 0.5
|
|
db 0x81,0,0,0,0,0 ; 1
|
|
db 0x82,0,0,0,0,0 ; 2
|
|
db 0x81,0,0,0,0,0x80 ; -1
|
|
arctan_input_count equ ($ - arctan_inputs) / 6
|
|
|
|
ln_inputs:
|
|
db 0x80,0,0,0,0,0 ; 0.5
|
|
db 0x81,0,0,0,0,0 ; 1
|
|
db 0x82,0,0,0,0,0 ; 2
|
|
db 0x81,0,0,0,0,0x40 ; 1.5
|
|
db 0x84,0,0,0,0,0x20 ; 10
|
|
ln_input_count equ ($ - ln_inputs) / 6
|
|
|
|
exp_inputs:
|
|
db 0x82,0,0,0,0,0x80 ; -2
|
|
db 0x81,0,0,0,0,0x80 ; -1
|
|
db 0x80,0,0,0,0,0x80 ; -0.5
|
|
db 0,0,0,0,0,0
|
|
db 0x80,0,0,0,0,0 ; 0.5
|
|
db 0x81,0,0,0,0,0 ; 1
|
|
db 0x82,0,0,0,0,0 ; 2
|
|
db 0x84,0,0,0,0,0x20 ; 10
|
|
exp_input_count equ ($ - exp_inputs) / 6
|
|
|
|
trig_inputs:
|
|
db 0,0,0,0,0,0
|
|
db 0x80,0x6a,0xc1,0x91,0x0a,0x06 ; pi/6
|
|
db 0x81,0x21,0xa2,0xda,0x0f,0x49 ; pi/2
|
|
db 0x82,0x21,0xa2,0xda,0x0f,0x49 ; pi
|
|
db 0x83,0x21,0xa2,0xda,0x0f,0x49 ; 2*pi
|
|
db 0x81,0x21,0xa2,0xda,0x0f,0xc9 ; -pi/2
|
|
db 0x81,0,0,0,0,0 ; 1
|
|
trig_input_count equ ($ - trig_inputs) / 6
|
|
|
|
probe_output:
|
|
times integer_input_count * 6 db 0
|
|
round_output equ $
|
|
times round_input_count * 5 db 0
|
|
arithmetic_output equ $
|
|
times arithmetic_pair_count * 28 db 0
|
|
part_output equ $
|
|
times part_input_count * 12 db 0
|
|
sqrt_output equ $
|
|
times sqrt_input_count * 6 db 0
|
|
atan_series_output equ $
|
|
times atan_series_input_count * 6 db 0
|
|
arctan_output equ $
|
|
times arctan_input_count * 6 db 0
|
|
ln_output equ $
|
|
times ln_input_count * 6 db 0
|
|
exp_output equ $
|
|
times exp_input_count * 6 db 0
|
|
sin_output equ $
|
|
times trig_input_count * 6 db 0
|
|
cos_output equ $
|
|
times trig_input_count * 6 db 0
|
|
probe_output_end:
|
|
|
|
output_name db 'R48.OUT',0
|
|
arithmetic_input_cursor dw arithmetic_pairs
|
|
arithmetic_output_cursor dw arithmetic_output
|
|
arithmetic_remaining db arithmetic_pair_count
|
|
part_input_cursor dw part_inputs
|
|
part_output_cursor dw part_output
|
|
part_remaining db part_input_count
|
|
sqrt_input_cursor dw sqrt_inputs
|
|
sqrt_output_cursor dw sqrt_output
|
|
sqrt_remaining db sqrt_input_count
|
|
atan_series_input_cursor dw atan_series_inputs
|
|
atan_series_output_cursor dw atan_series_output
|
|
atan_series_remaining db atan_series_input_count
|
|
arctan_input_cursor dw arctan_inputs
|
|
arctan_output_cursor dw arctan_output
|
|
arctan_remaining db arctan_input_count
|
|
ln_input_cursor dw ln_inputs
|
|
ln_output_cursor dw ln_output
|
|
ln_remaining db ln_input_count
|
|
exp_input_cursor dw exp_inputs
|
|
exp_output_cursor dw exp_output
|
|
exp_remaining db exp_input_count
|
|
trig_input_cursor dw trig_inputs
|
|
sin_output_cursor dw sin_output
|
|
cos_output_cursor dw cos_output
|
|
trig_remaining db trig_input_count
|
|
|
|
; Code5 file offset 108800 + 0x0cd0. Keeping the slice contiguous preserves
|
|
; every near displacement among the conversion/compare core routines. It is
|
|
; also placed at its original CS offset so absolute table references 1191..
|
|
; 1435 used by the transcendental helpers continue to address original bytes.
|
|
times (0x0bd0 - ($ - $$)) db 0
|
|
real48_core:
|
|
incbin "TDKPIN.EXE", 112080, 0x7d4
|
|
|
|
real48_i32_to_registers equ real48_core + (0x0f3b - 0x0cd0)
|
|
real48_registers_to_i32 equ real48_core + (0x0f77 - 0x0cd0)
|
|
real48_add_registers equ real48_core + (0x0cd4 - 0x0cd0)
|
|
real48_subtract_registers equ real48_core
|
|
real48_multiply_registers equ real48_core + (0x0d97 - 0x0cd0)
|
|
real48_divide_registers equ real48_core + (0x0e9a - 0x0cd0)
|
|
real48_integer_part equ real48_core + (0x1059 - 0x0cd0)
|
|
real48_fractional_part equ real48_core + (0x10aa - 0x0cd0)
|
|
real48_sqrt equ real48_core + (0x10be - 0x0cd0)
|
|
real48_arctan_series equ real48_core + (0x1436 - 0x0cd0)
|
|
real48_arctan equ real48_core + (0x1307 - 0x0cd0)
|
|
real48_ln equ real48_core + (0x11bb - 0x0cd0)
|
|
real48_exp equ real48_core + (0x1264 - 0x0cd0)
|
|
real48_sin equ real48_core + (0x1130 - 0x0cd0)
|
|
real48_cos equ real48_core + (0x111d - 0x0cd0)
|
|
|
|
%macro probe_arithmetic 1
|
|
mov bp, [arithmetic_input_cursor]
|
|
mov ax, [bp]
|
|
mov bx, [bp + 2]
|
|
mov dx, [bp + 4]
|
|
mov cx, [bp + 6]
|
|
mov si, [bp + 8]
|
|
mov di, [bp + 10]
|
|
call %1
|
|
pushf
|
|
mov di, [arithmetic_output_cursor]
|
|
mov [di], ax
|
|
mov [di + 2], bx
|
|
mov [di + 4], dx
|
|
pop ax
|
|
and al, 1
|
|
mov [di + 6], al
|
|
add word [arithmetic_output_cursor], 7
|
|
%endmacro
|
|
|
|
%macro probe_trig 2
|
|
mov bp, [trig_input_cursor]
|
|
mov ax, [bp]
|
|
mov bx, [bp + 2]
|
|
mov dx, [bp + 4]
|
|
push cs
|
|
call %1
|
|
mov di, [%2]
|
|
mov [di], ax
|
|
mov [di + 2], bx
|
|
mov [di + 4], dx
|
|
add word [%2], 6
|
|
%endmacro
|
|
|
|
%macro probe_exp 0
|
|
mov bp, [exp_input_cursor]
|
|
mov ax, [bp]
|
|
mov bx, [bp + 2]
|
|
mov dx, [bp + 4]
|
|
push cs
|
|
call real48_exp
|
|
mov di, [exp_output_cursor]
|
|
mov [di], ax
|
|
mov [di + 2], bx
|
|
mov [di + 4], dx
|
|
add word [exp_output_cursor], 6
|
|
%endmacro
|
|
|
|
%macro probe_ln 0
|
|
mov bp, [ln_input_cursor]
|
|
mov ax, [bp]
|
|
mov bx, [bp + 2]
|
|
mov dx, [bp + 4]
|
|
push cs
|
|
call real48_ln
|
|
mov di, [ln_output_cursor]
|
|
mov [di], ax
|
|
mov [di + 2], bx
|
|
mov [di + 4], dx
|
|
add word [ln_output_cursor], 6
|
|
%endmacro
|
|
|
|
%macro probe_arctan 0
|
|
mov bp, [arctan_input_cursor]
|
|
mov ax, [bp]
|
|
mov bx, [bp + 2]
|
|
mov dx, [bp + 4]
|
|
push cs
|
|
call real48_arctan
|
|
mov di, [arctan_output_cursor]
|
|
mov [di], ax
|
|
mov [di + 2], bx
|
|
mov [di + 4], dx
|
|
add word [arctan_output_cursor], 6
|
|
%endmacro
|
|
|
|
%macro probe_atan_series 0
|
|
mov bp, [atan_series_input_cursor]
|
|
mov ax, [bp]
|
|
mov bx, [bp + 2]
|
|
mov dx, [bp + 4]
|
|
call real48_arctan_series
|
|
mov di, [atan_series_output_cursor]
|
|
mov [di], ax
|
|
mov [di + 2], bx
|
|
mov [di + 4], dx
|
|
add word [atan_series_output_cursor], 6
|
|
%endmacro
|
|
|
|
%macro probe_sqrt 0
|
|
mov bp, [sqrt_input_cursor]
|
|
mov ax, [bp]
|
|
mov bx, [bp + 2]
|
|
mov dx, [bp + 4]
|
|
push cs
|
|
call real48_sqrt
|
|
mov di, [sqrt_output_cursor]
|
|
mov [di], ax
|
|
mov [di + 2], bx
|
|
mov [di + 4], dx
|
|
add word [sqrt_output_cursor], 6
|
|
%endmacro
|
|
|
|
%macro probe_part 1
|
|
mov bp, [part_input_cursor]
|
|
mov ax, [bp]
|
|
mov bx, [bp + 2]
|
|
mov dx, [bp + 4]
|
|
push cs
|
|
call %1
|
|
mov di, [part_output_cursor]
|
|
mov [di], ax
|
|
mov [di + 2], bx
|
|
mov [di + 4], dx
|
|
add word [part_output_cursor], 6
|
|
%endmacro
|
|
|
|
main:
|
|
push cs
|
|
pop ds
|
|
push cs
|
|
pop es
|
|
|
|
mov si, integer_inputs
|
|
mov di, probe_output
|
|
mov cx, integer_input_count
|
|
.integer_loop:
|
|
mov ax, [si]
|
|
mov dx, [si + 2]
|
|
push cx
|
|
call real48_i32_to_registers
|
|
pop cx
|
|
stosw ; exponent/low fraction
|
|
mov ax, bx
|
|
stosw ; middle fraction
|
|
mov ax, dx
|
|
stosw ; high fraction/sign
|
|
add si, 4
|
|
loop .integer_loop
|
|
|
|
mov si, round_inputs
|
|
mov di, round_output
|
|
mov bp, round_input_count
|
|
.round_loop:
|
|
mov ax, [si]
|
|
mov bx, [si + 2]
|
|
mov dx, [si + 4]
|
|
mov ch, 1 ; Borland Round entry mode
|
|
call real48_registers_to_i32
|
|
stosw
|
|
mov ax, dx
|
|
stosw
|
|
mov byte [di], 0
|
|
jnc .round_no_overflow
|
|
inc byte [di]
|
|
.round_no_overflow:
|
|
inc di
|
|
add si, 6
|
|
dec bp
|
|
jnz .round_loop
|
|
|
|
.arithmetic_loop:
|
|
probe_arithmetic real48_add_registers
|
|
probe_arithmetic real48_subtract_registers
|
|
probe_arithmetic real48_multiply_registers
|
|
probe_arithmetic real48_divide_registers
|
|
add word [arithmetic_input_cursor], 12
|
|
dec byte [arithmetic_remaining]
|
|
jnz .arithmetic_loop
|
|
|
|
.part_loop:
|
|
probe_part real48_integer_part
|
|
probe_part real48_fractional_part
|
|
add word [part_input_cursor], 6
|
|
dec byte [part_remaining]
|
|
jnz .part_loop
|
|
|
|
.sqrt_loop:
|
|
probe_sqrt
|
|
add word [sqrt_input_cursor], 6
|
|
dec byte [sqrt_remaining]
|
|
jnz .sqrt_loop
|
|
|
|
.atan_series_loop:
|
|
probe_atan_series
|
|
add word [atan_series_input_cursor], 6
|
|
dec byte [atan_series_remaining]
|
|
jnz .atan_series_loop
|
|
|
|
.arctan_loop:
|
|
probe_arctan
|
|
add word [arctan_input_cursor], 6
|
|
dec byte [arctan_remaining]
|
|
jnz .arctan_loop
|
|
|
|
.ln_loop:
|
|
probe_ln
|
|
add word [ln_input_cursor], 6
|
|
dec byte [ln_remaining]
|
|
jnz .ln_loop
|
|
|
|
.exp_loop:
|
|
probe_exp
|
|
add word [exp_input_cursor], 6
|
|
dec byte [exp_remaining]
|
|
jnz .exp_loop
|
|
|
|
.trig_loop:
|
|
probe_trig real48_sin, sin_output_cursor
|
|
probe_trig real48_cos, cos_output_cursor
|
|
add word [trig_input_cursor], 6
|
|
dec byte [trig_remaining]
|
|
jnz .trig_loop
|
|
|
|
mov dx, output_name
|
|
xor cx, cx
|
|
mov ah, 0x3c ; create/truncate
|
|
int 0x21
|
|
jc .failure
|
|
mov bx, ax
|
|
mov dx, probe_output
|
|
mov cx, probe_output_end - probe_output
|
|
mov ah, 0x40
|
|
int 0x21
|
|
mov ah, 0x3e
|
|
int 0x21
|
|
mov ax, 0x4c00
|
|
int 0x21
|
|
.failure:
|
|
mov ax, 0x4c01
|
|
int 0x21
|