/*
 * Copyright (C) 2022-2023 nukeykt
 *
 * This file is part of YMF276-LLE.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 *  YMF276/YM3438 emulator.
 *  Thanks:
 *      John McMaster (siliconpr0n.org):
 *          Yamaha YM3438 & YM2610 decap and die shot.
 *      org, andkorzh, HardWareMan (emu-russia):
 *          help & support, YMF276 and YM2612 decap.
 *
 */

// YMF276/YM3438 core

#include <stdio.h>
#include <string.h>

#include "fmopn2.h"

enum {
    eg_state_attack = 0,
    eg_state_decay,
    eg_state_sustain,
    eg_state_release
};

static const int fm_algorithm[4][6][8] = {
    {
        { 1, 1, 1, 1, 1, 1, 1, 1 }, /* OP1_0         */
        { 1, 1, 1, 1, 1, 1, 1, 1 }, /* OP1_1         */
        { 0, 0, 0, 0, 0, 0, 0, 0 }, /* OP2           */
        { 0, 0, 0, 0, 0, 0, 0, 0 }, /* Last operator */
        { 0, 0, 0, 0, 0, 0, 0, 0 }, /* Last operator */
        { 0, 0, 0, 0, 0, 0, 0, 1 }  /* Out           */
    },
    {
        { 0, 1, 0, 0, 0, 1, 0, 0 }, /* OP1_0         */
        { 0, 0, 0, 0, 0, 0, 0, 0 }, /* OP1_1         */
        { 1, 1, 1, 0, 0, 0, 0, 0 }, /* OP2           */
        { 0, 0, 0, 0, 0, 0, 0, 0 }, /* Last operator */
        { 0, 0, 0, 0, 0, 0, 0, 0 }, /* Last operator */
        { 0, 0, 0, 0, 0, 1, 1, 1 }  /* Out           */
    },
    {
        { 0, 0, 0, 0, 0, 0, 0, 0 }, /* OP1_0         */
        { 0, 0, 0, 0, 0, 0, 0, 0 }, /* OP1_1         */
        { 0, 0, 0, 0, 0, 0, 0, 0 }, /* OP2           */
        { 1, 0, 0, 1, 1, 1, 1, 0 }, /* Last operator */
        { 0, 0, 0, 0, 0, 0, 0, 0 }, /* Last operator */
        { 0, 0, 0, 0, 1, 1, 1, 1 }  /* Out           */
    },
    {
        { 0, 0, 1, 0, 0, 1, 0, 0 }, /* OP1_0         */
        { 0, 0, 0, 0, 0, 0, 0, 0 }, /* OP1_1         */
        { 0, 0, 0, 1, 0, 0, 0, 0 }, /* OP2           */
        { 1, 1, 0, 1, 1, 0, 0, 0 }, /* Last operator */
        { 0, 0, 1, 0, 0, 0, 0, 0 }, /* Last operator */
        { 1, 1, 1, 1, 1, 1, 1, 1 }  /* Out           */
    }
};

void FMOPN2_ClockPhase1(fmopn2_t *chip);

void FMOPN2_Prescaler(fmopn2_t *chip)
{
    if (!chip->pinput.phi)
    {
        int ic_check;

        chip->ic_latch[0] = chip->ic_latch[1] << 1;
        chip->ic_latch[0] |= chip->pinput.ic;

        ic_check = (chip->ic_latch[1] & 0x800) == 0 && chip->pinput.ic;

        chip->prescaler_latch[0] = chip->prescaler_latch[1] << 1;
        chip->prescaler_latch[0] |= !ic_check && (chip->prescaler_latch[1] & 0x1f) == 0;

        chip->ic_check_latch[0] = chip->ic_check_latch[1] << 1;
        chip->ic_check_latch[0] |= ic_check;

        chip->phi1_latch[0] = (chip->prescaler_latch[1] & 0x21) != 0;
        chip->phi2_latch[0] = (chip->prescaler_latch[1] & 0xc) != 0;

        if (!(chip->flags & fmopn2_flags_ym3438))
        {
            chip->dphi1_latch[0] = (chip->prescaler_latch[1] & 0x9) != 0;
            chip->dphi2_latch[0] = (chip->prescaler_latch[1] & 0x24) != 0;

            chip->dphi1_latch[2] = chip->dphi1_latch[1];
            chip->dphi2_latch[2] = chip->dphi2_latch[1];
        }
    }
    else
    {
        chip->ic_latch[1] = chip->ic_latch[0] & 0xfff;
        chip->ic_check_latch[1] = chip->ic_check_latch[0] & 0xf;
        chip->prescaler_latch[1] = chip->prescaler_latch[0] & 0x3f;
        chip->phi1_latch[1] = chip->phi1_latch[0] & 0x1;
        chip->phi2_latch[1] = chip->phi2_latch[0] & 0x1;

        if (!(chip->flags & fmopn2_flags_ym3438))
        {
            chip->dphi1_latch[1] = chip->dphi1_latch[0];
            chip->dphi2_latch[1] = chip->dphi2_latch[0];

            chip->dphi1_latch[3] = chip->dphi1_latch[2];
        }
    }

    chip->fsm_reset = (chip->ic_check_latch[1] & 16) != 0;

    if (!(chip->flags & fmopn2_flags_ym3438))
    {
        chip->dclk1 = chip->dphi1_latch[1] && !chip->dphi1_latch[2];
        chip->dclk2 = chip->dphi2_latch[1] && !chip->dphi2_latch[2];
    }
}

void FMOPN2_YMF276DAC(fmopn2_t *chip)
{
    chip->fsm_load_l = (chip->fsm_shifter_ctrl[1] & 0x20) != 0 && chip->i_phi2;
    chip->fsm_load_r = (chip->fsm_shifter_ctrl[1] & 0x20000) != 0 && chip->i_phi2;

    if (chip->dclk1)
    {
        chip->dac_shifter[0] = chip->dac_shifter[1] << 1;

        if (chip->fsm_load_l)
            chip->dac_shifter[0] |= (chip->ch_accm_l[1] >> 1);
        if (chip->fsm_load_r)
            chip->dac_shifter[0] |= (chip->ch_accm_r[1] >> 1);
    }
    if (chip->dclk2)
    {
        chip->dac_shifter[1] = chip->dac_shifter[0];
    }

    if (!chip->pinput.phi)
    {
        chip->fsm_lro_l2[0] = chip->fsm_lro_l2[1] << 1;
        if (chip->fsm_lro_l[1] & 2)
            chip->fsm_lro_l2[0] |= 1;
        chip->fsm_wco_l2[0] = chip->fsm_wco_l2[1] << 1;
        if (chip->fsm_wco_l[1] & 2)
            chip->fsm_wco_l2[0] |= 1;

        chip->dac_so_l[0] = chip->dac_so_l[1] << 1;
        if (chip->dac_shifter[1] & 0x8000)
            chip->dac_so_l[0] |= 1;
    }
    else
    {
        chip->fsm_lro_l2[1] = chip->fsm_lro_l2[0];
        chip->fsm_wco_l2[1] = chip->fsm_wco_l2[0];

        chip->dac_so_l[1] = chip->dac_so_l[0];
    }

    chip->o_bco = chip->dphi1_latch[2] || chip->dphi1_latch[3];
    chip->o_wco = (chip->fsm_wco_l2[1] & 32) != 0;
    chip->o_lro = (chip->fsm_lro_l2[1] & 32) != 0;
    chip->o_so = (chip->dac_so_l[1] & 4) != 0;
}

void FMOPN2_HandleIO(fmopn2_t *chip)
{
    int write_data = chip->input.cs && chip->input.wr && (chip->input.address & 1) == 1 && !chip->input.ic;
    int write_addr = (chip->input.cs && chip->input.wr && (chip->input.address & 1) == 0) || chip->input.ic;
    int read_enable = chip->input.cs && chip->input.rd && !chip->input.ic;
    int io_dir = chip->input.cs && chip->input.rd && !chip->input.ic;
    int data_enable = !io_dir && !chip->input.ic;

    if (chip->input.cs && chip->input.wr)
    {
        chip->data_latch = chip->input.data;
        chip->bank_latch = (chip->input.address >> 1) & 1;
    }

    if (write_addr)
        chip->write_addr_trig = 1;
    if (write_data)
        chip->write_data_trig = 1;

    if (!read_enable)
    {
        chip->status_timer_a_dlatch = chip->timer_a_status[1];
        chip->status_timer_b_dlatch = chip->timer_b_status[1];
    }
}

int FMOPN2_GetBus(fmopn2_t *chip)
{
    int data = 0;
    int io_dir = chip->input.cs && chip->input.rd && !chip->input.ic;
    int data_enable = !io_dir && !chip->input.ic;
    if (data_enable)
        data = chip->data_latch;
    if (chip->io_ic_latch[1])
        data = 0;
    return data;
}


int FMOPN2_ReadTest(fmopn2_t *chip)
{
    if (chip->mode_test_2c[1] & 128)
        return chip->fsm_sel23;
    return 0; // FIXME: high impedance
}

int FMOPN2_ReadStatus(fmopn2_t *chip)
{
    int io_dir = chip->input.cs && chip->input.rd && !chip->input.ic;
    int read_enable = chip->input.cs && chip->input.rd && !chip->input.ic && (chip->input.address & 3) == 0;
    int status;
    int testdata = 0;
    if (!io_dir)
        return 0;
   
    if (!read_enable)
    {
        return 0; // FIXME: floating bus
    }
    if (chip->mode_test_21[1] & 64)
    {
        testdata |= (chip->pg_debug[1] & 1) << 15;
        if (chip->mode_test_21[1] & 1)
            testdata |= ((chip->eg_debug[1] >> 9) & 1) << 14;
        else
            testdata |= (chip->eg_incsh_nonzero[1] & 1) << 14;
        if (chip->mode_test_2c[1] & 16)
            testdata |= chip->ch_out_debug[1] & 0x1ff;
        else
            testdata |= chip->op_output[1] & 0x3fff;
        if (chip->mode_test_21[1] & 128)
            status = testdata & 255;
        else
            status = testdata >> 8;
    }
    else
    {
        status = (chip->busy_latch[1] << 7) | (chip->status_timer_b_dlatch << 1) | chip->status_timer_a_dlatch;
    }
    return status;
}

void FMOPN2_FSM1(fmopn2_t *chip)
{
    int i;
    int connect = 0;
    int reset = chip->input.i_fsm_reset;
    chip->fsm_cnt1[0] = chip->fsm_cnt1[1] + 1;
    if (reset || (chip->fsm_cnt1[1] & 2) != 0)
        chip->fsm_cnt1[0] = 0;
    chip->fsm_cnt2[0] = chip->fsm_cnt2[1];
    if ((chip->fsm_cnt1[1] & 2) != 0)
        chip->fsm_cnt2[0]++;
    if (reset)
        chip->fsm_cnt2[0] = 0;

    if (!(chip->flags & fmopn2_flags_ym3438))
    {
        int cnt_comb = (chip->fsm_cnt2[1] << 2) | chip->fsm_cnt1[1];

        chip->fsm_clock_eg_l = cnt_comb == 30;
        chip->fsm_op1_sel_l = cnt_comb == 6 || cnt_comb == 8 || cnt_comb == 9 || cnt_comb == 10 || cnt_comb == 12 || cnt_comb == 13;
        chip->fsm_sel1_l = cnt_comb == 0;
        chip->fsm_sel2_l = cnt_comb == 1;
        chip->fsm_sel23_l = cnt_comb == 29;
        chip->fsm_ch3_sel_l = cnt_comb == 1 || cnt_comb == 9 || cnt_comb == 17 || cnt_comb == 25;
        chip->fsm_dac_load_l = cnt_comb == 30 || cnt_comb == 4 || cnt_comb == 9 || cnt_comb == 14 || cnt_comb == 20 || cnt_comb == 9;
        chip->fsm_dac_out_sel_l = cnt_comb == 14 || cnt_comb == 16 || cnt_comb == 17 || cnt_comb == 18 || cnt_comb == 20 || cnt_comb == 21 ||
            cnt_comb == 22 || cnt_comb == 24 || cnt_comb == 25 || cnt_comb == 26 || cnt_comb == 28 || cnt_comb == 29;
        chip->fsm_dac_ch6_l = cnt_comb == 4 || cnt_comb == 5 || cnt_comb == 6 || cnt_comb == 8;

        chip->fsm_wco_l[0] = (chip->fsm_wco_l[1] << 1) | ((cnt_comb & 8) == 0);
        chip->fsm_lro_l[0] = chip->fsm_lro_l[1] << 1;
        if (((cnt_comb >> 3) ^ (cnt_comb >> 4)) & 1)
            chip->fsm_lro_l[0] |= 1;
    }

}

