From ffcc46d32fd2f1969d0ae8a29a937740e7f45a02 Mon Sep 17 00:00:00 2001 From: nmlgc Date: Sun, 14 Feb 2021 12:51:12 +0100 Subject: [PATCH] [Decompilation] [th05] pi_put_8(), pi_put_quarter_8() > assigning to the DI register immediately before a CALL Yeah, no amount of comma operator trickery can get *that* out of this compiler. Also, these TH05 .PI functions are the only place in PC-98 Touhou with a `IMUL DI, imm8` instruction, which is impossible to get out of Turbo C++'s built-in assembler. Well, at least the `if` branches decompile somewhat nicely. Part of P0134, funded by [Anonymous]. --- Makefile.mak | 4 +- libs/master.lib/master.inc | 2 + master.hpp | 5 ++ th05/formats/pi_asm_2.asm | 37 +++++++++++++ th05/formats/pi_cpp_2.cpp | 55 +++++++++++++++++++ th05/formats/pi_impl.hpp | 39 +++++++++++++ th05/formats/pi_put.asm | 109 ------------------------------------- th05/pi_cpp_2.cpp | 1 + th05_maine.asm | 3 +- th05_op.asm | 2 +- 10 files changed, 144 insertions(+), 113 deletions(-) create mode 100644 th05/formats/pi_cpp_2.cpp create mode 100644 th05/formats/pi_impl.hpp delete mode 100644 th05/formats/pi_put.asm create mode 100644 th05/pi_cpp_2.cpp diff --git a/Makefile.mak b/Makefile.mak index 2b3903e4..91447b51 100644 --- a/Makefile.mak +++ b/Makefile.mak @@ -150,7 +150,7 @@ bin\th05\res_kso.com: th05\res_kso.cpp $** | masters.lib -bin\th05\op.exe: th05\op010.cpp bin\th05\op.obj th05\op011.cpp th05\m_char.cpp bin\th05\pi_asm_2.obj bin\th05\initop.obj bin\th05\input_s.obj bin\th05\inp_h_w.obj bin\th05\snd_dlym.obj th05\cdg_p_nc.cpp bin\th05\frmdelay.obj bin\th04\cdg_load.obj bin\th05\egcrect.obj bin\hfliplut.obj +bin\th05\op.exe: th05\op010.cpp bin\th05\op.obj th05\op011.cpp th05\m_char.cpp bin\th05\pi_cpp_2.obj bin\th05\pi_asm_2.obj bin\th05\initop.obj bin\th05\input_s.obj bin\th05\inp_h_w.obj bin\th05\snd_dlym.obj th05\cdg_p_nc.cpp bin\th05\frmdelay.obj bin\th04\cdg_load.obj bin\th05\egcrect.obj bin\hfliplut.obj $(CC) $(CFLAGS) -ml -DGAME=5 -DBINARY='O' -3 -Z -nbin\th05\ -eOP.EXE @&&| $** | @@ -160,7 +160,7 @@ bin\th05\main.exe: bin\th05\main.obj th05\main010.cpp th05\main011.cpp th05\p_co $** | -bin\th05\maine.exe: bin\th05\maine.obj th05\maine011.cpp th05\regist.cpp th05\staff.cpp bin\th05\pi_asm_2.obj bin\th05\initmain.obj bin\th05\input_s.obj bin\th05\inp_h_w.obj bin\th05\snd_dlym.obj bin\th05\frmdelay.obj bin\th04\cdg_load.obj bin\th05\egcrect.obj bin\hfliplut.obj +bin\th05\maine.exe: bin\th05\maine.obj th05\maine011.cpp th05\regist.cpp th05\staff.cpp bin\th05\pi_cpp_2.obj bin\th05\pi_asm_2.obj bin\th05\initmain.obj bin\th05\input_s.obj bin\th05\inp_h_w.obj bin\th05\snd_dlym.obj bin\th05\frmdelay.obj bin\th04\cdg_load.obj bin\th05\egcrect.obj bin\hfliplut.obj $(CC) $(CFLAGS) -ml -DGAME=5 -DBINARY='E' -Z -nbin\th05\ -eMAINE.EXE @&&| $** | diff --git a/libs/master.lib/master.inc b/libs/master.lib/master.inc index 2fa5305b..0191f636 100644 --- a/libs/master.lib/master.inc +++ b/libs/master.lib/master.inc @@ -7,6 +7,8 @@ include libs/master.lib/macros.inc GAIJI_PUTSA procdesc pascal far \ x:word, y:word, strp_seg:word, strp_off:word, atrb:word +GRAPH_PACK_PUT_8_NOCLIP procdesc pascal far \ + left:word, top:word, linepat_sgm:word, linepat_off:word, len:word GRAPH_PI_FREE procdesc pascal far \ header:far ptr, image:far ptr PALETTE_SHOW procdesc pascal far diff --git a/master.hpp b/master.hpp index f20118bb..81fb15dd 100644 --- a/master.hpp +++ b/master.hpp @@ -460,6 +460,11 @@ void MASTER_RET palette_white_out(unsigned speed); void MASTER_RET graph_pack_put_8( int x, int y, const void far *linepat, int len ); + // Copy of graph_pack_put_8() that does not clip the Y coordinate to + // the vertical grc_setclip() coordinates. + void MASTER_RET graph_pack_put_8_noclip( + screen_x_t left, screen_y_t top, const void far *linepat, pixel_t len + ); #endif // --- diff --git a/th05/formats/pi_asm_2.asm b/th05/formats/pi_asm_2.asm index 90d78424..87885e60 100644 --- a/th05/formats/pi_asm_2.asm +++ b/th05/formats/pi_asm_2.asm @@ -16,6 +16,43 @@ include th03/arg_bx.inc SHARED_ segment word public 'CODE' use16 assume cs:SHARED_ +public PI_PUT_8_ROWLOOP +pi_put_8_rowloop proc pascal near +; Can't use ARG, because the function doesn't `PUSH BP`! +@@stride_packed = word ptr [bp+2] +@@w = word ptr [bp+4] +@@top = word ptr [bp+6] +@@left = word ptr [bp+8] +@@h equ di + + mov bp, sp + +@@put_row: + push es + call graph_pack_put_8_noclip pascal, @@left, @@top, es, si, @@w + pop es + inc @@top + cmp @@top, RES_Y + jb short @@next_row + sub @@top, RES_Y + +@@next_row: + add si, @@stride_packed + + ; .PI pointer normalization, see pi_buffer_p_normalize() + mov ax, si + shr ax, 4 + mov dx, es + add dx, ax + mov es, dx + and si, 0Fh + + dec @@h + jnz short @@put_row + retn 8 +pi_put_8_rowloop endp + + public PI_PALETTE_APPLY func pi_palette_apply arg_bx far, @slot:word diff --git a/th05/formats/pi_cpp_2.cpp b/th05/formats/pi_cpp_2.cpp new file mode 100644 index 00000000..83dc8141 --- /dev/null +++ b/th05/formats/pi_cpp_2.cpp @@ -0,0 +1,55 @@ +// Second TH05 .PI C++ translation unit. + +#pragma codeseg SHARED_ + +extern "C" { +#include +#include "platform.h" +#include "pc98.h" +#include "planar.h" +#include "master.hpp" +#include "th05/formats/pi.h" +#include "th05/formats/pi_impl.hpp" + +// Additionally takes: +// • `void far *pi_buf` in ES:SI +// • `pixel_t h` in DI +void pascal near pi_put_8_rowloop( + screen_x_t left, vram_y_t top, pixel_t w, size_t stride_packed +); + +void DEFCONV pi_put_8(screen_x_t left, vram_y_t top, int slot) +{ + #define rowloop_func __asm { \ + push left; /* left */ \ + push top; /* top */ \ + mov ax, word ptr pi_headers[di].xsize; \ + push ax; /* w */ \ + shr ax, 1; \ + push ax; /* stride_packed */ \ + mov di, word ptr pi_headers[di].ysize; \ + call near ptr pi_put_8_rowloop; \ + } + pi_put_impl(left, top, slot, rowloop_func); + #undef rowloop_func +} + +#pragma codestring "\x90" + +void pascal pi_put_quarter_8( + screen_x_t left, vram_y_t top, int slot, int quarter +) +{ + #define rowloop_func __asm { \ + push left; \ + push top; \ + push PI_QUARTER_W; \ + push (PI_W / 2); \ + mov di, PI_QUARTER_H; \ + call near ptr pi_put_8_rowloop; \ + } + pi_put_quarter_impl(left, top, slot, quarter, rowloop_func); + #undef rowloop_func +} + +} diff --git a/th05/formats/pi_impl.hpp b/th05/formats/pi_impl.hpp new file mode 100644 index 00000000..2602e3e6 --- /dev/null +++ b/th05/formats/pi_impl.hpp @@ -0,0 +1,39 @@ +// Shared parts of the pi_put_*() functions. + +#include "decomp.h" + +inline void imul_di(int8_t factor) { + __emit__(0x6B, 0xFF, factor); +} + +#define pi_put_impl(left, top, slot, rowloop_func) \ + _SI = slot; \ + _DI = _SI; \ + _SI <<= 2; /* *= sizeof(void far *) */ \ + __asm { les si, pi_buffers[si]; } \ + imul_di(sizeof(PiHeader)); \ + rowloop_func + +#define buffer_offset_off _AX +#define buffer_offset_sgm _DX +#define quarter_local _CL + +#define pi_put_quarter_impl(left, top, slot, quarter, rowloop_func) \ + buffer_offset_off = 0; \ + buffer_offset_sgm = 0; \ + _SI = slot; \ + \ + quarter_local = quarter; \ + if(quarter_local & 1) { \ + buffer_offset_off = (PI_QUARTER_W / 2); \ + } \ + if(quarter_local & 2) { \ + /* Careful! Parenthesizing this naively leads to overflows, since */ \ + /* (PI_QUARTER * PI_W) doesn't fit into 16 bits. */\ + buffer_offset_sgm = ((PI_QUARTER_H / 2) * (PI_W / 16)); \ + } \ + _SI <<= 2; /* *= sizeof(void far *) */ \ + __asm { les si, pi_buffers[si]; } \ + _SI += buffer_offset_off; \ + _ES += buffer_offset_sgm; \ + rowloop_func diff --git a/th05/formats/pi_put.asm b/th05/formats/pi_put.asm deleted file mode 100644 index c9878d7b..00000000 --- a/th05/formats/pi_put.asm +++ /dev/null @@ -1,109 +0,0 @@ -public PI_PUT_8 -pi_put_8 proc - ; (PASCAL calling convention, parameter list needs to be reversed here) - arg @@slot:word, @@top:word, @@left:word - - push bp - mov bp, sp - push si - push di - mov si, @@slot - mov di, si - shl si, 2 - les si, _pi_buffers[si] - imul di, size PiHeader - push @@left - push @@top - mov ax, _pi_headers.PiHeader._xsize[di] - push ax - shr ax, 1 - push ax - mov di, _pi_headers.PiHeader._ysize[di] - call pi_put_8_rowloop - pop di - pop si - pop bp - ret 6 -pi_put_8 endp - align 2 - -; --------------------------------------------------------------------------- - -public PI_PUT_QUARTER_8 -pi_put_quarter_8 proc - ; (PASCAL calling convention, parameter list needs to be reversed here) - arg @@quarter:byte, @@slot:word, @@top:word, @@left:word - - push bp - mov bp, sp - push si - push di - xor ax, ax - xor dx, dx - mov si, @@slot - mov cl, @@quarter - test cl, 1 - jz short @@bottom_quarter? - mov ax, 160 - -@@bottom_quarter?: - test cl, 2 - jz short @@put - mov dx, ((640 * 200) / 2) / 16 - -@@put: - shl si, 2 - les si, _pi_buffers[si] - add si, ax - mov ax, es - add ax, dx - mov es, ax - push @@left - push @@top - push 320 - push 320 - mov di, 200 - call pi_put_8_rowloop - pop di - pop si - pop bp - ret 8 -pi_put_quarter_8 endp - -; --------------------------------------------------------------------------- - -; void pascal pi_put_8_rowloop( -; void far *pi_buf, -; pixel_t h, -; screen_x_t x, vram_y_t y, pixel_t w, size_t stride_packed -; ); -pi_put_8_rowloop proc near -@@stride_packed = word ptr [bp+2] -@@w = word ptr [bp+4] -@@top = word ptr [bp+6] -@@left = word ptr [bp+8] -@@h equ di - - mov bp, sp - -@@put_row: - push es - call graph_pack_put_8_noclip pascal, @@left, @@top, es, si, @@w - pop es - inc @@top - cmp @@top, RES_Y - jb short @@next_row - sub @@top, RES_Y - -@@next_row: - add si, @@stride_packed - mov ax, si - shr ax, 4 - mov dx, es - add dx, ax - mov es, dx - and si, 0Fh - dec @@h - jnz short @@put_row - retn 8 -pi_put_8_rowloop endp diff --git a/th05/pi_cpp_2.cpp b/th05/pi_cpp_2.cpp new file mode 100644 index 00000000..d809a76e --- /dev/null +++ b/th05/pi_cpp_2.cpp @@ -0,0 +1 @@ +#include "th05/formats/pi_cpp_2.cpp" diff --git a/th05_maine.asm b/th05_maine.asm index b22f1313..6528702b 100644 --- a/th05_maine.asm +++ b/th05_maine.asm @@ -7540,7 +7540,8 @@ include th05/snd/load.asm include th05/snd/kajaint.asm include th05/formats/pi_put_masked.asm include th05/formats/pi_load.asm -include th05/formats/pi_put.asm + extern PI_PUT_8:proc + extern PI_PUT_QUARTER_8:proc extern PI_PALETTE_APPLY:proc extern PI_FREE:proc extern GAME_INIT_MAIN:proc diff --git a/th05_op.asm b/th05_op.asm index 533bc618..e1e46976 100644 --- a/th05_op.asm +++ b/th05_op.asm @@ -2545,7 +2545,7 @@ include th05/snd/load.asm include th05/snd/kajaint.asm include th05/formats/pi_put_masked.asm include th05/formats/pi_load.asm -include th05/formats/pi_put.asm + extern PI_PUT_8:proc extern PI_PALETTE_APPLY:proc extern PI_FREE:proc extern _game_init_op:proc