Files
tdkpin/original/tools/probes/real48_reference.asm
T
ddidderr 8b99e9607c feat(reconstruction): complete binary-backed C recovery
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
2026-08-23 16:41:17 +02:00

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