void FMOPN2_FSM2(fmopn2_t *chip)
{
    int i, connect = 0;
    int cnt_comb;
    chip->fsm_cnt1[1] = chip->fsm_cnt1[0] & 0x3;
    chip->fsm_cnt2[1] = chip->fsm_cnt2[0] & 0x7;

    cnt_comb = (chip->fsm_cnt2[1] << 2) | chip->fsm_cnt1[1];

    if (!(chip->flags & fmopn2_flags_ym3438))
    {
        chip->fsm_clock_eg = chip->fsm_clock_eg_l;
        chip->fsm_op4_sel = cnt_comb == 0 || cnt_comb == 1 || cnt_comb == 2 || cnt_comb == 4 || cnt_comb == 5 || cnt_comb == 6;
        chip->fsm_op1_sel = chip->fsm_op1_sel_l;
        chip->fsm_op3_sel = cnt_comb == 16 || cnt_comb == 17 || cnt_comb == 18 || cnt_comb == 20 || cnt_comb == 21 || cnt_comb == 22;
        chip->fsm_op2_sel = cnt_comb == 24 || cnt_comb == 25 || cnt_comb == 26 || cnt_comb == 28 || cnt_comb == 29 || cnt_comb == 30;
        chip->fsm_sel2 = chip->fsm_sel2_l;
        chip->fsm_sel23 = chip->fsm_sel23_l;
        chip->fsm_ch3_sel = chip->fsm_ch3_sel_l;
        chip->fsm_dac_load = chip->fsm_dac_load_l;
        chip->fsm_dac_out_sel = chip->fsm_dac_out_sel_l;
        chip->fsm_dac_ch6 = chip->fsm_dac_ch6_l;
        chip->fsm_clock_timers = chip->fsm_sel2_l;
        chip->fsm_clock_timers1 = chip->fsm_sel1_l;

        chip->fsm_wco_l[1] = chip->fsm_wco_l[0];
        chip->fsm_lro_l[1] = chip->fsm_lro_l[0];
    }
    else
    {
        chip->fsm_clock_eg = cnt_comb == 0;
        chip->fsm_op4_sel = cnt_comb == 0 || cnt_comb == 1 || cnt_comb == 2 || cnt_comb == 4 || cnt_comb == 5 || cnt_comb == 6;
        chip->fsm_op1_sel = cnt_comb == 8 || cnt_comb == 9 || cnt_comb == 10 || cnt_comb == 12 || cnt_comb == 13 || cnt_comb == 14;
        chip->fsm_op3_sel = cnt_comb == 16 || cnt_comb == 17 || cnt_comb == 18 || cnt_comb == 20 || cnt_comb == 21 || cnt_comb == 22;
        chip->fsm_op2_sel = cnt_comb == 24 || cnt_comb == 25 || cnt_comb == 26 || cnt_comb == 28 || cnt_comb == 29 || cnt_comb == 30;
        chip->fsm_sel2 = cnt_comb == 2;
        chip->fsm_sel23 = cnt_comb == 30;
        chip->fsm_ch3_sel = cnt_comb == 2 || cnt_comb == 10 || cnt_comb == 18 || cnt_comb == 26;
        chip->fsm_dac_load = cnt_comb == 0 || cnt_comb == 5 || cnt_comb == 10 || cnt_comb == 16 || cnt_comb == 21 || cnt_comb == 26;
        chip->fsm_dac_out_sel = cnt_comb == 16 || cnt_comb == 17 || cnt_comb == 18 || cnt_comb == 20 || cnt_comb == 21 || cnt_comb == 22 ||
            cnt_comb == 24 || cnt_comb == 25 || cnt_comb == 26 || cnt_comb == 28 || cnt_comb == 29 || cnt_comb == 30;
        chip->fsm_dac_ch6 = cnt_comb == 5 || cnt_comb == 6 || cnt_comb == 8 || cnt_comb == 9;
        chip->fsm_clock_timers = cnt_comb == 2;
        chip->fsm_clock_timers1 = cnt_comb == 1;
    }

    for (i = 0; i < 3; i++)
        connect |= ((chip->chan_connect[i][1] >> 5) & 1) << i;

    chip->alg_mod_op1_0 = 0;
    chip->alg_mod_op1_1 = 0;
    chip->alg_mod_op2 = 0;
    chip->alg_mod_prev_0 = 0;
    chip->alg_mod_prev_1 = 0;
    chip->alg_output = 0;

    if (chip->fsm_op2_sel)
    {
        chip->alg_mod_op1_0 |= fm_algorithm[0][0][connect];
        chip->alg_mod_op1_1 |= fm_algorithm[0][1][connect];
        chip->alg_mod_op2 |= fm_algorithm[0][2][connect];
        chip->alg_mod_prev_0 |= fm_algorithm[0][3][connect];
        chip->alg_mod_prev_1 |= fm_algorithm[0][4][connect];
        chip->alg_output |= fm_algorithm[2][5][connect];
    }
    if (chip->fsm_op4_sel)
    {
        chip->alg_mod_op1_0 |= fm_algorithm[1][0][connect];
        chip->alg_mod_op1_1 |= fm_algorithm[1][1][connect];
        chip->alg_mod_op2 |= fm_algorithm[1][2][connect];
        chip->alg_mod_prev_0 |= fm_algorithm[1][3][connect];
        chip->alg_mod_prev_1 |= fm_algorithm[1][4][connect];
        chip->alg_output |= fm_algorithm[3][5][connect];
    }
    if (chip->fsm_op1_sel)
    {
        chip->alg_mod_op1_0 |= fm_algorithm[2][0][connect];
        chip->alg_mod_op1_1 |= fm_algorithm[2][1][connect];
        chip->alg_mod_op2 |= fm_algorithm[2][2][connect];
        chip->alg_mod_prev_0 |= fm_algorithm[2][3][connect];
        chip->alg_mod_prev_1 |= fm_algorithm[2][4][connect];
        chip->alg_output |= fm_algorithm[0][5][connect];
    }
    if (chip->fsm_op3_sel)
    {
        chip->alg_mod_op1_0 |= fm_algorithm[3][0][connect];
        chip->alg_mod_op1_1 |= fm_algorithm[3][1][connect];
        chip->alg_mod_op2 |= fm_algorithm[3][2][connect];
        chip->alg_mod_prev_0 |= fm_algorithm[3][3][connect];
        chip->alg_mod_prev_1 |= fm_algorithm[3][4][connect];
        chip->alg_output |= fm_algorithm[1][5][connect];
    }
}

void FMOPN2_HandleIO1(fmopn2_t *chip)
{
    int write_data_en = !chip->write_data_sr[1] && chip->write_data_dlatch;
    int write_addr_en = !chip->write_addr_sr[1] && chip->write_addr_dlatch;
    int busy_cnt = chip->busy_cnt[1] + chip->busy_latch[1];
    int busy_of = (busy_cnt >> 5) & 1;
    chip->write_addr_trig_sync = chip->write_addr_trig;
    chip->write_data_trig_sync = chip->write_data_trig;
    chip->write_addr_sr[0] = chip->write_addr_dlatch;
    chip->write_data_sr[0] = chip->write_data_dlatch;

    chip->busy_latch[0] = write_data_en || (chip->busy_latch[1] && !(chip->input.ic || busy_of));
    if (chip->input.ic)
        busy_cnt = 0;
    chip->busy_cnt[0] = busy_cnt & 31;
    chip->io_ic_latch[0] = chip->input.ic;
}

void FMOPN2_HandleIO2(fmopn2_t *chip)
{
    chip->write_addr_dlatch = chip->write_addr_trig_sync;
    if (chip->write_addr_dlatch)
        chip->write_addr_trig = 0;
    chip->write_data_dlatch = chip->write_data_trig_sync;
    if (chip->write_data_dlatch)
        chip->write_data_trig = 0;
    chip->write_addr_sr[1] = chip->write_addr_sr[0] & 1;
    chip->write_data_sr[1] = chip->write_data_sr[0] & 1;
    chip->busy_cnt[1] = chip->busy_cnt[0] & 31;
    chip->busy_latch[1] = chip->busy_latch[0] & 1;
    chip->io_ic_latch[1] = chip->io_ic_latch[0] & 1;
}

void FMOPN2_DoShiftRegisters(fmopn2_t *chip, int sel)
{
    int i, j;
    int to = sel;
    int from = sel ^ 1;
    int rot = sel == 0 ? 1 : 0;
#define SLOT_ROTATE(x) rot ? ((x << 1) | ((x >> 11) & 1)) : x
#define CH_ROTATE(x) rot ? ((x << 1) | ((x >> 5) & 1)) : x
    // slot registers
    for (i = 0; i < 2; i++)
    {
        // multi
        for (j = 0; j < 4; j++)
            chip->slot_multi[i][j][to] = SLOT_ROTATE(chip->slot_multi[i][j][from]);
        // dt
        for (j = 0; j < 3; j++)
            chip->slot_dt[i][j][to] = SLOT_ROTATE(chip->slot_dt[i][j][from]);
        // tl
        for (j = 0; j < 7; j++)
            chip->slot_tl[i][j][to] = SLOT_ROTATE(chip->slot_tl[i][j][from]);
        // ar
        for (j = 0; j < 5; j++)
            chip->slot_ar[i][j][to] = SLOT_ROTATE(chip->slot_ar[i][j][from]);
        // ks
        for (j = 0; j < 2; j++)
            chip->slot_ks[i][j][to] = SLOT_ROTATE(chip->slot_ks[i][j][from]);
        // dr
        for (j = 0; j < 5; j++)
            chip->slot_dr[i][j][to] = SLOT_ROTATE(chip->slot_dr[i][j][from]);
        // am
        for (j = 0; j < 1; j++)
            chip->slot_am[i][j][to] = SLOT_ROTATE(chip->slot_am[i][j][from]);
        // sr
        for (j = 0; j < 5; j++)
            chip->slot_sr[i][j][to] = SLOT_ROTATE(chip->slot_sr[i][j][from]);
        // rr
        for (j = 0; j < 4; j++)
            chip->slot_rr[i][j][to] = SLOT_ROTATE(chip->slot_rr[i][j][from]);
        // sl
        for (j = 0; j < 4; j++)
            chip->slot_sl[i][j][to] = SLOT_ROTATE(chip->slot_sl[i][j][from]);
        // ssg eg
        for (j = 0; j < 4; j++)
            chip->slot_ssg_eg[i][j][to] = SLOT_ROTATE(chip->slot_ssg_eg[i][j][from]);
    }
    // channel registers

    // fnum
    for (j = 0; j < 11; j++)
        chip->chan_fnum[j][to] = CH_ROTATE(chip->chan_fnum[j][from]);
    // fnum ch3
    for (j = 0; j < 11; j++)
        chip->chan_fnum_ch3[j][to] = CH_ROTATE(chip->chan_fnum_ch3[j][from]);
    // block
    for (j = 0; j < 3; j++)
        chip->chan_block[j][to] = CH_ROTATE(chip->chan_block[j][from]);
    // block ch3
    for (j = 0; j < 3; j++)
        chip->chan_block_ch3[j][to] = CH_ROTATE(chip->chan_block_ch3[j][from]);
    // connect
    for (j = 0; j < 3; j++)
        chip->chan_connect[j][to] = CH_ROTATE(chip->chan_connect[j][from]);
    // fb
    for (j = 0; j < 3; j++)
        chip->chan_fb[j][to] = CH_ROTATE(chip->chan_fb[j][from]);
    // pms
    for (j = 0; j < 3; j++)
        chip->chan_pms[j][to] = CH_ROTATE(chip->chan_pms[j][from]);
    // ams
    for (j = 0; j < 2; j++)
        chip->chan_ams[j][to] = CH_ROTATE(chip->chan_ams[j][from]);
    // pan
    for (j = 0; j < 2; j++)
        chip->chan_pan[j][to] = CH_ROTATE(chip->chan_pan[j][from]);
#undef SLOT_ROTATE
#undef CH_ROTATE
}

