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
168 lines
5.1 KiB
C
168 lines
5.1 KiB
C
#include "../tdkpin_key_input.h"
|
|
|
|
#include <assert.h>
|
|
#include <string.h>
|
|
|
|
static uint8_t g_dgroup[0x5000];
|
|
static uint8_t g_objects[0x1000];
|
|
static Win16FarPtr g_window;
|
|
static Win16FarPtr g_event;
|
|
static Win16FarPtr g_application;
|
|
static Win16FarPtr g_child;
|
|
static unsigned g_construct_calls;
|
|
static unsigned g_make_calls;
|
|
static unsigned g_show_calls;
|
|
static unsigned g_get_dc_calls;
|
|
static unsigned g_release_dc_calls;
|
|
static unsigned g_row_calls;
|
|
static INT16 g_last_row;
|
|
|
|
Win16FarPtr tdkpin_full_child_window_construct(
|
|
Win16FarPtr window,
|
|
uint16_t vmt,
|
|
Win16FarPtr title,
|
|
Win16FarPtr parent)
|
|
{
|
|
assert(window == 0 && vmt == 0x017e);
|
|
assert(title == win16_dgroup_pointer(0x0306) && parent == g_window);
|
|
g_construct_calls++;
|
|
return g_child;
|
|
}
|
|
|
|
Win16FarPtr win16_call_application_window_method(
|
|
Win16FarPtr procedure,
|
|
Win16FarPtr application,
|
|
Win16FarPtr window)
|
|
{
|
|
assert(procedure == win16_make_far_pointer(0x8000, 0x0034));
|
|
assert(application == g_application && window == g_child);
|
|
g_make_calls++;
|
|
return g_child;
|
|
}
|
|
|
|
void object_windows_show(Win16FarPtr object, INT16 command)
|
|
{
|
|
assert(object == g_child && command == 1);
|
|
g_show_calls++;
|
|
}
|
|
|
|
int32_t borland_multiply_i32(int32_t left, int32_t right)
|
|
{
|
|
return (int32_t)((uint32_t)left * (uint32_t)right);
|
|
}
|
|
|
|
HDC16 GetDC16(HWND16 window)
|
|
{
|
|
assert(window == 0x2222);
|
|
g_get_dc_calls++;
|
|
return 0x3333;
|
|
}
|
|
|
|
INT16 ReleaseDC16(HWND16 window, HDC16 dc)
|
|
{
|
|
assert(window == 0x2222 && dc == 0x3333);
|
|
g_release_dc_calls++;
|
|
return 1;
|
|
}
|
|
|
|
void tdkpin_draw_board_decoration_row_on_dc(INT16 y, HDC16 dc)
|
|
{
|
|
assert(dc == 0x3333);
|
|
g_last_row = y;
|
|
g_row_calls++;
|
|
}
|
|
|
|
static void prepare_fixture(uint16_t scan_code)
|
|
{
|
|
memset(g_dgroup, 0, sizeof(g_dgroup));
|
|
memset(g_objects, 0, sizeof(g_objects));
|
|
win16_reset_segment_bindings();
|
|
win16_bind_segment(0x7000, g_objects, sizeof(g_objects), true);
|
|
win16_bind_segment(0x7200, g_dgroup, sizeof(g_dgroup), true);
|
|
win16_set_dgroup_selector(0x7200);
|
|
g_window = win16_make_far_pointer(0x7000, 0x0000);
|
|
g_event = win16_make_far_pointer(0x7000, 0x0c00);
|
|
g_application = win16_make_far_pointer(0x7000, 0x0800);
|
|
g_child = win16_make_far_pointer(0x7000, 0x0900);
|
|
win16_write_u16(g_window, 4, 0x2222);
|
|
win16_write_u16(g_event, 8, scan_code);
|
|
win16_write_u16(g_event, 0x0a, 0xaaaa);
|
|
win16_write_u16(g_event, 0x0c, 0xbbbb);
|
|
win16_write_u16(g_application, 0, 0x0200);
|
|
win16_write_u32(
|
|
win16_dgroup_pointer(0x0234), 0,
|
|
win16_make_far_pointer(0x8000, 0x0034));
|
|
win16_write_u32(win16_dgroup_pointer(0x064e), 0, g_application);
|
|
g_construct_calls = 0;
|
|
g_make_calls = 0;
|
|
g_show_calls = 0;
|
|
g_get_dc_calls = 0;
|
|
g_release_dc_calls = 0;
|
|
g_row_calls = 0;
|
|
g_last_row = 0;
|
|
}
|
|
|
|
static void test_help_and_auxiliary_gate(void)
|
|
{
|
|
prepare_fixture(0x3b);
|
|
win16_set_indeterminate_u16(0xabcd);
|
|
assert(tdkpin_handle_key_press(g_window, g_event) == 0xabcd);
|
|
assert(g_construct_calls == 1 && g_make_calls == 1 && g_show_calls == 1);
|
|
assert(win16_read_far_pointer(g_window, 0x45) == g_child);
|
|
assert(win16_read_u16(win16_far_add_offset(g_event, 0x0a)) == 0xaaaa);
|
|
|
|
prepare_fixture(0x1d);
|
|
win16_write_u16(g_window, 0x41, 1);
|
|
assert(tdkpin_handle_key_press(g_window, g_event) == 0);
|
|
assert(win16_read_u8(win16_far_add_offset(g_window, 0x0bda)) == 0);
|
|
assert(win16_read_u16(win16_far_add_offset(g_event, 0x0a)) == 0);
|
|
assert(win16_read_u16(win16_far_add_offset(g_event, 0x0c)) == 0);
|
|
}
|
|
|
|
static void test_down_key_threshold_and_player_gate(void)
|
|
{
|
|
prepare_fixture(0x50);
|
|
win16_write_u32(g_window, 0x5a, 100);
|
|
win16_write_u32(g_window, 0x0bae, (uint32_t)-12000);
|
|
win16_write_u32(g_window, 0x0baa, 0x12345678u);
|
|
win16_write_u8(win16_dgroup_pointer(0x07d0), 1);
|
|
tdkpin_handle_key_press(g_window, g_event);
|
|
assert((int32_t)win16_read_u32(
|
|
win16_far_add_offset(g_window, 0x0bae)) == -17000);
|
|
assert(win16_read_u32(win16_far_add_offset(g_window, 0x0baa)) == 0);
|
|
assert(g_row_calls == 1 && g_last_row == 84);
|
|
assert(g_get_dc_calls == 1 && g_release_dc_calls == 1);
|
|
|
|
prepare_fixture(0x50);
|
|
win16_write_u32(g_window, 0x5a, 100);
|
|
win16_write_u32(g_window, 0x0bae, 1000);
|
|
tdkpin_handle_key_press(g_window, g_event);
|
|
assert((int32_t)win16_read_u32(
|
|
win16_far_add_offset(g_window, 0x0bae)) == -4000);
|
|
assert(g_row_calls == 0 && g_get_dc_calls == 0);
|
|
}
|
|
|
|
static void test_flipper_keys_and_tilt(void)
|
|
{
|
|
prepare_fixture(0x1d);
|
|
tdkpin_handle_key_press(g_window, g_event);
|
|
assert(win16_read_u8(win16_far_add_offset(g_window, 0x0bda)) == 1);
|
|
|
|
prepare_fixture(0x1c);
|
|
tdkpin_handle_key_press(g_window, g_event);
|
|
assert(win16_read_u8(win16_far_add_offset(g_window, 0x0bdb)) == 1);
|
|
|
|
prepare_fixture(0x1d);
|
|
win16_write_u8(win16_dgroup_pointer(0x07c6), 1);
|
|
tdkpin_handle_key_press(g_window, g_event);
|
|
assert(win16_read_u8(win16_far_add_offset(g_window, 0x0bda)) == 0);
|
|
}
|
|
|
|
int main(void)
|
|
{
|
|
test_help_and_auxiliary_gate();
|
|
test_down_key_threshold_and_player_gate();
|
|
test_flipper_keys_and_tilt();
|
|
return 0;
|
|
}
|