// File: OpenFodder[P]SOS_Unpacker/capsimg/CAPSImg/CapsFDCEmulator.cpp
// Function: FdcShiftBit(CapsFdc*)
void FdcShiftBit(PCAPSFDC pc)
{
	// get selected drive
	PCAPSDRIVE pd=pc->driveprc;

	// do nothing in bit skip area
	if (pc->datalock<=pd->ovlmax && pc->datalock>=pd->ovlmin)
		return;

	// read real or random data
	int bval=(pc->datamode == cfdcdmNoise) ? FdcReadBitNoise(pc) : FdcReadBit(pc);

	// shift read bit into am decoder
	UDWORD amdecode=pc->amdecode<<1;
	if (bval)
		amdecode|=1;
	pc->amdecode=amdecode;

	// get am info, clear AM found, A1 and C2 mark signals
	UDWORD aminfo=pc->aminfo & ~(CAPSFDC_AI_AMFOUND|CAPSFDC_AI_MARKA1|CAPSFDC_AI_MARKC2);

	// bitcell distance of last mark detected
	if (pc->ammarkdist)
		pc->ammarkdist--;

	// am detector if enabled
	if (aminfo & CAPSFDC_AI_AMDETENABLE) {
		// not a mark in shifter/decoder
		int amt=0;

		// check if shifter/decoder has a mark
		// the real hardware probably has two shifters (clocked and fed by data separator) connected to a decoder
		// each bit of the shifter/decoder is for shifter0#0, shifter1#0...shifter0#7, shifter1#7, 
		// only 2 comparisons is needed per cell instead of 8 (A1/0A, C2/14 and 0A/A1, 14/C2)
		switch (amdecode & 0xffff) {
			// A1 mark only enabled if not overlapped with another A1
			case 0x4489:
				if (!pc->ammarkdist || pc->ammarktype!=1)
					amt=1;
				break;

			// C2 mark always enabled
			case 0x5224:
				amt=2;
				break;
		}

		// process mark if found
		if (amt) {
			// we just read the last data bit of a mark, delay by a clock bit to read from decoder#1
			pc->amdatadelay=1;

			// if overlapped with a different mark
			if (pc->ammarkdist && pc->ammarktype!=amt) {
				// dsr value is invalid
				pc->amdataskip++;

				// delay by an additional data bit (data, clock)
				pc->amdatadelay+=2;
			}

			// if dsr is empty dsr shouldn't be flushed, dsr value is invalid
			if (!pc->dsrcnt)
				pc->amdataskip++;

			// force dsr to flush its current value, since data values start from next data bit
			pc->dsrcnt=7;

			// 16 bitcells must be read before next mark, otherwise marks are overlapped (8 clock+data bits)
			pc->ammarkdist=16;

			// save last mark type; only used when marks overlap
			pc->ammarktype=amt;

			// set mark signal, the shifter/decoder must be connected to the crc logic, not dsr
			if (amt == 1) {
				aminfo|=CAPSFDC_AI_MARKA1|CAPSFDC_AI_MA1ACTIVE;

				// if CRC is enabled, first A1 mark activates the CRC logic
				if (aminfo & CAPSFDC_AI_CRCENABLE) {
					// if CRC logic is not activate yet reset CRC value and counter, 16 cells already available as mark
					if (!(aminfo & CAPSFDC_AI_CRCACTIVE)) {
						aminfo|=CAPSFDC_AI_CRCACTIVE;
						pc->crc=~0;
						pc->crccnt=16;
					}
				}
			} else
				aminfo|=CAPSFDC_AI_MARKC2;
		}
	}

	// process CRC if activated
	if (aminfo & CAPSFDC_AI_CRCACTIVE) {
		// process new value at every 16 cells (8 clock/data)
		if (!(pc->crccnt & 0xf)) {
			// reset CRC process if less than 3 consecutive A1 marks detected
			if (pc->crccnt>48 || (aminfo & CAPSFDC_AI_MARKA1)) {
				// 3 consecutive A1 marks found: set AM found signal, disable AM detector
				if (pc->crccnt == 48) {
					aminfo|=CAPSFDC_AI_AMFOUND|CAPSFDC_AI_AMACTIVE;
					aminfo&=~CAPSFDC_AI_AMDETENABLE;
				}

				// select data bits for CRC source byte value; needed without separate clock and data shifters
				int value=0;
				for (int mask=0x4000; mask; mask>>=2) {
					value<<=1;
					if (amdecode & mask)
						value|=1;
				}

				// update CRC
				UWORD crc=(UWORD)pc->crc;
				pc->crc=crctab_ccitt[value^(crc>>8)] ^ (crc << 8);
			} else
				aminfo&=~(CAPSFDC_AI_CRCACTIVE|CAPSFDC_AI_AMACTIVE);
		}

		pc->crccnt++;
	}

	// wait for data clock cycle plus bitcell delay
	if (!pc->amdatadelay) {
		// set next delay
		// just read a clock bit here, next cell is data, that gets processed at the clock bit after that
		pc->amdatadelay=1;

		// clear dsr signals
		aminfo&=~(CAPSFDC_AI_DSRREADY|CAPSFDC_AI_DSRAM|CAPSFDC_AI_DSRMA1);

		// shift data bit into dsr, this is a clock bit, data bit is at decoder#1
		pc->dsr=((pc->dsr<<1) | (amdecode>>1 & 1)) & 0xff;

		// process data if 8 bits are dsr now, otherwise just increase dsr counter
		if (++pc->dsrcnt == 8) {
			// reset dsr counter
			pc->dsrcnt=0;

			// if AM found set dsr signal
			if (aminfo & CAPSFDC_AI_AMACTIVE) {
				aminfo&=~CAPSFDC_AI_AMACTIVE;
				aminfo|=CAPSFDC_AI_DSRAM;
			}

			// if A1 mark found set dsr signal
			if (aminfo & CAPSFDC_AI_MA1ACTIVE) {
				aminfo&=~CAPSFDC_AI_MA1ACTIVE;
				aminfo|=CAPSFDC_AI_DSRMA1;
			}

			// set dsr ready signal, unless data is invalid
			if (!pc->amdataskip)
				aminfo|=CAPSFDC_AI_DSRREADY;
			else
				pc->amdataskip--;
		}
	} else
		pc->amdatadelay--;

	// save new am info
	pc->aminfo=aminfo;
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x40, %rsp
movq %rdi, -0x8(%rbp)
movq -0x8(%rbp), %rax
movq 0x100(%rax), %rax
movq %rax, -0x10(%rbp)
movq -0x8(%rbp), %rax
movl 0x80(%rax), %eax
movq -0x10(%rbp), %rcx
cmpl 0x58(%rcx), %eax
jg 0xbfe6
movq -0x8(%rbp), %rax
movl 0x80(%rax), %eax
movq -0x10(%rbp), %rcx
cmpl 0x54(%rcx), %eax
jl 0xbfe6
jmp 0xc363
movq -0x8(%rbp), %rax
cmpl $0x1, 0x84(%rax)
jne 0xc001
movq -0x8(%rbp), %rdi
callq 0xc3d0
movl %eax, -0x30(%rbp)
jmp 0xc00d
movq -0x8(%rbp), %rdi
callq 0xc370
movl %eax, -0x30(%rbp)
movl -0x30(%rbp), %eax
movl %eax, -0x14(%rbp)
movq -0x8(%rbp), %rax
movl 0x5c(%rax), %eax
shll %eax
movl %eax, -0x18(%rbp)
cmpl $0x0, -0x14(%rbp)
je 0xc02e
movl -0x18(%rbp), %eax
orl $0x1, %eax
movl %eax, -0x18(%rbp)
movl -0x18(%rbp), %ecx
movq -0x8(%rbp), %rax
movl %ecx, 0x5c(%rax)
movq -0x8(%rbp), %rax
movl 0x60(%rax), %eax
andq $-0xe1, %rax
movl %eax, -0x1c(%rbp)
movq -0x8(%rbp), %rax
cmpl $0x0, 0x70(%rax)
je 0xc05f
movq -0x8(%rbp), %rax
movl 0x70(%rax), %ecx
addl $-0x1, %ecx
movl %ecx, 0x70(%rax)
movl -0x1c(%rbp), %eax
andq $0x1, %rax
cmpq $0x0, %rax
je 0xc191
movl $0x0, -0x20(%rbp)
movzwl -0x18(%rbp), %eax
movl %eax, -0x34(%rbp)
subl $0x4489, %eax           # imm = 0x4489
je 0xc093
jmp 0xc087
movl -0x34(%rbp), %eax
subl $0x5224, %eax           # imm = 0x5224
je 0xc0b0
jmp 0xc0b7
movq -0x8(%rbp), %rax
cmpl $0x0, 0x70(%rax)
je 0xc0a7
movq -0x8(%rbp), %rax
cmpl $0x1, 0x74(%rax)
je 0xc0ae
movl $0x1, -0x20(%rbp)
jmp 0xc0b7
movl $0x2, -0x20(%rbp)
cmpl $0x0, -0x20(%rbp)
je 0xc18f
movq -0x8(%rbp), %rax
movl $0x1, 0x68(%rax)
movq -0x8(%rbp), %rax
cmpl $0x0, 0x70(%rax)
je 0xc0fc
movq -0x8(%rbp), %rax
movl 0x74(%rax), %eax
cmpl -0x20(%rbp), %eax
je 0xc0fc
movq -0x8(%rbp), %rax
movl 0x6c(%rax), %ecx
addl $0x1, %ecx
movl %ecx, 0x6c(%rax)
movq -0x8(%rbp), %rax
movl 0x68(%rax), %ecx
addl $0x2, %ecx
movl %ecx, 0x68(%rax)
movq -0x8(%rbp), %rax
cmpl $0x0, 0x7c(%rax)
jne 0xc113
movq -0x8(%rbp), %rax
movl 0x6c(%rax), %ecx
addl $0x1, %ecx
movl %ecx, 0x6c(%rax)
movq -0x8(%rbp), %rax
movl $0x7, 0x7c(%rax)
movq -0x8(%rbp), %rax
movl $0x10, 0x70(%rax)
movl -0x20(%rbp), %ecx
movq -0x8(%rbp), %rax
movl %ecx, 0x74(%rax)
cmpl $0x1, -0x20(%rbp)
jne 0xc181
movl -0x1c(%rbp), %eax
orq $0x50, %rax
movl %eax, -0x1c(%rbp)
movl -0x1c(%rbp), %eax
andq $0x2, %rax
cmpq $0x0, %rax
je 0xc17f
movl -0x1c(%rbp), %eax
andq $0x4, %rax
cmpq $0x0, %rax
jne 0xc17d
movl -0x1c(%rbp), %eax
orq $0x4, %rax
movl %eax, -0x1c(%rbp)
movq -0x8(%rbp), %rax
movl $0xffffffff, 0x54(%rax) # imm = 0xFFFFFFFF
movq -0x8(%rbp), %rax
movl $0x10, 0x58(%rax)
jmp 0xc17f
jmp 0xc18d
movl -0x1c(%rbp), %eax
orq $0x80, %rax
movl %eax, -0x1c(%rbp)
jmp 0xc18f
jmp 0xc191
movl -0x1c(%rbp), %eax
andq $0x4, %rax
cmpq $0x0, %rax
je 0xc27b
movq -0x8(%rbp), %rax
movl 0x58(%rax), %eax
andl $0xf, %eax
cmpl $0x0, %eax
jne 0xc26e
movq -0x8(%rbp), %rax
cmpl $0x30, 0x58(%rax)
ja 0xc1d0
movl -0x1c(%rbp), %eax
andq $0x40, %rax
cmpq $0x0, %rax
je 0xc262
movq -0x8(%rbp), %rax
cmpl $0x30, 0x58(%rax)
jne 0xc1ee
movl -0x1c(%rbp), %eax
orq $0x28, %rax
movl %eax, -0x1c(%rbp)
movl -0x1c(%rbp), %eax
andq $-0x2, %rax
movl %eax, -0x1c(%rbp)
movl $0x0, -0x24(%rbp)
movl $0x4000, -0x28(%rbp)    # imm = 0x4000
cmpl $0x0, -0x28(%rbp)
je 0xc22b
movl -0x24(%rbp), %eax
shll %eax
movl %eax, -0x24(%rbp)
movl -0x18(%rbp), %eax
andl -0x28(%rbp), %eax
cmpl $0x0, %eax
je 0xc21e
movl -0x24(%rbp), %eax
orl $0x1, %eax
movl %eax, -0x24(%rbp)
jmp 0xc220
movl -0x28(%rbp), %eax
sarl $0x2, %eax
movl %eax, -0x28(%rbp)
jmp 0xc1fc
movq -0x8(%rbp), %rax
movl 0x54(%rax), %eax
movw %ax, -0x2a(%rbp)
movl -0x24(%rbp), %eax
movzwl -0x2a(%rbp), %ecx
sarl $0x8, %ecx
xorl %ecx, %eax
movslq %eax, %rcx
leaq 0x1bee4(%rip), %rax     # 0x28130
movzwl (%rax,%rcx,2), %ecx
movzwl -0x2a(%rbp), %eax
shll $0x8, %eax
xorl %eax, %ecx
movq -0x8(%rbp), %rax
movl %ecx, 0x54(%rax)
jmp 0xc26c
movl -0x1c(%rbp), %eax
andq $-0xd, %rax
movl %eax, -0x1c(%rbp)
jmp 0xc26e
movq -0x8(%rbp), %rax
movl 0x58(%rax), %ecx
addl $0x1, %ecx
movl %ecx, 0x58(%rax)
movq -0x8(%rbp), %rax
cmpl $0x0, 0x68(%rax)
jne 0xc34c
movq -0x8(%rbp), %rax
movl $0x1, 0x68(%rax)
movl -0x1c(%rbp), %eax
andq $-0x701, %rax           # imm = 0xF8FF
movl %eax, -0x1c(%rbp)
movq -0x8(%rbp), %rax
movl 0x78(%rax), %ecx
shll %ecx
movl -0x18(%rbp), %eax
shrl %eax
andl $0x1, %eax
orl %eax, %ecx
andl $0xff, %ecx
movq -0x8(%rbp), %rax
movl %ecx, 0x78(%rax)
movq -0x8(%rbp), %rcx
movl 0x7c(%rcx), %eax
addl $0x1, %eax
movl %eax, 0x7c(%rcx)
cmpl $0x8, %eax
jne 0xc34a
movq -0x8(%rbp), %rax
movl $0x0, 0x7c(%rax)
movl -0x1c(%rbp), %eax
andq $0x8, %rax
cmpq $0x0, %rax
je 0xc300
movl -0x1c(%rbp), %eax
andq $-0x9, %rax
movl %eax, -0x1c(%rbp)
movl -0x1c(%rbp), %eax
orq $0x200, %rax            # imm = 0x200
movl %eax, -0x1c(%rbp)
movl -0x1c(%rbp), %eax
andq $0x10, %rax
cmpq $0x0, %rax
je 0xc323
movl -0x1c(%rbp), %eax
andq $-0x11, %rax
movl %eax, -0x1c(%rbp)
movl -0x1c(%rbp), %eax
orq $0x400, %rax            # imm = 0x400
movl %eax, -0x1c(%rbp)
movq -0x8(%rbp), %rax
cmpl $0x0, 0x6c(%rax)
jne 0xc33b
movl -0x1c(%rbp), %eax
orq $0x100, %rax            # imm = 0x100
movl %eax, -0x1c(%rbp)
jmp 0xc348
movq -0x8(%rbp), %rax
movl 0x6c(%rax), %ecx
addl $-0x1, %ecx
movl %ecx, 0x6c(%rax)
jmp 0xc34a
jmp 0xc359
movq -0x8(%rbp), %rax
movl 0x68(%rax), %ecx
addl $-0x1, %ecx
movl %ecx, 0x68(%rax)
movl -0x1c(%rbp), %ecx
movq -0x8(%rbp), %rax
movl %ecx, 0x60(%rax)
addq $0x40, %rsp
popq %rbp
retq
nopl (%rax)