#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>

#define enter(s,l)
#define save(x)
#define load(x)
#define leave()

/* When you assign just one register to dword(), the second one is
 * automatically extended to hold the higher dword bits. */

/* parametry: DWORD (ax,dx), DWORD (bx,cx) */
/* vraci DWORD (ax,dx) ; zbytek == garbage */
/* si ma po navratu z funkce puvodni hodnotu */
uint32_t
f_0x17e(uint32_t dword1 /* ax,dx */, uint32_t dword2 /* cx,bx */)
{
	/* [0] == lower, [1] == higher */
	uint16_t *dword1W, *dword2W;

	dword1W = (uint16_t *) &dword1; dword2W = (uint16_t *) &dword2;

	dword1W[0] = dword1W[0]              *              dword2W[1];
	dword1W[1] = dword1W[0] * dword2W[0] + dword1W[1] * dword2W[1];

	return dword1;
}

uint32_t
function(unsigned char *bp)
{
	uint16_t bp_m_0x6; uint32_t bp_m_0x4;
	uint32_t dword_axdx, dword_cxbx;
	uint16_t si = 0; /* ??????? nevim kolik to je ! */

	enter(0x6, 0);

	/* <zasobnik> sp <lokalni promnene> bp <cosi> <parametry>
	 *  ........           6 bytu          6 bytu  */
/* parametry:
[bx+12]
[bx+10]
[bx+0E]
[bx+0C]
[bx+0A]
[bx+08]
[bx+02]
[bx]
*/

	save(si);

	bp_m_0x6 = *(bp + 0x6) & 0xf;

	dword_cxbx = *((uint32_t *) (bp + 0xc)) + bp_m_0x6;
	dword_axdx = *((uint32_t *) (bp + 0xe)) + bp_m_0x6;

	/* Tohle vypada tak hashovite ;-)). */
	dword_cxbx = f_0x17e(dword_axdx, dword_cxbx)
		      + (si << 0x10)
		      + *((uint32_t *) (bp + 0x6))
		      + *((uint32_t *) (bp + 0xa))
		      + *((uint32_t *) (bp + 0xe))
		      + *((uint32_t *) (bp + 0x12));
	dword_cxbx += f_0x17e(bp_m_0x6 + *((uint32_t *) (bp + 0x6)),
			      bp_m_0x6 + *((uint32_t *) (bp + 0x12)))
			 + *((uint16_t *) (bp + 0x12));
	bp_m_0x4 = dword_cxbx;
	dword_cxbx += dword_cxbx << bp_m_0x6;
	dword_cxbx += *((uint32_t *) (bp + 0xc)) << 0x7;
	dword_cxbx += *((uint32_t *) (bp + 0x12)) << 0xb;
	dword_cxbx += *((uint32_t *) (bp + 0xe)) << 0x11;
	dword_cxbx += bp_m_0x4 << 0xd;
	dword_cxbx += bp_m_0x4 >> 0xf;

	/* we're low-endian, remember */
	bp_m_0x4 = (dword_cxbx & 0x7fffffff) | 0x40000000;

	dword_axdx = bp_m_0x4;

	goto _3528;
_3528:
	load(si);

	leave();

	return dword_axdx;
}

int
main(int argc, char *argv[])
{
/*
0000352B:i55                             push      bp
0000352C:i8BEC                           mov       bp,sp
0000352E:iC45E06                         les       bx,[bp+06]
00003531:i268B4716                       mov       ax,[bx+16]
00003535:i268B5714                       mov       dx,[bx+14]
00003539:i260B5708                       or        dx,[bx+08]
0000353D:i260B470A                       or        ax,[bx+0A]
00003541:i260B570C                       or        dx,[bx+0C]
00003545:i260B470E                       or        ax,[bx+0E]
00003549:i260B5710                       or        dx,[bx+10]
0000354D:i260B4712                       or        ax,[bx+12]
00003551:i83E200                         and (w)   dx,+00
00003554:i250080                         and       ax,8000
00003557:i0BD0                           or        dx,ax
00003559:i7405                           je        file:00003560 -.
0000355B:iB80100                         mov       ax,0001        |
0000355E:iEB5A                           jmps      file:000035BA  | -.
00003560:iC45E06                         les       bx,[bp+06]    <'  |
00003563:i26FF7712                       push (w)  [bx+12]           |
00003567:i26FF7710                       push (w)  [bx+10]           |
0000356B:i26FF770E                       push (w)  [bx+0E]           |
0000356F:i26FF770C                       push (w)  [bx+0C]           |
00003573:i26FF770A                       push (w)  [bx+0A]           |
00003577:i26FF7708                       push (w)  [bx+08]           |
0000357B:i26FF7702                       push (w)  [bx+02]           |
0000357F:i26FF37                         push (w)  [bx]              |
00003582:i0E                             push      cs                |
00003583:iE876FE                         calln     file:000033FC     |
..nejake podivnosti, ktere skakaji na 355E (takze konci) a ruzne pri |
tom nastavuji ax..                                                   |
000035BA:i5D                             pop       bp               <'
000035BB:iCB                             retf
*/

	/*
	 * Yet known working combinations:
	 * P       H       S       N               K               Khex
	 * 16      15      1       09800417        1141891134      440FE03E
	 * 16      4111    1       09800417        1343455301      50138045
	 * 16      4099    3       00000621        1929752320      7305AF00
	 * 16      3       1       09900102        1592149490      5EE645F2
	 * 16      4099    1       09900102        1833170605      6D43F6AD
	 *
	 * Codes stored at (long words, little endian):
	 * f9f0:0  Ser No
	 * f9f0:4  ??? (16 - not used in licensing code)
	 * f9f0:8  P
	 * f9f0:c  H
	 * f9f0:10 S
	 * f9f0:14 K
	 */

	/* bx -> bp+6,
	 * bx+2 -> bp+8,
	 * bp+8 -> bp+a,
	 * bp+a -> bp+c,
	 * bp+c -> bp+e,
	 * bp+e -> bp+10,
	 * bp+10 -> bp+12,
	 * bp+12 -> bp+14 */

	unsigned char bp[0x20];

	if (argc < 4) return 1;

	*((uint32_t *) (bp + 0x6)) = atol(argv[1]); /* N */
	*((uint32_t *) (bp + 0xa)) = atol(argv[2]); /* P */
	*((uint32_t *) (bp + 0xe)) = atol(argv[3]); /* H */
	*((uint32_t *) (bp + 0x12)) = atol(argv[4]); /* S */

	printf("%x\n", function(bp));

	return 0;
}
