#include "../tdkpin_gameplay_helpers.h" #include #include #include int32_t g_ball_x_milli; int32_t g_ball_y_milli; uint8_t g_borland_cpu_level = 2; _Noreturn void borland_runtime_error(uint16_t code) { (void)code; __builtin_trap(); } _Noreturn void win16_integer_divide_fault(void) { __builtin_trap(); } static uint8_t g_stack[0x400]; static uint8_t g_object[0x0c00]; static uint8_t g_dgroup[0x5000]; static Win16FarPtr g_receiver; static unsigned g_client_rect_calls; static unsigned g_get_dc_calls; static unsigned g_create_dc_calls; static unsigned g_create_bitmap_calls; static unsigned g_select_calls; static unsigned g_blit_calls; static unsigned g_delete_object_calls; static unsigned g_delete_dc_calls; static unsigned g_release_dc_calls; static INT16 g_expected_x; static INT16 g_expected_y; static INT16 g_expected_height; BOOL16 GetClientRect16(HWND16 window, Win16FarPtr rectangle) { assert(window == 0x2222); assert(rectangle == win16_make_far_pointer(0x7000, 0x00e6)); win16_write_u16(rectangle, 0, 0); win16_write_u16(rectangle, 2, 0); win16_write_u16(rectangle, 4, 640); win16_write_u16(rectangle, 6, 460); g_client_rect_calls++; return 1; } HDC16 GetDC16(HWND16 window) { assert(window == 0x2222); g_get_dc_calls++; return 0x3333; } HDC16 CreateCompatibleDC16(HDC16 dc) { assert(dc == 0x3333 && g_create_dc_calls < 3); return (HDC16)(0x4001 + g_create_dc_calls++); } HBITMAP16 CreateCompatibleBitmap16(HDC16 dc, INT16 width, INT16 height) { assert(dc == 0x3333 && width == 100 && height == 100); g_create_bitmap_calls++; return 0x5000; } HGDIOBJ16 SelectObject16(HDC16 dc, HGDIOBJ16 object) { switch (g_select_calls++) { case 0: assert(dc == 0x4001 && object == 0x6000); return 0x7001; case 1: assert(dc == 0x4002 && object == 0x5000); return 0x7002; case 2: assert(dc == 0x4001 && object == 0x6100); return 0x6000; case 3: assert(dc == 0x4001 && object == 0x6200); return 0x6100; case 4: assert(dc == 0x4001 && object == 0x7001); return 0x6200; case 5: assert(dc == 0x4002 && object == 0x7002); return 0x5000; default: assert(g_select_calls == 7); assert(dc == 0x4003 && object == 0x7003); return 0; } } BOOL16 BitBlt16( HDC16 destination, INT16 destination_x, INT16 destination_y, INT16 width, INT16 height, HDC16 source, INT16 source_x, INT16 source_y, uint32_t raster_operation) { switch (g_blit_calls++) { case 0: assert(destination == 0x4002); assert(destination_x == 0 && destination_y == 0); assert(width == 19 && height == 19 && source == 0x4001); assert(source_x == g_expected_x && source_y == g_expected_y); assert(raster_operation == 0x00cc0020u); break; case 1: assert(destination == 0x4002 && destination_x == 1); assert(destination_y == 1 && width == 19 && height == 19); assert(source == 0x4001 && source_x == 0 && source_y == 0); assert(raster_operation == 0x008800c6u); break; case 2: assert(destination == 0x4002 && destination_x == 1); assert(destination_y == 1 && width == 19 && height == 19); assert(source == 0x4001 && source_x == 0 && source_y == 0); assert(raster_operation == 0x00ee0086u); break; default: assert(g_blit_calls == 4); assert(destination == 0x3333); assert(destination_x == g_expected_x && destination_y == g_expected_y); assert(width == 19 && height == g_expected_height); assert(source == 0x4002 && source_x == 0 && source_y == 0); assert(raster_operation == 0x00cc0020u); break; } return 1; } BOOL16 DeleteObject16(HGDIOBJ16 object) { assert(object == 0x5000); g_delete_object_calls++; return 1; } BOOL16 DeleteDC16(HDC16 dc) { assert(dc == (HDC16)(0x4001 + g_delete_dc_calls)); g_delete_dc_calls++; return 1; } INT16 ReleaseDC16(HWND16 window, HDC16 dc) { assert(window == 0x2222 && dc == 0x3333); g_release_dc_calls++; return 1; } static void reset_counters(void) { g_client_rect_calls = 0; g_get_dc_calls = 0; g_create_dc_calls = 0; g_create_bitmap_calls = 0; g_select_calls = 0; g_blit_calls = 0; g_delete_object_calls = 0; g_delete_dc_calls = 0; g_release_dc_calls = 0; } static void prepare_fixture(void) { memset(g_stack, 0, sizeof(g_stack)); memset(g_object, 0, sizeof(g_object)); memset(g_dgroup, 0, sizeof(g_dgroup)); win16_reset_segment_bindings(); win16_bind_segment(0x7000, g_stack, sizeof(g_stack), true); win16_bind_segment(0x7100, g_object, sizeof(g_object), true); win16_bind_segment(0x7200, g_dgroup, sizeof(g_dgroup), true); win16_set_dgroup_selector(0x7200); win16_set_stack_state(0x7000, 0); g_receiver = win16_make_far_pointer(0x7100, 0); win16_write_stack_u16(0x0106, win16_far_offset(g_receiver)); win16_write_stack_u16(0x0108, win16_far_selector(g_receiver)); win16_write_stack_u16(0x00fa, 0x7003); win16_write_u16(g_receiver, 4, 0x2222); win16_write_u16(g_receiver, 0x52, 0x6200); win16_write_u16(g_receiver, 0x54, 0x6100); win16_write_u16(win16_dgroup_pointer(0x085b), 0, 0x6000); reset_counters(); } static void assert_complete_gdi_lifecycle(void) { assert(g_client_rect_calls == 1 && g_get_dc_calls == 1); assert(g_create_dc_calls == 3 && g_create_bitmap_calls == 1); assert(g_select_calls == 7 && g_blit_calls == 4); assert(g_delete_object_calls == 1 && g_delete_dc_calls == 3); assert(g_release_dc_calls == 1); assert(win16_read_stack_u16(0x00f4) == 0x3333); assert(win16_read_stack_u16(0x00f2) == 0x4001); assert(win16_read_stack_u16(0x00f0) == 0x4002); assert(win16_read_stack_u16(0x00ee) == 0x4003); assert(win16_read_stack_u16(0x00f8) == 0x5000); assert(win16_read_stack_u16(0x00fe) == 0x7001); assert(win16_read_stack_u16(0x00fc) == 0x7002); } static void test_render_and_bottom_clipping(void) { prepare_fixture(); g_ball_x_milli = 100000; g_ball_y_milli = 440000; g_expected_x = 91; g_expected_y = 431; g_expected_height = 12; tdkpin_render_ball_from_caller_frame(0x0100); assert((int32_t)win16_read_u32( win16_far_add_offset(g_receiver, 0x0ba2)) == 92); assert((int32_t)win16_read_u32( win16_far_add_offset(g_receiver, 0x0ba6)) == 432); assert(win16_read_stack_u16(0x00d6) == 12); assert_complete_gdi_lifecycle(); prepare_fixture(); g_ball_x_milli = 100000; g_ball_y_milli = 500000; g_expected_x = 91; g_expected_y = 491; g_expected_height = 0; tdkpin_render_ball_from_caller_frame(0x0100); assert(win16_read_stack_u16(0x00d6) == 0); assert_complete_gdi_lifecycle(); } static void test_reset_branches_and_state(void) { prepare_fixture(); static const uint16_t completion_words[5] = { 0x3371, 0x33c4, 0x3417, 0x346a, 0x34bd}; for (unsigned index = 0; index < 5; index++) { win16_write_u16( win16_dgroup_pointer(completion_words[index]), 0, 1); } win16_write_u16(win16_dgroup_pointer(0x0851), 0, 0xaaaa); win16_write_u16(win16_dgroup_pointer(0x0853), 0, 0xbbbb); win16_write_u8(win16_dgroup_pointer(0x07c8), 0); win16_write_u8(win16_dgroup_pointer(0x07c6), 1); win16_write_u8(win16_far_add_offset(g_receiver, 0x0bdd), 1); g_expected_x = 316; g_expected_y = 404; g_expected_height = 19; tdkpin_reset_ball_state(0x0100); assert(win16_read_u16(win16_dgroup_pointer(0x0851)) == 0); assert(win16_read_u16(win16_dgroup_pointer(0x0853)) == 0); assert(win16_read_u8(win16_dgroup_pointer(0x07c8)) == 1); assert(win16_read_u8(win16_dgroup_pointer(0x07c6)) == 0); assert(g_ball_x_milli == 325000 && g_ball_y_milli == 413000); assert(win16_read_u32(win16_far_add_offset(g_receiver, 0x0bba)) == 325000u); assert(win16_read_u32(win16_far_add_offset(g_receiver, 0x0bbe)) == 413000u); assert(win16_read_u32(win16_far_add_offset(g_receiver, 0x0bc2)) == 325000u); assert(win16_read_u32(win16_far_add_offset(g_receiver, 0x0bc6)) == 413000u); assert(win16_read_u32(win16_far_add_offset(g_receiver, 0x0baa)) == 0); assert(win16_read_u32(win16_far_add_offset(g_receiver, 0x0bae)) == 0); assert(win16_read_u32(win16_far_add_offset(g_receiver, 0x0bca)) == 0); assert(win16_read_u16(win16_far_add_offset(g_receiver, 0x0bce)) == 0); assert(win16_read_u16(win16_far_add_offset(g_receiver, 0x0bd0)) == 0); assert(win16_read_u16(win16_far_add_offset(g_receiver, 0x0bd2)) == 0); assert(win16_read_u8(win16_far_add_offset(g_receiver, 0x0bdd)) == 0); assert_complete_gdi_lifecycle(); prepare_fixture(); win16_write_u16(win16_dgroup_pointer(0x3371), 0, 0); win16_write_u16(win16_dgroup_pointer(0x0851), 0, 0xaaaa); win16_write_u16(win16_dgroup_pointer(0x0853), 0, 0xbbbb); win16_write_u8(win16_dgroup_pointer(0x07c8), 7); g_expected_x = 316; g_expected_y = 404; g_expected_height = 19; tdkpin_reset_ball_state(0x0100); assert(win16_read_u16(win16_dgroup_pointer(0x0851)) == 0xaaaa); assert(win16_read_u16(win16_dgroup_pointer(0x0853)) == 0xbbbb); assert(win16_read_u8(win16_dgroup_pointer(0x07c8)) == 7); assert_complete_gdi_lifecycle(); } int main(void) { test_render_and_bottom_clipping(); test_reset_branches_and_state(); return 0; }