void FMOPN2_FMRegisters1(fmopn2_t *chip)
{
    int i, j;
    int write_data_en = !chip->write_data_sr[1] && chip->write_data_dlatch;
    int write_addr_en = !chip->write_addr_sr[1] && chip->write_addr_dlatch;
    int bus = FMOPN2_GetBus(chip);
    int address = bus | (chip->bank_latch << 8);
    int fm_write = (bus & 0xf0) != 0;


    if (write_addr_en)
        chip->write_fm_address[0] = fm_write;
    else
        chip->write_fm_address[0] = chip->write_fm_address[1];

    if (chip->input.ic)
        chip->fm_address[0] = 0;
    else if (fm_write && write_addr_en)
        chip->fm_address[0] = address;
    else
        chip->fm_address[0] = chip->fm_address[1];

    chip->write_fm_data[0] = (chip->write_fm_address[1] && write_data_en) || (chip->write_fm_data[1] && !write_addr_en);

    if (chip->input.ic)
        chip->fm_data[0] = 0;
    else if (chip->write_fm_address[1] && write_data_en)
        chip->fm_data[0] = bus;
    else
        chip->fm_data[0] = chip->fm_data[1];

    if (write_addr_en)
    {
        chip->write_mode_21[0] = address == 0x21;
        chip->write_mode_22[0] = address == 0x22;
        chip->write_mode_24[0] = address == 0x24;
        chip->write_mode_25[0] = address == 0x25;
        chip->write_mode_26[0] = address == 0x26;
        chip->write_mode_27[0] = address == 0x27;
        chip->write_mode_28[0] = address == 0x28;
        chip->write_mode_2a[0] = address == 0x2a;
        chip->write_mode_2b[0] = address == 0x2b;
        chip->write_mode_2c[0] = address == 0x2c;
    }
    else
    {
        chip->write_mode_21[0] = chip->write_mode_21[1];
        chip->write_mode_22[0] = chip->write_mode_22[1];
        chip->write_mode_24[0] = chip->write_mode_24[1];
        chip->write_mode_25[0] = chip->write_mode_25[1];
        chip->write_mode_26[0] = chip->write_mode_26[1];
        chip->write_mode_27[0] = chip->write_mode_27[1];
        chip->write_mode_28[0] = chip->write_mode_28[1];
        chip->write_mode_2a[0] = chip->write_mode_2a[1];
        chip->write_mode_2b[0] = chip->write_mode_2b[1];
        chip->write_mode_2c[0] = chip->write_mode_2c[1];
    }

    if (chip->input.ic)
    {
        chip->mode_test_21[0] = 0;
        chip->mode_lfo_en[0] = 0;
        chip->mode_lfo_freq[0] = 0;
        chip->mode_timer_a_reg[0] = 0;
        chip->mode_timer_b_reg[0] = 0;
        chip->mode_ch3[0] = 0;
        chip->mode_timer_a_load[0] = 0;
        chip->mode_timer_a_enable[0] = 0;
        chip->mode_timer_a_reset[0] = 0;
        chip->mode_timer_b_load[0] = 0;
        chip->mode_timer_b_enable[0] = 0;
        chip->mode_timer_b_reset[0] = 0;
        chip->mode_kon_operator[0] = 0;
        chip->mode_kon_channel[0] = 0;
        chip->mode_dac_data[0] = 0;
        chip->mode_dac_en[0] = 0;
        chip->mode_test_2c[0] = 0;
        // slot registers
        for (i = 0; i < 2; i++)
        {
            // multi
            for (j = 0; j < 4; j++)
                chip->slot_multi[i][j][0] &= ~1;
            // dt
            for (j = 0; j < 3; j++)
                chip->slot_dt[i][j][0] &= ~1;
            // tl
            for (j = 0; j < 7; j++)
                chip->slot_tl[i][j][0] &= ~1;
            // ar
            for (j = 0; j < 5; j++)
                chip->slot_ar[i][j][0] &= ~1;
            // ks
            for (j = 0; j < 2; j++)
                chip->slot_ks[i][j][0] &= ~1;
            // dr
            for (j = 0; j < 5; j++)
                chip->slot_dr[i][j][0] &= ~1;
            // am
            for (j = 0; j < 1; j++)
                chip->slot_am[i][j][0] &= ~1;
            // sr
            for (j = 0; j < 5; j++)
                chip->slot_sr[i][j][0] &= ~1;
            // rr
            for (j = 0; j < 4; j++)
                chip->slot_rr[i][j][0] &= ~1;
            // sl
            for (j = 0; j < 4; j++)
                chip->slot_sl[i][j][0] &= ~1;
            // ssg eg
            for (j = 0; j < 4; j++)
                chip->slot_ssg_eg[i][j][0] &= ~1;
        }
        // channel registers

        // fn low
        for (j = 0; j < 11; j++)
            chip->chan_fnum[j][0] &= ~1;
        // fn low ch3
        for (j = 0; j < 11; j++)
            chip->chan_fnum_ch3[j][0] &= ~1;
        // block fn high
        for (j = 0; j < 3; j++)
            chip->chan_block[j][0] &= ~1;
        // block fn high ch3
        for (j = 0; j < 3; j++)
            chip->chan_block_ch3[j][0] &= ~1;
        // connect
        for (j = 0; j < 3; j++)
            chip->chan_connect[j][0] &= ~1;
        // fb
        for (j = 0; j < 3; j++)
            chip->chan_fb[j][0] &= ~1;
        // pms
        for (j = 0; j < 3; j++)
            chip->chan_pms[j][0] &= ~1;
        // ams
        for (j = 0; j < 2; j++)
            chip->chan_ams[j][0] &= ~1;
        // pan
        for (j = 0; j < 2; j++)
            chip->chan_pan[j][0] &= ~1;

        chip->chan_a4[0] = 0;
        chip->chan_ac[0] = 0;
    }
    else
    {
        if (write_data_en && chip->write_mode_21[1] && !chip->bank_latch)
            chip->mode_test_21[0] = bus & 255;
        else
            chip->mode_test_21[0] = chip->mode_test_21[1];
        if (write_data_en && chip->write_mode_22[1] && !chip->bank_latch)
        {
            chip->mode_lfo_en[0] = (bus >> 3) & 1;
            chip->mode_lfo_freq[0] = bus & 7;
        }
        else
        {
            chip->mode_lfo_en[0] = chip->mode_lfo_en[1];
            chip->mode_lfo_freq[0] = chip->mode_lfo_freq[1];
        }
        chip->mode_timer_a_reg[0] = 0;
        if (write_data_en && chip->write_mode_24[1] && !chip->bank_latch)
            chip->mode_timer_a_reg[0] |= (bus & 255) << 2;
        else
            chip->mode_timer_a_reg[0] |= chip->mode_timer_a_reg[1] & 0x3fc;
        if (write_data_en && chip->write_mode_25[1] && !chip->bank_latch)
            chip->mode_timer_a_reg[0] |= bus & 3;
        else
            chip->mode_timer_a_reg[0] |= chip->mode_timer_a_reg[1] & 0x3;
        if (write_data_en && chip->write_mode_26[1] && !chip->bank_latch)
            chip->mode_timer_b_reg[0] = bus & 255;
        else
            chip->mode_timer_b_reg[0] = chip->mode_timer_b_reg[1];
        if (write_data_en && chip->write_mode_27[1] && !chip->bank_latch)
        {
            chip->mode_ch3[0] = (bus >> 6) & 3;
            chip->mode_timer_a_load[0] = bus & 1;
            chip->mode_timer_a_enable[0] = (bus >> 2) & 1;
            chip->mode_timer_a_reset[0] = (bus >> 4) & 1;
            chip->mode_timer_b_load[0] = (bus >> 1) & 1;
            chip->mode_timer_b_enable[0] = (bus >> 3) & 1;
            chip->mode_timer_b_reset[0] = (bus >> 5) & 1;
        }
        else
        {
            chip->mode_ch3[0] = chip->mode_ch3[1];
            chip->mode_timer_a_load[0] = chip->mode_timer_a_load[1];
            chip->mode_timer_a_enable[0] = chip->mode_timer_a_enable[1];
            chip->mode_timer_a_reset[0] = 0;
            chip->mode_timer_b_load[0] = chip->mode_timer_b_load[1];
            chip->mode_timer_b_enable[0] = chip->mode_timer_b_enable[1];
            chip->mode_timer_b_reset[0] = 0;
        }
        if (write_data_en && chip->write_mode_28[1] && !chip->bank_latch)
        {
            chip->mode_kon_operator[0] = (bus >> 4) & 15;
            chip->mode_kon_channel[0] = bus & 15;
        }
        else
        {
            chip->mode_kon_operator[0] = chip->mode_kon_operator[1];
            chip->mode_kon_channel[0] = chip->mode_kon_channel[1];
        }
        if (write_data_en && chip->write_mode_2a[1] && !chip->bank_latch)
            chip->mode_dac_data[0] = (bus & 255) ^ 128;
        else
            chip->mode_dac_data[0] = chip->mode_dac_data[1];
        if (write_data_en && chip->write_mode_2b[1] && !chip->bank_latch)
            chip->mode_dac_en[0] = (bus >> 7) & 1;
        else
            chip->mode_dac_en[0] = chip->mode_dac_en[1];
        if (write_data_en && chip->write_mode_2c[1] && !chip->bank_latch)
            chip->mode_test_2c[0] = bus & 0xf8;
        else
            chip->mode_test_2c[0] = chip->mode_test_2c[1];
    }
    if (chip->write_fm_data[1] && (chip->fm_address[1]&3) == chip->reg_cnt1[1]
        && ((chip->fm_address[1]>>2)&1) == ((chip->reg_cnt2[1]>>1)&1) && ((chip->fm_address[1]>>8)&1) == (chip->reg_cnt2[1]&1))
    {
        int bank = (chip->fm_address[1]>>3)&1;
        switch (chip->fm_address[1] & 0xf0)
        {
            case 0x30:
                // multi
                for (j = 0; j < 4; j++)
                {
                    chip->slot_multi[bank][j][0] &= ~1;
                    chip->slot_multi[bank][j][0] |= (chip->fm_data[1] >> (j + 0)) & 1;
                }
                // dt
                for (j = 0; j < 3; j++)
                {
                    chip->slot_dt[bank][j][0] &= ~1;
                    chip->slot_dt[bank][j][0] |= (chip->fm_data[1] >> (j + 4)) & 1;
                }
                break;
            case 0x40:
                // tl
                for (j = 0; j < 7; j++)
                {
                    chip->slot_tl[bank][j][0] &= ~1;
                    chip->slot_tl[bank][j][0] |= (chip->fm_data[1] >> (j + 0)) & 1;
                }
                break;
            case 0x50:
                // ar
                for (j = 0; j < 5; j++)
                {
                    chip->slot_ar[bank][j][0] &= ~1;
                    chip->slot_ar[bank][j][0] |= (chip->fm_data[1] >> (j + 0)) & 1;
                }
                // ks
                for (j = 0; j < 2; j++)
                {
                    chip->slot_ks[bank][j][0] &= ~1;
                    chip->slot_ks[bank][j][0] |= (chip->fm_data[1] >> (j + 6)) & 1;
                }
                break;
            case 0x60:
                // dr
                for (j = 0; j < 5; j++)
                {
                    chip->slot_dr[bank][j][0] &= ~1;
                    chip->slot_dr[bank][j][0] |= (chip->fm_data[1] >> (j + 0)) & 1;
                }
                // am
                for (j = 0; j < 1; j++)
                {
                    chip->slot_am[bank][j][0] &= ~1;
                    chip->slot_am[bank][j][0] |= (chip->fm_data[1] >> (j + 7)) & 1;
                }
                break;
            case 0x70:
                // sr
                for (j = 0; j < 5; j++)
                {
                    chip->slot_sr[bank][j][0] &= ~1;
                    chip->slot_sr[bank][j][0] |= (chip->fm_data[1] >> (j + 0)) & 1;
                }
                break;
            case 0x80:
                // rr
                for (j = 0; j < 4; j++)
                {
                    chip->slot_rr[bank][j][0] &= ~1;
                    chip->slot_rr[bank][j][0] |= (chip->fm_data[1] >> (j + 0)) & 1;
                }
                // sl
                for (j = 0; j < 4; j++)
                {
                    chip->slot_sl[bank][j][0] &= ~1;
                    chip->slot_sl[bank][j][0] |= (chip->fm_data[1] >> (j + 4)) & 1;
                }
                break;
            case 0x90:
                // ssg eg
                for (j = 0; j < 4; j++)
                {
                    chip->slot_ssg_eg[bank][j][0] &= ~1;
                    chip->slot_ssg_eg[bank][j][0] |= (chip->fm_data[1] >> (j + 0)) & 1;
                }
                break;
        }
    }
    if (chip->write_fm_data[1] && (chip->fm_address[1] & 3) == chip->reg_cnt1[1] && ((chip->fm_address[1] >> 8) & 1) == (chip->reg_cnt2[1] & 1))
    {
        switch (chip->fm_address[1] & 0xfc)
        {
            case 0xa0:
                // fnum
                for (j = 0; j < 8; j++)
                {
                    chip->chan_fnum[j][0] &= ~1;
                    chip->chan_fnum[j][0] |= (chip->fm_data[1] >> (j + 0)) & 1;
                }
                for (j = 0; j < 3; j++)
                {
                    chip->chan_fnum[8+j][0] &= ~1;
                    chip->chan_fnum[8+j][0] |= (chip->chan_a4[1] >> (j + 0)) & 1;
                }
                // block
                for (j = 0; j < 3; j++)
                {
                    chip->chan_block[j][0] &= ~1;
                    chip->chan_block[j][0] |= (chip->chan_a4[1] >> (j + 3)) & 1;
                }
                break;
            case 0xa4:
                chip->chan_a4[0] = chip->fm_data[1] & 0x3f;
                break;
            case 0xa8:
                // fnum
                for (j = 0; j < 8; j++)
                {
                    chip->chan_fnum_ch3[j][0] &= ~1;
                    chip->chan_fnum_ch3[j][0] |= (chip->fm_data[1] >> (j + 0)) & 1;
                }
                for (j = 0; j < 3; j++)
                {
                    chip->chan_fnum_ch3[8+j][0] &= ~1;
                    chip->chan_fnum_ch3[8+j][0] |= (chip->chan_ac[1] >> (j + 0)) & 1;
                }
                // block
                for (j = 0; j < 3; j++)
                {
                    chip->chan_block_ch3[j][0] &= ~1;
                    chip->chan_block_ch3[j][0] |= (chip->chan_ac[1] >> (j + 3)) & 1;
                }
                break;
            case 0xac:
                chip->chan_ac[0] = chip->fm_data[1] & 0x3f;
                break;
            case 0xb0:
                // connect
                for (j = 0; j < 3; j++)
                {
                    chip->chan_connect[j][0] &= ~1;
                    chip->chan_connect[j][0] |= (chip->fm_data[1] >> (j + 0)) & 1;
                }
                // fb
                for (j = 0; j < 3; j++)
                {
                    chip->chan_fb[j][0] &= ~1;
                    chip->chan_fb[j][0] |= (chip->fm_data[1] >> (j + 3)) & 1;
                }
                break;
            case 0xb4:
                // pms
                for (j = 0; j < 3; j++)
                {
                    chip->chan_pms[j][0] &= ~1;
                    chip->chan_pms[j][0] |= (chip->fm_data[1] >> (j + 0)) & 1;
                }
                // ams
                for (j = 0; j < 2; j++)
                {
                    chip->chan_ams[j][0] &= ~1;
                    chip->chan_ams[j][0] |= (chip->fm_data[1] >> (j + 4)) & 1;
                }
                // pan
                for (j = 0; j < 2; j++)
                {
                    chip->chan_pan[j][0] &= ~1;
                    chip->chan_pan[j][0] |= !((chip->fm_data[1] >> (j + 6)) & 1);
                }
                break;
        }
    }
    // keyon
    chip->mode_kon[0][0] = chip->mode_kon[0][1] << 1;
    chip->mode_kon[1][0] = chip->mode_kon[1][1] << 1;
    chip->mode_kon[2][0] = chip->mode_kon[2][1] << 1;
    chip->mode_kon[3][0] = chip->mode_kon[3][1] << 1;
    if (chip->reg_cnt2[1] == ((chip->mode_kon_channel[1] >> 2) & 1) && chip->reg_cnt1[1] == (chip->mode_kon_channel[1] & 3))
    {
        chip->mode_kon[0][0] |= (chip->mode_kon_operator[1] >> 0) & 1;
        chip->mode_kon[1][0] |= (chip->mode_kon_operator[1] >> 3) & 1;
        chip->mode_kon[2][0] |= (chip->mode_kon_operator[1] >> 1) & 1;
        chip->mode_kon[3][0] |= (chip->mode_kon_operator[1] >> 2) & 1;
    }
    else
    {
        if (!chip->input.ic)
            chip->mode_kon[0][0] |= (chip->mode_kon[3][1] >> 5) & 1;
        chip->mode_kon[1][0] |= (chip->mode_kon[0][1] >> 5) & 1;
        chip->mode_kon[2][0] |= (chip->mode_kon[1][1] >> 5) & 1;
        chip->mode_kon[3][0] |= (chip->mode_kon[2][1] >> 5) & 1;
    }
}

