// File: /workspace/github_cpp_makefile_star2_O1/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:
movq 0x100(%rdi), %rax
movl 0x80(%rdi), %ecx
cmpl 0x58(%rax), %ecx
jg 0x83b3
cmpl 0x54(%rax), %ecx
jge 0x8600
cmpl $0x1, 0x84(%rdi)
jne 0x83e2
movl 0x68(%rax), %edx
andl $0x7, %ecx
jne 0x83d4
movl %edx, %esi
shrl $0x16, %esi
xorl %edx, %esi
andl $0x1, %esi
leal (%rsi,%rdx,2), %edx
movl %edx, 0x68(%rax)
xorb $0x7, %cl
movl $0x1, %eax
shll %cl, %eax
andl %edx, %eax
jmp 0x8400
movq 0x38(%rax), %rax
movl %ecx, %edx
notb %cl
andb $0x7, %cl
movl $0x1, %esi
shll %cl, %esi
sarl $0x3, %edx
movslq %edx, %rcx
movzbl (%rax,%rcx), %eax
andl %esi, %eax
movl 0x5c(%rdi), %ecx
movl 0x60(%rdi), %esi
xorl %edx, %edx
testl %eax, %eax
setne %dl
leal (%rdx,%rcx,2), %edx
movl %edx, 0x5c(%rdi)
movl 0x70(%rdi), %eax
testl %eax, %eax
je 0x841f
decl %eax
movl %eax, 0x70(%rdi)
movl %esi, %eax
andl $0xffffff1f, %eax       # imm = 0xFFFFFF1F
testb $0x1, %sil
je 0x84e7
movzwl %dx, %r9d
cmpl $0x5224, %r9d           # imm = 0x5224
je 0x846f
xorl %r8d, %r8d
movb $0x1, %r10b
cmpl $0x4489, %r9d           # imm = 0x4489
jne 0x847d
cmpl $0x0, 0x70(%rdi)
je 0x8461
xorl %r8d, %r8d
cmpl $0x1, 0x74(%rdi)
movl $0x0, %r9d
je 0x8480
movl $0x1, %r9d
movb $0x1, %r8b
xorl %r10d, %r10d
jmp 0x8480
movl $0x2, %r9d
xorl %r10d, %r10d
xorl %r8d, %r8d
jmp 0x8480
xorl %r9d, %r9d
testb %r10b, %r10b
jne 0x84e7
movl $0x1, 0x68(%rdi)
cmpl $0x0, 0x70(%rdi)
je 0x84a2
cmpl %r9d, 0x74(%rdi)
je 0x84a2
incl 0x6c(%rdi)
movl $0x3, 0x68(%rdi)
cmpl $0x0, 0x7c(%rdi)
jne 0x84ab
incl 0x6c(%rdi)
movl $0x7, 0x7c(%rdi)
movl $0x10, 0x70(%rdi)
movl %r9d, 0x74(%rdi)
testb %r8b, %r8b
je 0x84dd
andl $0x6, %esi
cmpl $0x2, %esi
jne 0x84e4
orl $0x54, %eax
movabsq $0x10ffffffff, %rsi     # imm = 0x10FFFFFFFF
movq %rsi, 0x54(%rdi)
jmp 0x84e7
orl $0x80, %eax
jmp 0x84e7
orl $0x50, %eax
movl %eax, %r8d
testb $0x4, %r8b
je 0x857d
movl 0x58(%rdi), %esi
testb $0xf, %sil
jne 0x8578
cmpl $0x31, %esi
setb %r9b
testb $0x40, %r8b
sete %r8b
testb %r9b, %r8b
je 0x8516
andl $-0x4d, %eax
jmp 0x8578
pushq %rbx
movl %eax, %r9d
andl $-0x2a, %r9d
orl $0x28, %r9d
xorl %r8d, %r8d
movl $0x4000, %r10d          # imm = 0x4000
movl $0x4000, %r11d          # imm = 0x4000
xorl %ebx, %ebx
testl %edx, %r10d
setne %bl
leal (%rbx,%r8,2), %r8d
shrl $0x2, %r11d
cmpl $0x4, %r10d
movl %r11d, %r10d
jae 0x8531
cmpl $0x30, %esi
cmovel %r9d, %eax
movzwl 0x54(%rdi), %edx
movl %edx, %r9d
shrl $0x8, %r9d
xorl %r8d, %r9d
movslq %r9d, %r8
leaq 0x11b87(%rip), %r9      # 0x1a0f0
movzwl (%r9,%r8,2), %r8d
shll $0x8, %edx
xorl %r8d, %edx
movl %edx, 0x54(%rdi)
popq %rbx
incl %esi
movl %esi, 0x58(%rdi)
movl 0x68(%rdi), %edx
testl %edx, %edx
je 0x858b
decl %edx
movl %edx, 0x68(%rdi)
jmp 0x85fd
movl $0x1, 0x68(%rdi)
movl %eax, %edx
andl $0xfffff8ff, %edx       # imm = 0xFFFFF8FF
andl $0x1, %ecx
movl 0x78(%rdi), %esi
movl 0x7c(%rdi), %r8d
andl $0x7f, %esi
leal (%rcx,%rsi,2), %ecx
movl %ecx, 0x78(%rdi)
incl %r8d
movl %r8d, 0x7c(%rdi)
cmpl $0x8, %r8d
jne 0x85f4
movl $0x0, 0x7c(%rdi)
movl %eax, %ecx
andl $0xfffff8f7, %ecx       # imm = 0xFFFFF8F7
orl $0x200, %ecx            # imm = 0x200
testb $0x8, %al
cmovel %edx, %ecx
movl %ecx, %eax
andl $0xfffffaef, %eax       # imm = 0xFFFFFAEF
orl $0x400, %eax            # imm = 0x400
testb $0x10, %cl
cmovel %ecx, %eax
movl 0x6c(%rdi), %ecx
testl %ecx, %ecx
je 0x85f8
decl %ecx
movl %ecx, 0x6c(%rdi)
jmp 0x85fd
movl %edx, %eax
jmp 0x85fd
orl $0x100, %eax            # imm = 0x100
movl %eax, 0x60(%rdi)
retq