// File: /workspace/github_c_makefile_star2_O0/leiradel[P]zx48k-libretro/src/zx.h
// Function: zx_tick
static uint64_t _zx_tick(int num_ticks, uint64_t pins, void* user_data) {
    zx_t* sys = (zx_t*) user_data;
    /* video decoding and vblank interrupt */
    sys->scanline_counter -= num_ticks;
    if (sys->scanline_counter <= 0) {
        sys->scanline_counter += sys->scanline_period;
        /* decode next video scanline */
        if (_zx_decode_scanline(sys)) {
            /* request vblank interrupt */
            pins |= Z80_INT;
        }
    }

    /* tick audio systems */
    for (int i = 0; i < num_ticks; i++) {
        sys->tick_count++;
        bool sample_ready = beeper_tick(&sys->beeper);
        /* the AY-3-8912 chip runs at half CPU frequency */
        if (sys->type == ZX_TYPE_128) {
            if (sys->tick_count & 1) {
                ay38910_tick(&sys->ay);
            }
        }
        if (sample_ready) {
            float sample = sys->beeper.sample;
            if (sys->type == ZX_TYPE_128) {
                sample += sys->ay.sample;
            }
            sys->sample_buffer[sys->sample_pos++] = sample;
            if (sys->sample_pos == sys->num_samples) {
                if (sys->audio_cb) {
                    sys->audio_cb(sys->sample_buffer, sys->num_samples, sys->user_data);
                }
                sys->sample_pos = 0;
            }
        }
    }

    /* memory and IO requests */
    if (pins & Z80_MREQ) {
        /* a memory request machine cycle
            FIXME: 'contended memory' accesses should inject wait states
        */
        const uint16_t addr = Z80_GET_ADDR(pins);
        if (pins & Z80_RD) {
            Z80_SET_DATA(pins, mem_rd(&sys->mem, addr));
        }
        else if (pins & Z80_WR) {
            mem_wr(&sys->mem, addr, Z80_GET_DATA(pins));
        }
    }
    else if (pins & Z80_IORQ) {
        /* an IO request machine cycle
            see http://problemkaputt.de/zxdocs.htm#zxspectrum for address decoding
        */
        if (pins & Z80_RD) {
            /* an IO read
                FIXME: reading from port xxFF should return 'current VRAM data'
            */
            if ((pins & Z80_A0) == 0) {
                /* Spectrum ULA (...............0)
                    Bits 5 and 7 as read by INning from Port 0xfe are always one
                */
                uint8_t data = (1<<7)|(1<<5);
                /* MIC/EAR flags -> bit 6 */
                if (sys->last_fe_out & (1<<3|1<<4)) {
                    data |= (1<<6);
                }
                /* keyboard matrix bits are encoded in the upper 8 bit of the port address */
                uint16_t column_mask = (~(Z80_GET_ADDR(pins)>>8)) & 0x00FF;
                const uint16_t kbd_lines = kbd_test_lines(&sys->kbd, column_mask);
                data |= (~kbd_lines) & 0x1F;
                Z80_SET_DATA(pins, data);
            }
            else if ((pins & (Z80_A7|Z80_A6|Z80_A5)) == 0) {
                /* Kempston Joystick (........000.....) */
                Z80_SET_DATA(pins, sys->kbd_joymask | sys->joy_joymask);
            }
            else if (sys->type == ZX_TYPE_128){
                /* read from AY-3-8912 (11............0.) */
                if ((pins & (Z80_A15|Z80_A14|Z80_A1)) == (Z80_A15|Z80_A14)) {
                    pins = ay38910_iorq(&sys->ay, AY38910_BC1|pins) & Z80_PIN_MASK;
                }
            }
        }
        else if (pins & Z80_WR) {
            // an IO write
            const uint8_t data = Z80_GET_DATA(pins);
            if ((pins & Z80_A0) == 0) {
                /* Spectrum ULA (...............0)
                    "every even IO port addresses the ULA but to avoid
                    problems with other I/O devices, only FE should be used"
                    FIXME:
                        bit 3: MIC output (CAS SAVE, 0=On, 1=Off)
                */
                sys->border_color = _zx_palette[data & 7] & 0xFFD7D7D7;
                sys->last_fe_out = data;
                beeper_set(&sys->beeper, 0 != (data & (1<<4)));
            }
            else if (sys->type == ZX_TYPE_128) {
                /* Spectrum 128 memory control (0.............0.)
                    http://8bit.yarek.pl/computer/zx.128/
                */
                if ((pins & (Z80_A15|Z80_A1)) == 0) {
                    if (!sys->memory_paging_disabled) {
                        sys->last_mem_config = data;
                        /* bit 3 defines the video scanout memory bank (5 or 7) */
                        sys->display_ram_bank = (data & (1<<3)) ? 7 : 5;
                        /* only last memory bank is mappable */
                        mem_map_ram(&sys->mem, 0, 0xC000, 0x4000, sys->ram[data & 0x7]);

                        /* ROM0 or ROM1 */
                        if (data & (1<<4)) {
                            /* bit 4 set: ROM1 */
                            mem_map_rom(&sys->mem, 0, 0x0000, 0x4000, sys->rom[1]);
                        }
                        else {
                            /* bit 4 clear: ROM0 */
                            mem_map_rom(&sys->mem, 0, 0x0000, 0x4000, sys->rom[0]);
                        }
                    }
                    if (data & (1<<5)) {
                        /* bit 5 prevents further changes to memory pages
                            until computer is reset, this is used when switching
                            to the 48k ROM
                        */
                        sys->memory_paging_disabled = true;
                    }
                }
                else if ((pins & (Z80_A15|Z80_A14|Z80_A1)) == (Z80_A15|Z80_A14)) {
                    /* select AY-3-8912 register (11............0.) */
                    ay38910_iorq(&sys->ay, AY38910_BDIR|AY38910_BC1|pins);
                }
                else if ((pins & (Z80_A15|Z80_A14|Z80_A1)) == Z80_A15) {
                    /* write to AY-3-8912 (10............0.) */
                    ay38910_iorq(&sys->ay, AY38910_BDIR|pins);
                }
            }
        }
    }
    return pins;
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x40, %rsp
movl %edi, -0x4(%rbp)
movq %rsi, -0x10(%rbp)
movq %rdx, -0x18(%rbp)
movq -0x18(%rbp), %rax
movq %rax, -0x20(%rbp)
movl -0x4(%rbp), %edx
movq -0x20(%rbp), %rax
movl 0x1134(%rax), %ecx
subl %edx, %ecx
movl %ecx, 0x1134(%rax)
movq -0x20(%rbp), %rax
cmpl $0x0, 0x1134(%rax)
jg 0x209d6
movq -0x20(%rbp), %rax
movl 0x1130(%rax), %ecx
movq -0x20(%rbp), %rax
addl 0x1134(%rax), %ecx
movl %ecx, 0x1134(%rax)
movq -0x20(%rbp), %rdi
callq 0x23240
testb $0x1, %al
jne 0x209c6
jmp 0x209d4
movq -0x10(%rbp), %rax
orq $0x40000000, %rax       # imm = 0x40000000
movq %rax, -0x10(%rbp)
jmp 0x209d6
movl $0x0, -0x24(%rbp)
movl -0x24(%rbp), %eax
cmpl -0x4(%rbp), %eax
jge 0x20b15
movq -0x20(%rbp), %rax
movl 0x1120(%rax), %ecx
addl $0x1, %ecx
movl %ecx, 0x1120(%rax)
movq -0x20(%rbp), %rdi
addq $0x50, %rdi
callq 0x3370
andb $0x1, %al
movb %al, -0x25(%rbp)
movq -0x20(%rbp), %rax
cmpl $0x1, 0x1114(%rax)
jne 0x20a3f
movq -0x20(%rbp), %rax
movl 0x1120(%rax), %eax
andl $0x1, %eax
cmpl $0x0, %eax
je 0x20a3d
movq -0x20(%rbp), %rdi
addq $0x870, %rdi            # imm = 0x870
callq 0x31a0
jmp 0x20a3f
testb $0x1, -0x25(%rbp)
je 0x20b05
movq -0x20(%rbp), %rax
movss 0x60(%rax), %xmm0
movss %xmm0, -0x2c(%rbp)
movq -0x20(%rbp), %rax
cmpl $0x1, 0x1114(%rax)
jne 0x20a7a
movq -0x20(%rbp), %rax
movss 0x904(%rax), %xmm0
addss -0x2c(%rbp), %xmm0
movss %xmm0, -0x2c(%rbp)
movss -0x2c(%rbp), %xmm0
movq -0x20(%rbp), %rax
movq -0x20(%rbp), %rdx
movl 0x322c(%rdx), %ecx
movl %ecx, %esi
addl $0x1, %esi
movl %esi, 0x322c(%rdx)
movslq %ecx, %rcx
movss %xmm0, 0x3230(%rax,%rcx,4)
movq -0x20(%rbp), %rax
movl 0x322c(%rax), %eax
movq -0x20(%rbp), %rcx
cmpl 0x3228(%rcx), %eax
jne 0x20b03
movq -0x20(%rbp), %rax
cmpq $0x0, 0x3220(%rax)
je 0x20af5
movq -0x20(%rbp), %rax
movq 0x3220(%rax), %rax
movq -0x20(%rbp), %rdi
addq $0x3230, %rdi           # imm = 0x3230
movq -0x20(%rbp), %rcx
movl 0x3228(%rcx), %esi
movq -0x20(%rbp), %rcx
movq 0x3218(%rcx), %rdx
callq *%rax
movq -0x20(%rbp), %rax
movl $0x0, 0x322c(%rax)
jmp 0x20b05
jmp 0x20b07
movl -0x24(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x24(%rbp)
jmp 0x209dd
movq -0x10(%rbp), %rax
andq $0x2000000, %rax        # imm = 0x2000000
cmpq $0x0, %rax
je 0x20bc7
movq -0x10(%rbp), %rax
andq $0xffff, %rax           # imm = 0xFFFF
movw %ax, -0x2e(%rbp)
movq -0x10(%rbp), %rax
andq $0x8000000, %rax        # imm = 0x8000000
cmpq $0x0, %rax
je 0x20b88
movq -0x10(%rbp), %rax
andq $-0xff0001, %rax        # imm = 0xFF00FFFF
movq %rax, -0x40(%rbp)
movq -0x20(%rbp), %rdi
addq $0x1610, %rdi           # imm = 0x1610
movzwl -0x2e(%rbp), %esi
callq 0x235a0
movb %al, %cl
movq -0x40(%rbp), %rax
movzbl %cl, %ecx
shll $0x10, %ecx
movslq %ecx, %rcx
andq $0xff0000, %rcx         # imm = 0xFF0000
orq %rcx, %rax
movq %rax, -0x10(%rbp)
jmp 0x20bc2
movq -0x10(%rbp), %rax
andq $0x10000000, %rax       # imm = 0x10000000
cmpq $0x0, %rax
je 0x20bc0
movq -0x20(%rbp), %rdi
addq $0x1610, %rdi           # imm = 0x1610
movw -0x2e(%rbp), %cx
movq -0x10(%rbp), %rax
andq $0xff0000, %rax         # imm = 0xFF0000
shrq $0x10, %rax
movzwl %cx, %esi
movzbl %al, %edx
callq 0x5490
jmp 0x20bc2
jmp 0x20f40
movq -0x10(%rbp), %rax
andq $0x4000000, %rax        # imm = 0x4000000
cmpq $0x0, %rax
je 0x20f3e
movq -0x10(%rbp), %rax
andq $0x8000000, %rax        # imm = 0x8000000
cmpq $0x0, %rax
je 0x20d31
movq -0x10(%rbp), %rax
andq $0x1, %rax
cmpq $0x0, %rax
jne 0x20c90
movb $-0x60, -0x2f(%rbp)
movq -0x20(%rbp), %rax
movzbl 0x1125(%rax), %eax
andl $0x18, %eax
cmpl $0x0, %eax
je 0x20c22
movzbl -0x2f(%rbp), %eax
orl $0x40, %eax
movb %al, -0x2f(%rbp)
movq -0x10(%rbp), %rax
andq $0xffff, %rax           # imm = 0xFFFF
movzwl %ax, %eax
sarl $0x8, %eax
xorl $-0x1, %eax
andl $0xff, %eax
movw %ax, -0x32(%rbp)
movq -0x20(%rbp), %rdi
addq $0x1158, %rdi           # imm = 0x1158
movzwl -0x32(%rbp), %esi
callq 0x3470
movw %ax, -0x34(%rbp)
movzwl -0x34(%rbp), %ecx
xorl $-0x1, %ecx
andl $0x1f, %ecx
movzbl -0x2f(%rbp), %eax
orl %ecx, %eax
movb %al, -0x2f(%rbp)
movq -0x10(%rbp), %rax
andq $-0xff0001, %rax        # imm = 0xFF00FFFF
movzbl -0x2f(%rbp), %ecx
shll $0x10, %ecx
movslq %ecx, %rcx
andq $0xff0000, %rcx         # imm = 0xFF0000
orq %rcx, %rax
movq %rax, -0x10(%rbp)
jmp 0x20d2c
movq -0x10(%rbp), %rax
andq $0xe0, %rax
cmpq $0x0, %rax
jne 0x20cd8
movq -0x10(%rbp), %rax
andq $-0xff0001, %rax        # imm = 0xFF00FFFF
movq -0x20(%rbp), %rcx
movzbl 0x111d(%rcx), %ecx
movq -0x20(%rbp), %rdx
movzbl 0x111e(%rdx), %edx
orl %edx, %ecx
shll $0x10, %ecx
movslq %ecx, %rcx
andq $0xff0000, %rcx         # imm = 0xFF0000
orq %rcx, %rax
movq %rax, -0x10(%rbp)
jmp 0x20d2a
movq -0x20(%rbp), %rax
cmpl $0x1, 0x1114(%rax)
jne 0x20d28
movq -0x10(%rbp), %rax
andq $0xc002, %rax           # imm = 0xC002
cmpq $0xc000, %rax           # imm = 0xC000
jne 0x20d26
movq -0x20(%rbp), %rdi
addq $0x870, %rdi            # imm = 0x870
movabsq $0x20000000000, %rsi    # imm = 0x20000000000
orq -0x10(%rbp), %rsi
callq 0x3160
movabsq $0xffffffffff, %rcx     # imm = 0xFFFFFFFFFF
andq %rcx, %rax
movq %rax, -0x10(%rbp)
jmp 0x20d28
jmp 0x20d2a
jmp 0x20d2c
jmp 0x20f3c
movq -0x10(%rbp), %rax
andq $0x10000000, %rax       # imm = 0x10000000
cmpq $0x0, %rax
je 0x20f3a
movq -0x10(%rbp), %rax
andq $0xff0000, %rax         # imm = 0xFF0000
shrq $0x10, %rax
movb %al, -0x35(%rbp)
movq -0x10(%rbp), %rax
andq $0x1, %rax
cmpq $0x0, %rax
jne 0x20dbb
movzbl -0x35(%rbp), %eax
andl $0x7, %eax
movslq %eax, %rcx
leaq 0x865b(%rip), %rax      # 0x293d0
movl (%rax,%rcx,4), %ecx
andl $0xffd7d7d7, %ecx       # imm = 0xFFD7D7D7
movq -0x20(%rbp), %rax
movl %ecx, 0x1140(%rax)
movb -0x35(%rbp), %cl
movq -0x20(%rbp), %rax
movb %cl, 0x1125(%rax)
movq -0x20(%rbp), %rdi
addq $0x50, %rdi
movzbl -0x35(%rbp), %ecx
andl $0x10, %ecx
xorl %eax, %eax
cmpl %ecx, %eax
setne %al
movzbl %al, %esi
andl $0x1, %esi
callq 0x235e0
jmp 0x20f38
movq -0x20(%rbp), %rax
cmpl $0x1, 0x1114(%rax)
jne 0x20f36
movq -0x10(%rbp), %rax
andq $0x8002, %rax           # imm = 0x8002
cmpq $0x0, %rax
jne 0x20ece
movq -0x20(%rbp), %rax
testb $0x1, 0x111c(%rax)
jne 0x20eb5
movb -0x35(%rbp), %cl
movq -0x20(%rbp), %rax
movb %cl, 0x1124(%rax)
movzbl -0x35(%rbp), %edx
andl $0x8, %edx
movl $0x5, %ecx
movl $0x7, %eax
cmpl $0x0, %edx
cmovnel %eax, %ecx
movq -0x20(%rbp), %rax
movl %ecx, 0x113c(%rax)
movq -0x20(%rbp), %rdi
addq $0x1610, %rdi           # imm = 0x1610
movq -0x20(%rbp), %r8
addq $0x4230, %r8            # imm = 0x4230
movzbl -0x35(%rbp), %eax
andl $0x7, %eax
cltq
shlq $0xe, %rax
addq %rax, %r8
xorl %esi, %esi
movl $0xc000, %edx           # imm = 0xC000
movl $0x4000, %ecx           # imm = 0x4000
callq 0x3400
movzbl -0x35(%rbp), %eax
andl $0x10, %eax
cmpl $0x0, %eax
je 0x20e8f
movq -0x20(%rbp), %rdi
addq $0x1610, %rdi           # imm = 0x1610
movq -0x20(%rbp), %r8
addq $0x24230, %r8           # imm = 0x24230
addq $0x4000, %r8            # imm = 0x4000
xorl %edx, %edx
movl $0x4000, %ecx           # imm = 0x4000
movl %edx, %esi
callq 0x3080
jmp 0x20eb3
movq -0x20(%rbp), %rdi
addq $0x1610, %rdi           # imm = 0x1610
movq -0x20(%rbp), %r8
addq $0x24230, %r8           # imm = 0x24230
xorl %edx, %edx
movl $0x4000, %ecx           # imm = 0x4000
movl %edx, %esi
callq 0x3080
jmp 0x20eb5
movzbl -0x35(%rbp), %eax
andl $0x20, %eax
cmpl $0x0, %eax
je 0x20ecc
movq -0x20(%rbp), %rax
movb $0x1, 0x111c(%rax)
jmp 0x20f34
movq -0x10(%rbp), %rax
andq $0xc002, %rax           # imm = 0xC002
cmpq $0xc000, %rax           # imm = 0xC000
jne 0x20f00
movq -0x20(%rbp), %rdi
addq $0x870, %rdi            # imm = 0x870
movabsq $0x30000000000, %rsi    # imm = 0x30000000000
orq -0x10(%rbp), %rsi
callq 0x3160
jmp 0x20f32
movq -0x10(%rbp), %rax
andq $0xc002, %rax           # imm = 0xC002
cmpq $0x8000, %rax           # imm = 0x8000
jne 0x20f30
movq -0x20(%rbp), %rdi
addq $0x870, %rdi            # imm = 0x870
movabsq $0x10000000000, %rsi    # imm = 0x10000000000
orq -0x10(%rbp), %rsi
callq 0x3160
jmp 0x20f32
jmp 0x20f34
jmp 0x20f36
jmp 0x20f38
jmp 0x20f3a
jmp 0x20f3c
jmp 0x20f3e
jmp 0x20f40
movq -0x10(%rbp), %rax
addq $0x40, %rsp
popq %rbp
retq
nopw (%rax,%rax)