void FMOPN2_FMRegisters2(fmopn2_t *chip)
{
    chip->write_fm_address[1] = chip->write_fm_address[0];
    chip->write_fm_data[1] = chip->write_fm_data[0];
    chip->fm_address[1] = chip->fm_address[0];
    chip->fm_data[1] = chip->fm_data[0];
    chip->write_mode_21[1] = chip->write_mode_21[0];
    chip->write_mode_22[1] = chip->write_mode_22[0];
    chip->write_mode_24[1] = chip->write_mode_24[0];
    chip->write_mode_25[1] = chip->write_mode_25[0];
    chip->write_mode_26[1] = chip->write_mode_26[0];
    chip->write_mode_27[1] = chip->write_mode_27[0];
    chip->write_mode_28[1] = chip->write_mode_28[0];
    chip->write_mode_2a[1] = chip->write_mode_2a[0];
    chip->write_mode_2b[1] = chip->write_mode_2b[0];
    chip->write_mode_2c[1] = chip->write_mode_2c[0];
    chip->mode_test_21[1] = chip->mode_test_21[0];
    chip->mode_lfo_en[1] = chip->mode_lfo_en[0];
    chip->mode_lfo_freq[1] = chip->mode_lfo_freq[0];
    chip->mode_timer_a_reg[1] = chip->mode_timer_a_reg[0];
    chip->mode_timer_b_reg[1] = chip->mode_timer_b_reg[0];
    chip->mode_ch3[1] = chip->mode_ch3[0];
    chip->mode_timer_a_load[1] = chip->mode_timer_a_load[0];
    chip->mode_timer_a_enable[1] = chip->mode_timer_a_enable[0];
    chip->mode_timer_a_reset[1] = chip->mode_timer_a_reset[0];
    chip->mode_timer_b_load[1] = chip->mode_timer_b_load[0];
    chip->mode_timer_b_enable[1] = chip->mode_timer_b_enable[0];
    chip->mode_timer_b_reset[1] = chip->mode_timer_b_reset[0];
    chip->mode_kon_operator[1] = chip->mode_kon_operator[0];
    chip->mode_kon_channel[1] = chip->mode_kon_channel[0];
    chip->mode_dac_data[1] = chip->mode_dac_data[0];
    chip->mode_dac_en[1] = chip->mode_dac_en[0];
    chip->mode_test_2c[1] = chip->mode_test_2c[0];
    chip->chan_a4[1] = chip->chan_a4[0];
    chip->chan_ac[1] = chip->chan_ac[0];
    chip->mode_kon[0][1] = chip->mode_kon[0][0];
    chip->mode_kon[1][1] = chip->mode_kon[1][0];
    chip->mode_kon[2][1] = chip->mode_kon[2][0];
    chip->mode_kon[3][1] = chip->mode_kon[3][0];
}

void FMOPN2_Misc1(fmopn2_t *chip)
{
    chip->reg_cnt1[0] = chip->reg_cnt1[1] + 1;
    chip->reg_cnt2[0] = chip->reg_cnt2[1];
    if (chip->reg_cnt1[1] & 2)
    {
        chip->reg_cnt1[0] = 0;
        chip->reg_cnt2[0]++;
    }
    if (chip->fsm_sel23 || chip->input.ic)
    {
        chip->reg_cnt1[0] = 0;
        chip->reg_cnt2[0] = 0;
    }
}

void FMOPN2_Misc2(fmopn2_t *chip)
{
    chip->reg_cnt1[1] = chip->reg_cnt1[0] & 3;
    chip->reg_cnt2[1] = chip->reg_cnt2[0] & 7;
}

void FMOPN2_LFO1(fmopn2_t *chip)
{
    static const int lfo_cycles[8] = {
        108, 77, 71, 67, 62, 44, 8, 5
    };
    int inc = (chip->mode_test_21[1] & 2) != 0 || chip->fsm_sel23;
    int freq = chip->mode_lfo_freq[1];
    int of = (chip->lfo_cnt1[1] & lfo_cycles[freq]) == lfo_cycles[freq];

    chip->lfo_cnt1[0] = chip->lfo_cnt1[1] + inc;

    if (chip->input.ic || of)
        chip->lfo_cnt1[0] = 0;

    chip->lfo_cnt2[0] = chip->lfo_cnt2[1] + of;

    if (!chip->mode_lfo_en[1])
        chip->lfo_cnt2[0] = 0;

    chip->lfo_inc_latch[0] = chip->fsm_sel23;

    chip->lfo_dlatch_load = chip->lfo_inc_latch[1];
}

void FMOPN2_LFO2(fmopn2_t *chip)
{
    chip->lfo_cnt1[1] = chip->lfo_cnt1[0] & 127;
    chip->lfo_cnt2[1] = chip->lfo_cnt2[0] & 127;
    chip->lfo_inc_latch[1] = chip->lfo_inc_latch[0];
    if (chip->lfo_inc_latch[1] && !chip->lfo_dlatch_load)
        chip->lfo_dlatch = chip->lfo_cnt2[1];
}

void FMOPN2_PhaseGenerator1(fmopn2_t *chip)
{
    // Note table
    static const int fn_note[16] = {
        0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 3, 3, 3, 3, 3, 3
    };
    // LFO shift
    static const int pg_lfo_sh1[8][8] = {
        { 7, 7, 7, 7, 7, 7, 7, 7 },
        { 7, 7, 7, 7, 7, 7, 7, 7 },
        { 7, 7, 7, 7, 7, 7, 1, 1 },
        { 7, 7, 7, 7, 1, 1, 1, 1 },
        { 7, 7, 7, 1, 1, 1, 1, 0 },
        { 7, 7, 1, 1, 0, 0, 0, 0 },
        { 7, 7, 1, 1, 0, 0, 0, 0 },
        { 7, 7, 1, 1, 0, 0, 0, 0 }
    };

    static const int pg_lfo_sh2[8][8] = {
        { 7, 7, 7, 7, 7, 7, 7, 7 },
        { 7, 7, 7, 7, 2, 2, 2, 2 },
        { 7, 7, 7, 2, 2, 2, 7, 7 },
        { 7, 7, 2, 2, 7, 7, 2, 2 },
        { 7, 7, 2, 7, 7, 7, 2, 7 },
        { 7, 7, 7, 2, 7, 7, 2, 1 },
        { 7, 7, 7, 2, 7, 7, 2, 1 },
        { 7, 7, 7, 2, 7, 7, 2, 1 }
    };
#if 0
    // YM2610 decap
    static const int pg_lfo_sh2[8][8] = {
        { 7, 7, 7, 7, 7, 7, 7, 7 },
        { 7, 7, 7, 7, 2, 2, 2, 2 },
        { 7, 7, 7, 2, 2, 2, 7, 7 },
        { 7, 7, 2, 2, 7, 7, 2, 2 },
        { 7, 2, 2, 7, 7, 2, 2, 7 },
        { 7, 2, 7, 2, 7, 2, 2, 1 },
        { 7, 2, 7, 2, 7, 2, 2, 1 },
        { 7, 2, 7, 2, 7, 2, 2, 1 }
    };
#endif
    static const int pg_detune_add[4] = {
        0, 8, 10, 11
    };
    static const int pg_detune[8] = { 16, 17, 19, 20, 22, 24, 27, 29 };
    int i;
    int fnum = 0;
    int fnum_h;
    int block = 0;
    int pms = 0;
    int dt = 0;
    int dt_l = 0;
    int dt_sum;
    int dt_sum_l;
    int dt_sum_h;
    int kcode;
    int multi = 0;
    int lfo;
    int ch3_sel = chip->reg_cnt1[1] == 1 && (chip->reg_cnt2[1] & 1) == 0 && chip->mode_ch3[1] != 0;
    int op_sel = chip->reg_cnt2[1] >> 1;
    int bank = (chip->reg_cnt2[1] >> 2) & 1;
    int carry = 0;
    int pg_inc;
    int reset;
    if (ch3_sel && op_sel == 0)
    {
        for (i = 0; i < 11; i++)
            fnum |= ((chip->chan_fnum_ch3[i][1] >> 5) & 1) << i;
        for (i = 0; i < 3; i++)
            block |= ((chip->chan_block_ch3[i][1] >> 5) & 1) << i;
    }
    else if (ch3_sel && op_sel == 1)
    {
        for (i = 0; i < 11; i++)
            fnum |= ((chip->chan_fnum_ch3[i][1] >> 0) & 1) << i;
        for (i = 0; i < 3; i++)
            block |= ((chip->chan_block_ch3[i][1] >> 0) & 1) << i;
    }
    else if (ch3_sel && op_sel == 2)
    {
        for (i = 0; i < 11; i++)
            fnum |= ((chip->chan_fnum_ch3[i][1] >> 4) & 1) << i;
        for (i = 0; i < 3; i++)
            block |= ((chip->chan_block_ch3[i][1] >> 4) & 1) << i;
    }
    else
    {
        for (i = 0; i < 11; i++)
            fnum |= ((chip->chan_fnum[i][1] >> 4) & 1) << i;
        for (i = 0; i < 3; i++)
            block |= ((chip->chan_block[i][1] >> 4) & 1) << i;
    }
    for (i = 0; i < 3; i++)
        pms |= ((chip->chan_pms[i][1] >> 5) & 1) << i;
    for (i = 0; i < 3; i++)
        dt |= ((chip->slot_dt[bank][i][1] >> 11) & 1) << i;
    for (i = 0; i < 4; i++)
        multi |= ((chip->slot_multi[bank][i][1] >> 11) & 1) << i;

    kcode = (block << 2) | fn_note[fnum >> 7];

    chip->pg_kcode[0][0] = kcode;
    chip->pg_kcode[1][0] = chip->pg_kcode[0][1];

    chip->pg_fnum[0][0] = fnum;
    chip->pg_fnum[1][0] = chip->pg_fnum[0][1];

    lfo = (chip->lfo_dlatch >> 2) & 7;

    if (chip->lfo_dlatch & 32)
        lfo ^= 7;

    fnum_h = chip->pg_fnum[0][1] >> 4;

    chip->pg_fnum_lfo1 = fnum_h >> pg_lfo_sh1[pms][lfo];
    chip->pg_fnum_lfo2 = fnum_h >> pg_lfo_sh2[pms][lfo];

    chip->pg_lfo_shift = 2;
    if (pms > 5)
        chip->pg_lfo_shift = 7 - pms;

    chip->pg_lfo_sign = (chip->lfo_dlatch >> 6) & 1;

    chip->pg_freq1 = ((chip->pg_fnum[1][1] << 1) + chip->pg_lfo) & 0xfff;
    block = chip->pg_kcode[1][1] >> 2;
    chip->pg_block = block;
    chip->pg_dt[0] = dt;
    
    dt_l = chip->pg_dt[1] & 3;
    kcode = chip->pg_kcode[1][1];
    if (kcode > 28)
        kcode = 28;
    dt_sum = kcode + ((pg_detune_add[dt_l] + 1) << 2);
    dt_sum_l = dt_sum & 7;
    dt_sum_h = dt_sum >> 3;
    chip->pg_detune[0] = dt_l ? pg_detune[dt_sum_l] >> (9 - dt_sum_h) : 0;
    if (chip->pg_dt[1] & 0x04)
        chip->pg_detune[0] = -chip->pg_detune[0];

    chip->pg_freq3 = (chip->pg_freq2 + chip->pg_detune[1]) & 0x1ffff;

    chip->pg_multi[0][0] = multi;
    chip->pg_multi[1][0] = chip->pg_multi[0][1];
    chip->pg_multi2 = chip->pg_multi[1][1];
    chip->pg_inc[0] = chip->pg_freq4;

    chip->pg_inc_mask[0] = chip->pg_inc[1];
    if (chip->pg_reset[1] & 2)
        chip->pg_inc_mask[0] = 0;

    chip->pg_reset_latch[0] = (chip->pg_reset[1] & 2) != 0;

    pg_inc = chip->pg_inc_mask[1];

    reset = chip->pg_reset_latch[1] || (chip->mode_test_21[1] & 8) != 0;

    for (i = 0; i < 20; i++)
    {
        if (!reset)
            carry += (chip->pg_phase[i][1] >> 23) & 1;
        carry += pg_inc & 1;
        chip->pg_phase[i][0] = (chip->pg_phase[i][1] << 1) | (carry & 1);
        pg_inc >>= 1;
        carry >>= 1;
    }

    chip->pg_debug[0] = chip->pg_debug[1] >> 1;
    if (chip->fsm_sel2)
    {
        for (i = 0; i < 10; i++)
        {
            chip->pg_debug[0] |= ((chip->pg_phase[i][1] >> 23) & 1) << i;
        }
    }
}

