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
87 lines
2.9 KiB
C
87 lines
2.9 KiB
C
/* TDKPIN's small ObjectWindows/MMTIMER system-timer class. */
|
|
|
|
#include "tdkpin_system_timer.h"
|
|
|
|
enum {
|
|
SYSTEM_TIMER_VMT_OFFSET = 0,
|
|
SYSTEM_TIMER_ID_OFFSET = 2,
|
|
SYSTEM_TIMER_RECIPIENT_OFFSET = 4,
|
|
};
|
|
|
|
/*
|
|
* 1008:295c — create the underlying MMTIMER timer.
|
|
* MOV AL,[BP+0a] deliberately preserves AH returned by the stack checker, so
|
|
* the imported word-valued one_shot argument is not merely zero or one.
|
|
*/
|
|
uint16_t tdkpin_system_timer_start(
|
|
Win16FarPtr object,
|
|
uint8_t one_shot,
|
|
uint16_t resolution_ms,
|
|
uint16_t delay_ms)
|
|
{
|
|
uint16_t stack_result = borland_check_stack(2);
|
|
uint16_t one_shot_word =
|
|
(uint16_t)((stack_result & 0xff00u) | one_shot);
|
|
HWND16 recipient =
|
|
win16_read_u16(win16_far_add_offset(
|
|
object, SYSTEM_TIMER_RECIPIENT_OFFSET));
|
|
return SystemTimerMake16(
|
|
recipient, delay_ms, resolution_ms, one_shot_word);
|
|
}
|
|
|
|
/* 1008:2932 — cancel a live multimedia timer, then clear its id. */
|
|
void tdkpin_system_timer_stop(Win16FarPtr object)
|
|
{
|
|
(void)borland_check_stack(0);
|
|
uint16_t timer_id =
|
|
win16_read_u16(win16_far_add_offset(object, SYSTEM_TIMER_ID_OFFSET));
|
|
if (timer_id != 0) {
|
|
(void)TimeKillEvent16(timer_id);
|
|
}
|
|
win16_write_u16(object, SYSTEM_TIMER_ID_OFFSET, 0);
|
|
}
|
|
|
|
/*
|
|
* 1008:28a3 — construct the six-byte timer object and start its timer.
|
|
* A zero timer id invokes the Borland constructor-failure cleanup. That frees
|
|
* newly allocated instances but leaves caller-owned instances in place because
|
|
* 1020:03ef cleared their hidden VMT ownership argument.
|
|
*/
|
|
Win16FarPtr tdkpin_system_timer_construct(
|
|
Win16FarPtr object,
|
|
uint16_t vmt,
|
|
uint8_t one_shot,
|
|
uint16_t resolution_ms,
|
|
uint16_t delay_ms,
|
|
HWND16 recipient)
|
|
{
|
|
(void)borland_check_stack(0);
|
|
BorlandObjectCallFrame frame = {object, vmt};
|
|
if (!borland_enter_object_constructor(
|
|
&frame, SYSTEM_TIMER_VMT_OFFSET)) {
|
|
return frame.object;
|
|
}
|
|
|
|
frame.object = borland_default_object_constructor(frame.object, 0);
|
|
win16_write_u16(frame.object, SYSTEM_TIMER_ID_OFFSET, 0);
|
|
win16_write_u16(frame.object, SYSTEM_TIMER_RECIPIENT_OFFSET, recipient);
|
|
uint16_t timer_id = tdkpin_system_timer_start(
|
|
frame.object, one_shot, resolution_ms, delay_ms);
|
|
win16_write_u16(frame.object, SYSTEM_TIMER_ID_OFFSET, timer_id);
|
|
if (timer_id == 0) {
|
|
borland_finish_object_destructor(
|
|
&frame, SYSTEM_TIMER_VMT_OFFSET);
|
|
}
|
|
return frame.object;
|
|
}
|
|
|
|
/* 1008:2906 — stop the timer, run the root destructor, and release if owned. */
|
|
void tdkpin_system_timer_destruct(Win16FarPtr object, uint16_t vmt)
|
|
{
|
|
(void)borland_check_stack(0);
|
|
BorlandObjectCallFrame frame = {object, vmt};
|
|
tdkpin_system_timer_stop(frame.object);
|
|
borland_default_object_destructor(frame.object, 0);
|
|
borland_finish_object_destructor(&frame, SYSTEM_TIMER_VMT_OFFSET);
|
|
}
|