void FMOPN2_PhaseGenerator2(fmopn2_t *chip)
{
    int i;
    int block = chip->pg_kcode[1][0];
    chip->pg_fnum[0][1] = chip->pg_fnum[0][0];
    chip->pg_fnum[1][1] = chip->pg_fnum[1][0];
    chip->pg_kcode[0][1] = chip->pg_kcode[0][0];
    chip->pg_kcode[1][1] = chip->pg_kcode[1][0];
    chip->pg_lfo = (chip->pg_fnum_lfo1 + chip->pg_fnum_lfo2) >> chip->pg_lfo_shift;
    if (chip->pg_lfo_sign)
        chip->pg_lfo = -chip->pg_lfo;
    chip->pg_freq2 = (chip->pg_freq1 << chip->pg_block) >> 2;
    chip->pg_dt[1] = chip->pg_dt[0];
    chip->pg_detune[1] = chip->pg_detune[0];
    chip->pg_multi[0][1] = chip->pg_multi[0][0];
    chip->pg_multi[1][1] = chip->pg_multi[1][0];
    if (!chip->pg_multi2)
        chip->pg_freq4 = chip->pg_freq3 >> 1;
    else
        chip->pg_freq4 = chip->pg_freq3 * chip->pg_multi2;
    chip->pg_inc[1] = chip->pg_inc[0];
    chip->pg_inc_mask[1] = chip->pg_inc_mask[0];
    chip->pg_reset_latch[1] = chip->pg_reset_latch[0];
    for (i = 0; i < 20; i++)
    {
        chip->pg_phase[i][1] = chip->pg_phase[i][0];
    }

    chip->pg_debug[1] = chip->pg_debug[0];
}

void FMOPN2_EnvelopeGenerator1(fmopn2_t *chip)
{
    int i;
    int sum;
    int add;
    int timer_bit;
    int timer_bit_masked;
    int bank = (chip->reg_cnt2[1] >> 2) & 1;
    int rate_sel;
    int rate = 0;
    int ks = 0;
    int b0, b1;
    int inc1;
    int exp = 0;
    int linear = 0;
    int inc_total = 0;
    int level = 0;
    int level2 = 0;
    int kon;
    int kon2;
    int okon;
    int okon2;
    int state;
    int pg_reset;
    int kon_event;
    int ssg_eg = 0;
    int ssg_inv_e = 0;
    int ssg_dir = 0;
    int ssg_inv = 0;
    int ssg_holdup = 0;
    int ssg_enable;
    int ssg_pgreset = 0;
    int ssg_pgrepeat = 0;
    int eg_off;
    int eg_slreach;
    int sl = 0;
    int nextlevel = 0;
    int nextstate = eg_state_attack;
    int tl = 0;
    int istantattack = 0;
    int eg_output;
    int ams = 0;
    int csm_kon;
    static const int eg_stephi[4][4] = {
        { 0, 0, 0, 0 },
        { 1, 0, 0, 0 },
        { 1, 0, 1, 0 },
        { 1, 1, 1, 0 }
    };
    chip->eg_prescaler_clock_l[0] = chip->fsm_clock_eg;
    chip->eg_prescaler[0] = chip->eg_prescaler[1] + chip->fsm_clock_eg;
    if (((chip->eg_prescaler[1] & 2) != 0 && chip->fsm_clock_eg) || chip->input.ic)
        chip->eg_prescaler[0] = 0;
    chip->eg_step[0] = chip->eg_prescaler[1] >> 1;

    chip->eg_clock_delay[0] = (chip->eg_clock_delay[1] << 1) | chip->fsm_clock_eg;

    chip->eg_timer_load = chip->eg_step[1] && chip->eg_prescaler_clock_l[1];

    sum = (chip->eg_timer[1] >> 11) & 1;
    add = chip->eg_timer_carry[1];
    if ((chip->eg_prescaler[1] & 2) != 0 && chip->eg_prescaler_clock_l[1])
        add = 1;
    sum += add;
    chip->eg_timer_carry[0] = sum >> 1;
    sum &= 1;
    if (chip->input.ic || (chip->mode_test_21[1] & 32) != 0)
        sum = 0;

    chip->eg_timer[0] = (chip->eg_timer[1] << 1) | sum;

    timer_bit = sum;
    if (chip->mode_test_2c[1] & 64)
    {
        if (chip->mode_test_2c[1] & 128) // Assuming TEST pin is NC
            timer_bit |= FMOPN2_ReadTest(chip);
        else
            timer_bit |= chip->input.test & 1;
    }

    chip->eg_timer_mask[0] = timer_bit | chip->eg_timer_mask[1];
    if (chip->fsm_clock_eg || ((chip->eg_clock_delay[1]>>11) & 1) != 0 || chip->input.ic)
        chip->eg_timer_mask[0] = 0;

    timer_bit_masked = timer_bit;
    if (chip->eg_timer_mask[1])
        timer_bit_masked = 0;

    chip->eg_timer_masked[0] = (chip->eg_timer_masked[1] << 1) | timer_bit_masked;

    for (i = 0; i < 10; i++)
    {
        level2 |= ((chip->eg_level[i][1] >> 20) & 1) << i;
    }

    chip->eg_level_latch[0] = level2;

    csm_kon = chip->fsm_ch3_sel && chip->timer_csm_key_dlatch;
    kon2 = ((chip->mode_kon[3][1] >> 5) & 1) | csm_kon;
    chip->eg_kon_latch[0] = (chip->eg_kon_latch[1] << 1) | kon2;
    chip->eg_kon_csm[0] = (chip->eg_kon_csm[1] << 1) | csm_kon;

    kon = (chip->eg_kon_latch[1] >> 1) & 1;
    okon = (chip->eg_key[1] >> 23) & 1;
    pg_reset = (kon && !okon) || (chip->eg_ssg_pgreset[1] & 2) != 0;
    kon_event = (kon && !okon) || (okon && (chip->eg_ssg_pgrepeat[1] & 2) != 0);
    chip->pg_reset[0] = (chip->pg_reset[1] << 1) | pg_reset;
    if (chip->eg_ssg_pgreset[1] & 2)
        chip->pg_reset[0] |= 1;
    chip->eg_key[0] = (chip->eg_key[1] << 1) | kon;

    okon2 = (chip->eg_key[1] >> 21) & 1;

    for (i = 0; i < 4; i++)
        ssg_eg |= ((chip->slot_ssg_eg[bank][i][1] >> 11) & 1) << i;
    ssg_enable = (ssg_eg & 8) != 0;
    ssg_inv_e = ssg_enable && (ssg_eg & 4) != 0;
    if (ssg_enable)
    {
        if (okon2)
        {
            ssg_dir = (chip->eg_ssg_dir[1] >> 23) & 1;
            if (level2 & 512)
            {
                if ((ssg_eg & 3) == 2)
                    ssg_dir ^= 1;
                if ((ssg_eg & 3) == 3)
                    ssg_dir = 1;
            }
        }
        if (kon2)
            ssg_holdup = (ssg_eg & 7) == 3 || (ssg_eg & 7) == 5;
        if (level2 & 512)
        {
            if ((ssg_eg & 3) == 0)
                ssg_pgreset = 1;
            if ((ssg_eg & 1) == 0)
                ssg_pgrepeat = 1;
        }
    }
    ssg_inv = okon2 & (((chip->eg_ssg_dir[1] >> 23) & 1) ^ ssg_inv_e);
    chip->eg_ssg_dir[0] = (chip->eg_ssg_dir[1] << 1) | ssg_dir;
    chip->eg_ssg_inv[0] = ssg_inv;
    chip->eg_ssg_holdup[0] = (chip->eg_ssg_holdup[1] << 1) | ssg_holdup;
    chip->eg_ssg_enable[0] = (chip->eg_ssg_enable[1] << 1) | ssg_enable;
    chip->eg_ssg_pgreset[0] = (chip->eg_ssg_pgreset[1] << 1) | ssg_pgreset;
    chip->eg_ssg_pgrepeat[0] = (chip->eg_ssg_pgrepeat[1] << 1) | ssg_pgrepeat;

    chip->eg_level_ssg[0] = eg_output = chip->eg_ssg_inv[1] ? chip->eg_level_latch_inv : chip->eg_level_latch[1];
    if (chip->mode_test_21[1] & 32)
        eg_output = 0;

    for (i = 0; i < 4; i++)
        sl |= ((chip->slot_sl[bank][i][1] >> 11) & 1) << i;

    if (sl == 15)
        sl |= 16;

    chip->eg_sl[0][0] = sl;
    chip->eg_sl[1][0] = chip->eg_sl[0][1];

    for (i = 0; i < 7; i++)
        tl |= ((chip->slot_tl[bank][i][1] >> 11) & 1) << i;

    chip->eg_tl[0][0] = tl;
    chip->eg_tl[1][0] = chip->eg_tl[0][1];

    b0 = (chip->eg_state[0][1] >> 21) & 1;
    b1 = (chip->eg_state[1][1] >> 21) & 1;

    rate_sel = b1 * 2 + b0;

    if (okon2)
    {
        if (ssg_pgrepeat)
            rate_sel = eg_state_attack;
    }
    else
    {
        if (kon2)
            rate_sel = eg_state_attack;
    }

    switch (rate_sel)
    {
        case eg_state_attack:
            for (i = 0; i < 5; i++)
                rate |= ((chip->slot_ar[bank][i][1] >> 11) & 1) << i;
            break;
        case eg_state_decay:
            for (i = 0; i < 5; i++)
                rate |= ((chip->slot_dr[bank][i][1] >> 11) & 1) << i;
            break;
        case eg_state_sustain:
            for (i = 0; i < 5; i++)
                rate |= ((chip->slot_sr[bank][i][1] >> 11) & 1) << i;
            break;
        case eg_state_release:
            rate = 1;
            for (i = 0; i < 4; i++)
                rate |= ((chip->slot_rr[bank][i][1] >> 11) & 1) << (i + 1);
            break;
    }

    chip->eg_rate_nonzero[0] = rate != 0;
    chip->eg_rate = rate;

    for (i = 0; i < 2; i++)
        ks |= ((chip->slot_ks[bank][i][1] >> 11) & 1) << i;

    chip->eg_ksv = chip->pg_kcode[0][1] >> (ks ^ 3);

    rate = chip->eg_rate2;
    if (rate & 64)
        rate = 63;

    sum = (rate >> 2) + chip->eg_shift_lock;

    inc1 = 0;
    if (rate < 48 && chip->eg_rate_nonzero[1])
    {
        switch (sum & 15)
        {
            case 12:
                inc1 = rate != 0;
                break;
            case 13:
                inc1 = (rate >> 1) & 1;
                break;
            case 14:
                inc1 = rate & 1;
                break;
        }
    }
    chip->eg_inc1 = inc1;
    chip->eg_inc2 = eg_stephi[rate & 3][chip->eg_timer_low_lock];
    chip->eg_rate12 = (rate & 60) == 48;
    chip->eg_rate13 = (rate & 60) == 52;
    chip->eg_rate14 = (rate & 60) == 56;
    chip->eg_rate15 = (rate & 60) == 60;
    chip->eg_maxrate[0] = (rate & 62) == 62;
    chip->eg_prescaler_l = (chip->eg_prescaler[1] & 2) != 0;

    chip->eg_incsh_nonzero[0] = chip->eg_incsh0 | chip->eg_incsh1 | chip->eg_incsh2 | chip->eg_incsh3;


    if (okon && !kon)
    {
        level = chip->eg_level_ssg[1];
    }
    else
    {
        for (i = 0; i < 10; i++)
        {
            level |= ((chip->eg_level[i][1] >> 22) & 1) << i;
        }
    }

    b0 = (chip->eg_state[0][1] >> 23) & 1;
    b1 = (chip->eg_state[1][1] >> 23) & 1;

    state = b1 * 2 + b0;

    exp = kon && (state == eg_state_attack) && !chip->eg_maxrate[1] && level != 0;

    eg_off = (chip->eg_ssg_enable[1] & 2) != 0 ? (level & 512) != 0 : (level & 0x3f0) == 0x3f0;
    eg_slreach = (level >> 4) == (chip->eg_sl[1][1] << 1);

    linear = !kon_event && !eg_off && (state == eg_state_sustain || state == eg_state_release);
    linear |= !kon_event && !eg_off && !eg_slreach && state == eg_state_decay;

    if (exp)
    {
        if (chip->eg_incsh0)
            inc_total |= ~level >> 4;
        if (chip->eg_incsh1)
            inc_total |= ~level >> 3;
        if (chip->eg_incsh2)
            inc_total |= ~level >> 2;
        if (chip->eg_incsh3)
            inc_total |= ~level >> 1;
    }
    if (linear)
    {
        if (chip->eg_ssg_enable[1] & 2)
        {
            if (chip->eg_incsh0)
                inc_total |= 4;
            if (chip->eg_incsh1)
                inc_total |= 8;
            if (chip->eg_incsh2)
                inc_total |= 16;
            if (chip->eg_incsh3)
                inc_total |= 32;
        }
        else
        {
            if (chip->eg_incsh0)
                inc_total |= 1;
            if (chip->eg_incsh1)
                inc_total |= 2;
            if (chip->eg_incsh2)
                inc_total |= 4;
            if (chip->eg_incsh3)
                inc_total |= 8;
        }
    }

    chip->eg_inc_total = inc_total;

    istantattack = chip->eg_maxrate[1] && (!chip->eg_maxrate[1] || kon_event);

    if (!istantattack)
        nextlevel |= level;

    if (chip->eg_kon_csm[1] & 2)
        nextlevel |= chip->eg_tl[1][1] << 3;

    if ((!kon_event && eg_off && (chip->eg_ssg_holdup[1] & 2) == 0 && state != eg_state_attack) || chip->input.ic)
    {
        nextlevel = 0x3ff;
        nextstate |= eg_state_release;
    }

    if (!kon_event && state == eg_state_sustain)
    {
        nextstate |= eg_state_sustain;
    }

    if (!kon_event && state == eg_state_decay && !eg_slreach)
    {
        nextstate |= eg_state_decay;
    }
    if (!kon_event && state == eg_state_decay && eg_slreach)
    {
        nextstate |= eg_state_sustain;
    }

    if (!kon && !kon_event)
    {
        nextstate |= eg_state_release;
    }
    if (!kon_event && state == eg_state_release)
    {
        nextstate |= eg_state_release;
    }

    if (!kon_event && state == eg_state_attack && level == 0)
    {
        nextstate |= eg_state_decay;
    }
    if (chip->input.ic)
    {
        nextstate |= eg_state_release;
    }


    chip->eg_nextlevel[0] = nextlevel;
    b0 = nextstate & 1;
    b1 = (nextstate >> 1) & 1;
    chip->eg_state[0][0] = (chip->eg_state[0][1] << 1) | b0;
    chip->eg_state[1][0] = (chip->eg_state[1][1] << 1) | b1;

    nextlevel = chip->eg_nextlevel[1];

    for (i = 0; i < 10; i++)
    {
        chip->eg_level[i][0] = (chip->eg_level[i][1] << 1) | (nextlevel & 1);
        nextlevel >>= 1;
    }


    if (chip->slot_am[bank][0][1] & (1<<11))
        for (i = 0; i < 2; i++)
            ams |= ((chip->chan_ams[i][1] >> 5) & 1) << i;

    chip->eg_ams = ams;

    if (chip->lfo_dlatch & 64)
        chip->eg_lfo[0] = chip->lfo_dlatch & 63;
    else
        chip->eg_lfo[0] = chip->lfo_dlatch ^ 63;

    chip->eg_ch3_latch[0] = chip->fsm_ch3_sel;

    chip->eg_out_tl = chip->eg_tl[0][1];
    if (chip->eg_ch3_latch[1] && chip->mode_ch3[1] == 2) // CSM
        chip->eg_out_tl = 0;

    chip->eg_out = eg_output + chip->eg_lfo[1];

    chip->eg_debug[0] = chip->eg_debug[1] << 1;
    if (chip->fsm_sel2)
        chip->eg_debug[0] |= chip->eg_out_total;
}

void FMOPN2_EnvelopeGenerator2(fmopn2_t *chip)
{
    int i;
    int b0, b1, b2, b3;
    static const int eg_am_shift[4] = {
        7, 3, 1, 0
    };
    chip->eg_prescaler_clock_l[1] = chip->eg_prescaler_clock_l[0];
    chip->eg_prescaler[1] = chip->eg_prescaler[0] & 3;
    chip->eg_step[1] = chip->eg_step[0];

    chip->eg_timer[1] = chip->eg_timer[0];
    chip->eg_clock_delay[1] = chip->eg_clock_delay[0];
    chip->eg_timer_carry[1] = chip->eg_timer_carry[0];
    chip->eg_timer_mask[1] = chip->eg_timer_mask[0];
    chip->eg_timer_masked[1] = chip->eg_timer_masked[0];

    if (!chip->eg_timer_load && chip->eg_step[1] && chip->eg_prescaler_clock_l[1])
    {
        b0 = (chip->eg_timer[1] >> 11) & 1;
        b1 = (chip->eg_timer[1] >> 10) & 1;
        chip->eg_timer_low_lock = b1 * 2 + b0;

        b0 = (chip->eg_timer_masked[1] & 0xaaa) != 0;
        b1 = (chip->eg_timer_masked[1] & 0x666) != 0;
        b2 = (chip->eg_timer_masked[1] & 0x1e1) != 0;
        b3 = (chip->eg_timer_masked[1] & 0x1f) != 0;
        chip->eg_shift_lock = b3 * 8 + b2 * 4 + b1 * 2 + b0;
    }

    chip->eg_rate_nonzero[1] = chip->eg_rate_nonzero[0];

    chip->eg_rate2 = (chip->eg_rate << 1) + chip->eg_ksv;

    chip->eg_maxrate[1] = chip->eg_maxrate[0];

    chip->eg_incsh0 = 0;
    chip->eg_incsh1 = 0;
    chip->eg_incsh2 = 0;
    chip->eg_incsh3 = 0;

    if (chip->eg_prescaler_l)
    {
        chip->eg_incsh0 = chip->eg_inc1;
        chip->eg_incsh3 = chip->eg_rate15;
        if (!chip->eg_inc2)
        {
            chip->eg_incsh0 |= chip->eg_rate12;
            chip->eg_incsh1 = chip->eg_rate13;
            chip->eg_incsh2 = chip->eg_rate14;
        }
        else
        {
            chip->eg_incsh1 = chip->eg_rate12;
            chip->eg_incsh2 = chip->eg_rate13;
            chip->eg_incsh3 |= chip->eg_rate14;
        }
    }

    chip->eg_incsh_nonzero[1] = chip->eg_incsh_nonzero[0];
    chip->eg_kon_latch[1] = chip->eg_kon_latch[0];

    chip->eg_level_ssg[1] = chip->eg_level_ssg[0];

    chip->pg_reset[1] = chip->pg_reset[0];

    chip->eg_ssg_dir[1] = chip->eg_ssg_dir[0];
    chip->eg_ssg_inv[1] = chip->eg_ssg_inv[0];
    chip->eg_ssg_holdup[1] = chip->eg_ssg_holdup[0];
    chip->eg_ssg_enable[1] = chip->eg_ssg_enable[0];
    chip->eg_ssg_pgreset[1] = chip->eg_ssg_pgreset[0];
    chip->eg_ssg_pgrepeat[1] = chip->eg_ssg_pgrepeat[0];

    chip->eg_level_latch[1] = chip->eg_level_latch[0];
    chip->eg_level_latch_inv = (512 - chip->eg_level_latch[0]) & 0x3ff;

    chip->eg_sl[0][1] = chip->eg_sl[0][0];
    chip->eg_sl[1][1] = chip->eg_sl[1][0];
    chip->eg_tl[0][1] = chip->eg_tl[0][0];
    chip->eg_tl[1][1] = chip->eg_tl[1][0];

    chip->eg_nextlevel[1] = chip->eg_nextlevel[0] + chip->eg_inc_total;

    chip->eg_kon_csm[1] = chip->eg_kon_csm[0];

    for (i = 0; i < 10; i++)
    {
        chip->eg_level[i][1] = chip->eg_level[i][0];
    }

    chip->eg_state[0][1] = chip->eg_state[0][0];
    chip->eg_state[1][1] = chip->eg_state[1][0];

    chip->eg_lfo[1] = (chip->eg_lfo[0] << 1) >> eg_am_shift[chip->eg_ams];

    chip->eg_ch3_latch[1] = chip->eg_ch3_latch[0];

    chip->eg_out_total = (chip->eg_out & 1023) + (chip->eg_out_tl << 3);
    if ((chip->eg_out & 1024) != 0 || (chip->eg_out_total & 1024) != 0)
        chip->eg_out_total = 1023;

    chip->eg_debug[1] = chip->eg_debug[0];
    chip->eg_key[1] = chip->eg_key[0];
}

void FMOPN2_Operator1(fmopn2_t *chip)
{
    int i;
    int carry = 0;
    int phase = 0;
    int quarter;
    int index;
    int atten = 0;
    int output;
    int mod1 = 0, mod2 = 0;
    int mod;
    int fb = 0;
    static const int logsin[128] = {
        0x6c3, 0x58b, 0x4e4, 0x471, 0x41a, 0x3d3, 0x398, 0x365, 0x339, 0x311, 0x2ed, 0x2cd, 0x2af, 0x293, 0x279, 0x261,
        0x24b, 0x236, 0x222, 0x20f, 0x1fd, 0x1ec, 0x1dc, 0x1cd, 0x1be, 0x1b0, 0x1a2, 0x195, 0x188, 0x17c, 0x171, 0x166,
        0x15b, 0x150, 0x146, 0x13c, 0x133, 0x129, 0x121, 0x118, 0x10f, 0x107, 0x0ff, 0x0f8, 0x0f0, 0x0e9, 0x0e2, 0x0db,
        0x0d4, 0x0cd, 0x0c7, 0x0c1, 0x0bb, 0x0b5, 0x0af, 0x0a9, 0x0a4, 0x09f, 0x099, 0x094, 0x08f, 0x08a, 0x086, 0x081,
        0x07d, 0x078, 0x074, 0x070, 0x06c, 0x068, 0x064, 0x060, 0x05c, 0x059, 0x055, 0x052, 0x04e, 0x04b, 0x048, 0x045,
        0x042, 0x03f, 0x03c, 0x039, 0x037, 0x034, 0x031, 0x02f, 0x02d, 0x02a, 0x028, 0x026, 0x024, 0x022, 0x020, 0x01e,
        0x01c, 0x01a, 0x018, 0x017, 0x015, 0x014, 0x012, 0x011, 0x00f, 0x00e, 0x00d, 0x00c, 0x00a, 0x009, 0x008, 0x007,
        0x007, 0x006, 0x005, 0x004, 0x004, 0x003, 0x002, 0x002, 0x001, 0x001, 0x001, 0x001, 0x000, 0x000, 0x000, 0x000
    };
    static const int logsin_d[128] = {
        0x196, 0x07c, 0x04a, 0x035, 0x029, 0x022, 0x01d, 0x019, 0x015, 0x013, 0x012, 0x00f, 0x00e, 0x00d, 0x00d, 0x00c,
        0x00b, 0x00a, 0x00a, 0x009, 0x009, 0x009, 0x008, 0x007, 0x007, 0x007, 0x007, 0x006, 0x007, 0x006, 0x006, 0x005,
        0x005, 0x005, 0x005, 0x005, 0x004, 0x005, 0x004, 0x004, 0x005, 0x004, 0x004, 0x003, 0x004, 0x003, 0x003, 0x003,
        0x003, 0x004, 0x003, 0x003, 0x003, 0x003, 0x003, 0x003, 0x003, 0x002, 0x003, 0x003, 0x003, 0x003, 0x002, 0x002,
        0x002, 0x002, 0x002, 0x002, 0x002, 0x002, 0x002, 0x002, 0x002, 0x002, 0x002, 0x001, 0x002, 0x002, 0x002, 0x001,
        0x001, 0x001, 0x002, 0x002, 0x001, 0x001, 0x002, 0x001, 0x001, 0x001, 0x001, 0x001, 0x001, 0x001, 0x001, 0x001,
        0x001, 0x001, 0x001, 0x000, 0x001, 0x000, 0x001, 0x000, 0x001, 0x001, 0x000, 0x000, 0x001, 0x001, 0x001, 0x001,
        0x000, 0x000, 0x000, 0x001, 0x000, 0x000, 0x001, 0x000, 0x001, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000
    };
    static const int pow[128] = {
        0x3f5, 0x3ea, 0x3df, 0x3d4, 0x3c9, 0x3bf, 0x3b4, 0x3a9, 0x39f, 0x394, 0x38a, 0x37f, 0x375, 0x36a, 0x360, 0x356,
        0x34c, 0x342, 0x338, 0x32e, 0x324, 0x31a, 0x310, 0x306, 0x2fd, 0x2f3, 0x2e9, 0x2e0, 0x2d6, 0x2cd, 0x2c4, 0x2ba,
        0x2b1, 0x2a8, 0x29e, 0x295, 0x28c, 0x283, 0x27a, 0x271, 0x268, 0x25f, 0x257, 0x24e, 0x245, 0x23c, 0x234, 0x22b,
        0x223, 0x21a, 0x212, 0x209, 0x201, 0x1f9, 0x1f0, 0x1e8, 0x1e0, 0x1d8, 0x1d0, 0x1c8, 0x1c0, 0x1b8, 0x1b0, 0x1a8,
        0x1a0, 0x199, 0x191, 0x189, 0x181, 0x17a, 0x172, 0x16b, 0x163, 0x15c, 0x154, 0x14d, 0x146, 0x13e, 0x137, 0x130,
        0x129, 0x122, 0x11b, 0x114, 0x10c, 0x106, 0x0ff, 0x0f8, 0x0f1, 0x0ea, 0x0e3, 0x0dc, 0x0d6, 0x0cf, 0x0c8, 0x0c2,
        0x0bb, 0x0b5, 0x0ae, 0x0a8, 0x0a1, 0x09b, 0x094, 0x08e, 0x088, 0x082, 0x07b, 0x075, 0x06f, 0x069, 0x063, 0x05d,
        0x057, 0x051, 0x04b, 0x045, 0x03f, 0x039, 0x033, 0x02d, 0x028, 0x022, 0x01c, 0x016, 0x011, 0x00b, 0x006, 0x000,
    };
    static const int pow_d[128] = {
        0x005, 0x005, 0x005, 0x006, 0x006, 0x005, 0x005, 0x005, 0x005, 0x005, 0x005, 0x005, 0x005, 0x006, 0x005, 0x005,
        0x005, 0x005, 0x005, 0x005, 0x005, 0x005, 0x005, 0x005, 0x005, 0x005, 0x005, 0x005, 0x005, 0x005, 0x004, 0x005,
        0x004, 0x004, 0x005, 0x005, 0x005, 0x005, 0x005, 0x005, 0x005, 0x005, 0x004, 0x004, 0x004, 0x005, 0x004, 0x005,
        0x004, 0x004, 0x004, 0x005, 0x004, 0x004, 0x005, 0x004, 0x004, 0x004, 0x004, 0x004, 0x004, 0x004, 0x004, 0x004,
        0x004, 0x003, 0x004, 0x004, 0x004, 0x004, 0x004, 0x004, 0x004, 0x004, 0x004, 0x004, 0x003, 0x004, 0x004, 0x004,
        0x003, 0x003, 0x003, 0x003, 0x004, 0x003, 0x003, 0x003, 0x003, 0x003, 0x004, 0x004, 0x003, 0x003, 0x004, 0x003,
        0x003, 0x003, 0x003, 0x003, 0x003, 0x003, 0x004, 0x003, 0x003, 0x003, 0x003, 0x003, 0x003, 0x003, 0x003, 0x003,
        0x003, 0x003, 0x003, 0x003, 0x003, 0x003, 0x003, 0x003, 0x002, 0x003, 0x003, 0x003, 0x003, 0x003, 0x002, 0x003,
    };
    for (i = 0; i < 10; i++)
    {
        carry += (chip->op_mod[i][1] >> 5) & 1;
        carry += (chip->pg_phase[10 + i][1] >> 19) & 1;
        phase += (carry & 1) << i;
        carry >>= 1;
    }
    chip->op_phase[0] = phase;

    chip->op_sign[0] = (chip->op_sign[1] << 1) | ((chip->op_phase[1] >> 9) & 1);

    quarter = chip->op_phase[1] & 255;
    if (chip->op_phase[1] & 256)
        quarter ^= 255;

    chip->op_logsin_add_delta[0] = (quarter & 1) == 0;

    chip->op_logsin_base[0] = logsin[quarter >> 1];
    chip->op_logsin_delta[0] = logsin_d[quarter >> 1];

    chip->op_env[0] = chip->eg_out_total;

    atten = chip->op_logsin_base[1];
    if (chip->op_logsin_add_delta[1])
        atten += chip->op_logsin_delta[1];

    atten += chip->op_env[1] << 2;

    chip->op_atten[0] = atten;

    atten = chip->op_atten[1];
    if (atten & 4096)
        atten = 4095;

    index = atten & 255;
    chip->op_shift[0] = atten >> 8;

    chip->op_pow_add_delta[0] = (index & 1) == 0;

    chip->op_pow_base[0] = pow[index >> 1];
    chip->op_pow_delta[0] = pow_d[index >> 1];

    output = chip->op_pow_base[1];
    if (chip->op_pow_add_delta[1])
        output += chip->op_pow_delta[1];

    output |= 0x400;

    output = (output << 2) >> chip->op_shift[1];

    if (chip->mode_test_21[1] & 16)
        output ^= 1 << 13;

    if (chip->op_sign[1] & 4)
    {
        output ^= 0x3fff;
        output++;
    }

    chip->op_output[0] = output;

    for (i = 0; i < 14; i++)
    {
        chip->op_op1[0][i][0] = chip->op_op1[0][i][1] << 1;
        chip->op_op1[1][i][0] = chip->op_op1[1][i][1] << 1;
        chip->op_op2[i][0] = chip->op_op2[i][1] << 1;
        if (chip->fsm_op1_sel)
        {
            chip->op_op1[0][i][0] |= (chip->op_output[1] >> i) & 1;
            chip->op_op1[1][i][0] |= (chip->op_op1[0][i][1] >> 5) & 1;
        }
        else
        {
            chip->op_op1[0][i][0] |= (chip->op_op1[0][i][1] >> 5) & 1;
            chip->op_op1[1][i][0] |= (chip->op_op1[1][i][1] >> 5) & 1;
        }
        if (chip->fsm_op2_sel)
            chip->op_op2[i][0] |= (chip->op_output[1] >> i) & 1;
        else
            chip->op_op2[i][0] |= (chip->op_op2[i][1] >> 5) & 1;
    }

    if (chip->alg_mod_op1_0)
    {
        for (i = 0; i < 14; i++)
            mod2 |= ((chip->op_op1[0][i][1] >> 5) & 1) << i;
    }
    if (chip->alg_mod_op1_1)
    {
        for (i = 0; i < 14; i++)
            mod1 |= ((chip->op_op1[1][i][1] >> 5) & 1) << i;
    }
    if (chip->alg_mod_op2)
    {
        for (i = 0; i < 14; i++)
            mod1 |= ((chip->op_op2[i][1] >> 5) & 1) << i;
    }
    if (chip->alg_mod_prev_0)
    {
        mod2 |= chip->op_output[1] & 0x3fff;
    }
    if (chip->alg_mod_prev_1)
    {
        mod1 |= chip->op_output[1] & 0x3fff;
    }
    if (mod1 & (1 << 13))
        mod1 |= 1 << 14;
    if (mod2 & (1 << 13))
        mod2 |= 1 << 14;
    mod = (mod1 + mod2) >> 1;
    mod &= 0x3fff;

    chip->op_mod_sum[0] = mod;
    chip->op_dofeedback[0] = chip->fsm_op2_sel;

    if (chip->op_dofeedback[1])
    {
        for (i = 0; i < 3; i++)
            fb |= (chip->chan_fb[i][1] & 1) << i;
        if (!fb)
            mod = 0;
        else
        {
            mod = chip->op_mod_sum[1];
            if (mod & (1 << 13))
                mod |= ~0x3fff;

            mod = mod >> (9 - fb);
        }
    }
    else
        mod = chip->op_mod_sum[1];

    for (i = 0; i < 10; i++)
    {
        chip->op_mod[i][0] = (chip->op_mod[i][1] << 1) | (mod & 1);
        mod >>= 1;
    }
}

void FMOPN2_Operator2(fmopn2_t *chip)
{
    int i;
    for (i = 0; i < 10; i++)
    {
        chip->op_mod[i][1] = chip->op_mod[i][0];
    }
    for (i = 0; i < 14; i++)
    {
        chip->op_op1[0][i][1] = chip->op_op1[0][i][0];
        chip->op_op1[1][i][1] = chip->op_op1[1][i][0];
        chip->op_op2[i][1] = chip->op_op2[i][0];
    }
    chip->op_phase[1] = chip->op_phase[0];
    chip->op_sign[1] = chip->op_sign[0];
    chip->op_logsin_add_delta[1] = chip->op_logsin_add_delta[0];
    chip->op_logsin_base[1] = chip->op_logsin_base[0];
    chip->op_logsin_delta[1] = chip->op_logsin_delta[0];
    chip->op_env[1] = chip->op_env[0];
    chip->op_atten[1] = chip->op_atten[0];
    chip->op_pow_add_delta[1] = chip->op_pow_add_delta[0];
    chip->op_pow_base[1] = chip->op_pow_base[0];
    chip->op_pow_delta[1] = chip->op_pow_delta[0];
    chip->op_shift[1] = chip->op_shift[0];
    chip->op_output[1] = chip->op_output[0];
    chip->op_mod_sum[1] = chip->op_mod_sum[0];
    chip->op_dofeedback[1] = chip->op_dofeedback[0];
}

void FMOPN2_YM3438Accumulator1(fmopn2_t *chip)
{
    int i;
    int sum;
    int inp = 0;
    int acc = 0;
    int test_dac = (chip->mode_test_2c[1] & 32) != 0;
    int load = test_dac || chip->fsm_op1_sel;
    int acc_clear = load && !test_dac;
    sum = test_dac;
    if (chip->alg_output && !test_dac)
        inp = (chip->op_output[1] >> 5) & 511;
    if (!acc_clear)
        for (i = 0; i < 9; i++)
            acc += ((chip->ch_accm[i][1] >> 5) & 1) << i;

    sum = test_dac + inp + acc;

    sum &= 511;

    if ((inp & 256) != 0 && (acc & 256) != 0 && (sum & 256) == 0)
        sum = 256;
    else if ((inp & 256) == 0 && (acc & 256) == 0 && (sum & 256) != 0)
        sum = 255;

    for (i = 0; i < 9; i++)
        chip->ch_accm[i][0] = (chip->ch_accm[i][1] << 1) | ((sum >> i) & 1);

    for (i = 0; i < 9; i++)
    {
        chip->ch_out[i][0] = chip->ch_out[i][1] << 1;
        if (load)
            chip->ch_out[i][0] |= (chip->ch_accm[i][1] >> 5) & 1;
        else
            chip->ch_out[i][0] |= (chip->ch_out[i][1] >> 5) & 1;
    }

    chip->ch_dac_load = chip->fsm_dac_load;

    chip->ch_out_debug[0] = chip->ch_out_dlatch;
}

void FMOPN2_YM3438Accumulator2(fmopn2_t* chip)
{
    int i;
    int test_dac = (chip->mode_test_2c[1] & 32) != 0;
    int do_out = 0;
    int sign;
    int out;
    for (i = 0; i < 9; i++)
    {
        chip->ch_accm[i][1] = chip->ch_accm[i][0];
        chip->ch_out[i][1] = chip->ch_out[i][0];
    }
    if ((chip->fsm_dac_load && !chip->ch_dac_load) || test_dac)
    {
        chip->ch_out_dlatch = 0;
        if (chip->fsm_dac_out_sel || test_dac)
        {
            for (i = 0; i < 9; i++)
                chip->ch_out_dlatch |= ((chip->ch_out[i][1] >> 5) & 1) << i;
        }
        else
        {
            for (i = 0; i < 9; i++)
                chip->ch_out_dlatch |= ((chip->ch_out[i][1] >> 4) & 1) << i;
        }
    }
    if ((chip->fsm_dac_ch6 && chip->mode_dac_en[1]) || test_dac)
    {
        chip->dac_val = chip->mode_dac_data[1] << 1;
        chip->dac_val |= (chip->mode_test_2c[1] & 8) != 0;
    }
    else
        chip->dac_val = chip->ch_out_dlatch;

    if (chip->fsm_dac_load && !chip->ch_dac_load)
    {
        chip->ch_out_pan_dlatch = 0;
        if (chip->fsm_dac_out_sel)
        {
            for (i = 0; i < 2; i++)
                chip->ch_out_pan_dlatch |= (((chip->chan_pan[i][1] >> 5) & 1) ^ 1) << i;
        }
        else
        {
            for (i = 0; i < 2; i++)
                chip->ch_out_pan_dlatch |= (((chip->chan_pan[i][1] >> 4) & 1) ^ 1) << i;
        }
    }

    do_out = test_dac || !chip->fsm_dac_load;
    if (do_out && (chip->ch_out_pan_dlatch & 2) != 0)
        chip->out_l = chip->dac_val;
    else
        chip->out_l = 0;
    if (do_out && (chip->ch_out_pan_dlatch & 1) != 0)
        chip->out_r = chip->dac_val;
    else
        chip->out_r = 0;

    if (chip->out_l & 256)
        chip->out_l |= ~0x1ff;
    if (chip->out_r & 256)
        chip->out_r |= ~0x1ff;

    chip->ch_out_debug[1] = chip->ch_out_debug[0];
}

void FMOPN2_YMF276Accumulator1(fmopn2_t *chip)
{
    int i;
    int sum1;
    int sum2;
    int sum;
    int inp = 0;
    int accm = 0;
    int acc = 0;
    int c;
    int test_dac = (chip->mode_test_2c[1] & 32) != 0;
    int test_dac2 = (chip->mode_test_2c[1] & 8) != 0;
    int load = test_dac || chip->fsm_op1_sel;
    int acc_clear = load && !test_dac;
    int sel_dac = (chip->fsm_op1_sel_l2[1] & 16) != 0 && chip->fsm_op1_sel && chip->mode_dac_en[1];
    int sel_fm = chip->fsm_op1_sel && !sel_dac;
    int out = 0;
    int pan = 0;
    int acc_l = 0;
    int acc_r = 0;

    chip->osc_out = 0;

    for (i = 0; i < 14; i++)
        accm += ((chip->ch_accm[i][1] >> 5) & 1) << i;
    if (chip->alg_output && !test_dac)
        inp = chip->op_output[1] & 0x3fff;
    if (test_dac2)
        inp = 0x3fff;
    if (!acc_clear)
        acc = accm;

    sum1 = (acc & 31) + (inp & 31) + (test_dac && !test_dac2);
    c = ((sum1 & 32) != 0 || test_dac) && !test_dac2;
    sum2 = (acc >> 5) + (inp >> 5) + c;

    sum = ((sum2 & 511) << 5) | (sum1 & 31);

    if ((inp & 0x2000) != 0 && (acc & 0x2000) != 0 && (sum & 0x2000) == 0)
        sum = 0x2000;
    else if ((inp & 0x2000) == 0 && (acc & 0x2000) == 0 && (sum & 0x2000) != 0)
        sum = 0x1fff;

    for (i = 0; i < 14; i++)
        chip->ch_accm[i][0] = (chip->ch_accm[i][1] << 1) | ((sum >> i) & 1);

    for (i = 0; i < 9; i++)
    {
        chip->ch_out[i][0] = chip->ch_out[i][1] << 1;
        if (load)
            chip->ch_out[i][0] |= (chip->ch_accm[i+5][1] >> 5) & 1;
        else
            chip->ch_out[i][0] |= (chip->ch_out[i][1] >> 5) & 1;
    }

    chip->ch_dac_load = chip->fsm_dac_load;

    chip->ch_out_debug[0] = chip->ch_out_dlatch;

    chip->fsm_op1_sel_l2[0] = (chip->fsm_op1_sel_l2[1] << 1) | chip->fsm_op1_sel;
    chip->fsm_op1_sel_l3[0] = chip->fsm_op1_sel;

    if (sel_dac)
        chip->osc_out |= chip->mode_dac_data[1] << 6;
    if (sel_fm)
        chip->osc_out |= accm;

    if (chip->osc_out & 0x2000)
        chip->osc_out |= 0x1c000;

    for (i = 0; i < 2; i++)
        pan |= (((chip->chan_pan[i][1] >> 5) & 1) ^ 1) << i;

    chip->fsm_shifter_ctrl[0] = chip->fsm_shifter_ctrl[1] << 1;

    if (chip->fsm_op1_sel && !chip->fsm_op1_sel_l3[1])
    {
        acc_l = 0;
        acc_r = 0;
        chip->fsm_shifter_ctrl[0] |= 1;
    }
    else
    {
        acc_l = chip->ch_accm_l[1];
        acc_r = chip->ch_accm_r[1];
    }

    chip->ch_accm_l[0] = acc_l + ((pan & 2) != 0 ? chip->osc_out : 0);
    chip->ch_accm_r[0] = acc_r + ((pan & 1) != 0 ? chip->osc_out : 0);
}

void FMOPN2_YMF276Accumulator2(fmopn2_t *chip)
{
    int i;
    int test_dac = (chip->mode_test_2c[1] & 32) != 0;
    for (i = 0; i < 14; i++)
    {
        chip->ch_accm[i][1] = chip->ch_accm[i][0];
    }
    for (i = 0; i < 9; i++)
    {
        chip->ch_out[i][1] = chip->ch_out[i][0];
    }
    if ((chip->fsm_dac_load && !chip->ch_dac_load) || test_dac)
    {
        chip->ch_out_dlatch = 0;
        if (chip->fsm_dac_out_sel || test_dac)
        {
            for (i = 0; i < 9; i++)
                chip->ch_out_dlatch |= ((chip->ch_out[i][1] >> 5) & 1) << i;
        }
        else
        {
            for (i = 0; i < 9; i++)
                chip->ch_out_dlatch |= ((chip->ch_out[i][1] >> 4) & 1) << i;
        }
    }

    chip->ch_out_debug[1] = chip->ch_out_debug[0];

    chip->fsm_op1_sel_l2[1] = chip->fsm_op1_sel_l2[0];
    chip->fsm_op1_sel_l3[1] = chip->fsm_op1_sel_l3[0];
    
    chip->ch_accm_l[1] = chip->ch_accm_l[0];
    chip->ch_accm_r[1] = chip->ch_accm_r[0];

    chip->fsm_shifter_ctrl[1] = chip->fsm_shifter_ctrl[0];
}

void FMOPN2_Timers1(fmopn2_t *chip)
{
    int time;
    int test_timers = (chip->mode_test_21[1] & 4) != 0;
    int reset;
    int subcnt;
    if (chip->timer_a_load_latch[1])
        time = chip->mode_timer_a_reg[1];
    else
        time = chip->timer_a_cnt[1];

    if ((chip->timer_a_load_dlatch && chip->fsm_clock_timers1) || test_timers)
        time++;

    reset = chip->mode_timer_a_reset[1] || chip->input.ic;

    if (reset)
        chip->timer_a_status[0] = 0;
    else
        chip->timer_a_status[0] = chip->timer_a_status[1] || (chip->timer_a_of[1] && chip->mode_timer_a_enable[1]);

    chip->timer_a_load_old[0] = chip->timer_a_load_dlatch;
    chip->timer_a_load_latch[0] = (!chip->timer_a_load_old[1] && chip->timer_a_load_dlatch) || chip->timer_a_of[1];
    if (!chip->timer_a_load_dlatch)
        chip->timer_a_cnt[0] = 0;
    else
        chip->timer_a_cnt[0] = time;
    chip->timer_a_of[0] = (time & 1024) != 0;


    subcnt = chip->timer_b_subcnt[1];
    if (chip->fsm_clock_timers1)
        subcnt++;

    if (chip->input.ic)
        chip->timer_b_subcnt[0] = 0;
    else
        chip->timer_b_subcnt[0] = subcnt;

    chip->timer_b_subcnt_of[0] = (subcnt & 16) != 0;

    if (chip->timer_b_load_latch[1])
        time = chip->mode_timer_b_reg[1];
    else
        time = chip->timer_b_cnt[1];

    if ((chip->timer_b_load_dlatch && chip->timer_b_subcnt_of[1]) || test_timers)
        time++;

    reset = chip->mode_timer_b_reset[1] || chip->input.ic;

    if (reset)
        chip->timer_b_status[0] = 0;
    else
        chip->timer_b_status[0] = chip->timer_b_status[1] || (chip->timer_b_of[1] && chip->mode_timer_b_enable[1]);

    chip->timer_b_load_old[0] = chip->timer_b_load_dlatch;
    chip->timer_b_load_latch[0] = (!chip->timer_b_load_old[1] && chip->timer_b_load_dlatch) || chip->timer_b_of[1];
    if (!chip->timer_b_load_dlatch)
        chip->timer_b_cnt[0] = 0;
    else
        chip->timer_b_cnt[0] = time;
    chip->timer_b_of[0] = (time & 256) != 0;

    chip->timer_dlatch = chip->fsm_clock_timers;
}

void FMOPN2_Timers2(fmopn2_t *chip)
{
    int read_enable = chip->input.cs && chip->input.rd && !chip->input.ic;
    chip->timer_a_load_latch[1] = chip->timer_a_load_latch[0];
    chip->timer_a_load_old[1] = chip->timer_a_load_old[0];
    chip->timer_a_cnt[1] = chip->timer_a_cnt[0] & 1023;
    chip->timer_a_of[1] = chip->timer_a_of[0];
    chip->timer_a_status[1] = chip->timer_a_status[0];
    chip->timer_b_subcnt[1] = chip->timer_b_subcnt[0] & 15;
    chip->timer_b_subcnt_of[1] = chip->timer_b_subcnt_of[0];
    chip->timer_b_load_latch[1] = chip->timer_b_load_latch[0];
    chip->timer_b_load_old[1] = chip->timer_b_load_old[0];
    chip->timer_b_cnt[1] = chip->timer_b_cnt[0] & 255;
    chip->timer_b_of[1] = chip->timer_b_of[0];
    chip->timer_b_status[1] = chip->timer_b_status[0];
    if (!chip->timer_dlatch && chip->fsm_clock_timers)
    {
        chip->timer_a_load_dlatch = chip->mode_timer_a_load[1];
        chip->timer_b_load_dlatch = chip->mode_timer_b_load[1];
        chip->timer_csm_key_dlatch = chip->mode_ch3[1] == 2 && ((!chip->timer_a_load_old[1] && chip->timer_a_load_dlatch) || chip->timer_a_of[1]);
    }
    if (!read_enable)
    {
        chip->status_timer_a_dlatch = chip->timer_a_status[1];
        chip->status_timer_b_dlatch = chip->timer_b_status[1];
    }
}

void FMOPN2_ClockPhase1(fmopn2_t *chip)
{
    FMOPN2_DoShiftRegisters(chip, 0);
    FMOPN2_HandleIO1(chip);
    FMOPN2_FMRegisters1(chip);
    FMOPN2_FSM1(chip);
    FMOPN2_Misc1(chip);
    FMOPN2_LFO1(chip);
    FMOPN2_PhaseGenerator1(chip);
    FMOPN2_EnvelopeGenerator1(chip);
    FMOPN2_Operator1(chip);
    if (!(chip->flags & fmopn2_flags_ym3438))
        FMOPN2_YMF276Accumulator1(chip);
    else
        FMOPN2_YM3438Accumulator1(chip);
    FMOPN2_Timers1(chip);
}

void FMOPN2_ClockPhase2(fmopn2_t *chip)
{
    FMOPN2_DoShiftRegisters(chip, 1);
    FMOPN2_HandleIO2(chip);
    FMOPN2_FMRegisters2(chip);
    FMOPN2_FSM2(chip);
    FMOPN2_Misc2(chip);
    FMOPN2_LFO2(chip);
    FMOPN2_PhaseGenerator2(chip);
    FMOPN2_EnvelopeGenerator2(chip);
    FMOPN2_Operator2(chip);
    if (!(chip->flags & fmopn2_flags_ym3438))
        FMOPN2_YMF276Accumulator2(chip);
    else
        FMOPN2_YM3438Accumulator2(chip);
    FMOPN2_Timers2(chip);
}

void FMOPN2_ClockFM(fmopn2_t *chip)
{
    FMOPN2_HandleIO(chip);
    if (chip->i_phi1)
    {
        FMOPN2_ClockPhase1(chip);
    }
    if (chip->i_phi2)
    {
        FMOPN2_ClockPhase2(chip);
    }
}

void FMOPN2_Clock(fmopn2_t *chip, int clk)
{
    chip->pinput.phi = clk;
    if (memcmp(&chip->pinput, &chip->pinput_old, sizeof(chip->pinput)) != 0)
    {
        FMOPN2_Prescaler(chip);
        chip->pinput_old = chip->pinput;
        chip->input.i_fsm_reset = chip->fsm_reset;
        if (chip->phi1_latch[1])
            chip->input.phi_phase = 1;
        if (chip->phi2_latch[1])
            chip->input.phi_phase = 2;
        chip->i_phi1 = chip->phi1_latch[1];
        chip->i_phi2 = chip->phi2_latch[1];
    }
    if (memcmp(&chip->input, &chip->input_old, sizeof(chip->input)) != 0)
    {
        FMOPN2_ClockFM(chip);
        chip->input_old = chip->input;
    }

    if (!(chip->flags & fmopn2_flags_ym3438))
        FMOPN2_YMF276DAC(chip);
}
