diff --git a/extern/YM3812-LLE/Readme.md b/extern/YM3812-LLE/Readme.md index 38aa0debb..77dde824a 100644 --- a/extern/YM3812-LLE/Readme.md +++ b/extern/YM3812-LLE/Readme.md @@ -8,6 +8,6 @@ https://twitter.com/travisgoodspeed/status/1652334901230723072 # MODIFICATION DISCLAIMER -this is a modified version of YM3812-LLE which adds functions to allow its usage. +this is a modified version of YM3812-LLE which adds functions to allow its usage and per-chan osc. the original Git commit is 7f0c6537ccd61e9e7dbddb4e4a353e007ea69c50. diff --git a/extern/YMF262-LLE/Readme.md b/extern/YMF262-LLE/Readme.md index f9cf1b581..14a7126d4 100644 --- a/extern/YMF262-LLE/Readme.md +++ b/extern/YMF262-LLE/Readme.md @@ -8,6 +8,7 @@ https://siliconpr0n.org/map/yamaha/ymf262-m/ # MODIFICATION DISCLAIMER -this is a modified version of YMF262-LLE which adds functions to allow its usage. +this is a modified version of YMF262-LLE which adds functions to allow its usage and per-chan osc. +it also brings in a small optimization. the original Git commit is 63406354d05bc860a6762377ddbb9e2609bd6c36. diff --git a/extern/YMF276-LLE/LICENSE b/extern/YMF276-LLE/LICENSE new file mode 100644 index 000000000..89e08fb00 --- /dev/null +++ b/extern/YMF276-LLE/LICENSE @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + 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. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. diff --git a/extern/YMF276-LLE/Readme.md b/extern/YMF276-LLE/Readme.md new file mode 100644 index 000000000..e9ccb6cf1 --- /dev/null +++ b/extern/YMF276-LLE/Readme.md @@ -0,0 +1,15 @@ +# YMF276-LLE + +Yamaha YMF276/YM3438 (OPN2) emulator using YM3438 and YMF276 die shots. + +Special thanks to John McMaster for decapping YM3438 and org(ogamespec) for decapping YMF276. + +https://siliconpr0n.org/map/yamaha/ym3438/ + +https://drive.google.com/drive/u/0/folders/10IOhV4wf4A6SLQkS-i1wyJnyXH5o8DKn + +# MODIFICATION DISCLAIMER + +this is a modified version of YMF276-LLE which adds functions for per-chan osc. + +the original Git commit is 172b3a40011d0d89528a7fc0d606cc92d94cd033. diff --git a/extern/YMF276-LLE/fmopn2.c b/extern/YMF276-LLE/fmopn2.c new file mode 100644 index 000000000..2a11366c1 --- /dev/null +++ b/extern/YMF276-LLE/fmopn2.c @@ -0,0 +1,2342 @@ +/* + * 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 +#include + +#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]; + } + if (chip->alg_mod_prev_1) + { + mod1 |= chip->op_output[1]; + } + 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; + + 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) + out |= chip->mode_dac_data[1] << 6; + if (sel_fm) + out |= accm; + + if (out & 0x2000) + 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 ? out : 0); + chip->ch_accm_r[0] = acc_r + ((pan & 1) != 0 ? 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); +} diff --git a/extern/YMF276-LLE/fmopn2.h b/extern/YMF276-LLE/fmopn2.h new file mode 100644 index 000000000..f1ba12839 --- /dev/null +++ b/extern/YMF276-LLE/fmopn2.h @@ -0,0 +1,362 @@ +/* + * 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. + * + */ + +#pragma once +#include + +enum { + fmopn2_flags_ym3438 = 1, +}; + +typedef struct { + int phi; + int ic; +} fmopn2_prescaler_input_t; + +typedef struct { + int phi_phase; + int ic; + int rd; + int wr; + int cs; + int address; + int data; + int test; + int i_fsm_reset; // (chip->ic_check_latch[1] & 16) != 0; +} fmopn2_input_t; + +typedef struct { + int flags; + // input + fmopn2_input_t input_old, input; + int i_phi1; + int i_phi2; + + fmopn2_prescaler_input_t pinput, pinput_old; + + // clock + int ic_latch[2]; // 12 + int ic_check_latch[2]; // 4 + int prescaler_latch[2]; // 6 + int phi1_latch[2]; + int phi2_latch[2]; + int dphi1_latch[4]; + int dphi2_latch[3]; + int dclk1; + int dclk2; + int fsm_reset; + + // output + int dac_val; + int out_l; + int out_r; + + // io + int write_addr_trig; + int write_addr_trig_sync; + int write_addr_dlatch; + int write_addr_sr[2]; + int write_data_trig; + int write_data_trig_sync; + int write_data_dlatch; + int write_data_sr[2]; + + int data_latch; + int bank_latch; + + int busy_cnt[2]; + int busy_latch[2]; + + int io_ic_latch[2]; + + int write_fm_address[2]; + int fm_address[2]; + int write_fm_data[2]; + int fm_data[2]; + int status_timer_a_dlatch; + int status_timer_b_dlatch; + + // mode registers + int write_mode_21[2]; + int write_mode_22[2]; + int write_mode_24[2]; + int write_mode_25[2]; + int write_mode_26[2]; + int write_mode_27[2]; + int write_mode_28[2]; + int write_mode_2a[2]; + int write_mode_2b[2]; + int write_mode_2c[2]; + + int mode_test_21[2]; + int mode_lfo_en[2]; + int mode_lfo_freq[2]; + int mode_timer_a_reg[2]; + int mode_timer_b_reg[2]; + int mode_ch3[2]; + int mode_timer_a_load[2]; + int mode_timer_a_enable[2]; + int mode_timer_a_reset[2]; + int mode_timer_b_load[2]; + int mode_timer_b_enable[2]; + int mode_timer_b_reset[2]; + int mode_kon_operator[2]; + int mode_kon_channel[2]; + int mode_dac_data[2]; + int mode_dac_en[2]; + int mode_test_2c[2]; + + int mode_kon[4][2]; + + // operator registers + int slot_multi[2][4][2]; + int slot_dt[2][3][2]; + int slot_tl[2][7][2]; + int slot_ar[2][5][2]; + int slot_ks[2][2][2]; + int slot_dr[2][5][2]; + int slot_am[2][1][2]; + int slot_sr[2][5][2]; + int slot_rr[2][4][2]; + int slot_sl[2][4][2]; + int slot_ssg_eg[2][4][2]; + // channel registers + int chan_fnum[11][2]; + int chan_fnum_ch3[11][2]; + int chan_block[3][2]; + int chan_block_ch3[3][2]; + int chan_a4[2]; + int chan_ac[2]; + int chan_connect[3][2]; + int chan_fb[3][2]; + int chan_pms[3][2]; + int chan_ams[2][2]; + int chan_pan[2][2]; + + int reg_cnt1[2]; + int reg_cnt2[2]; + + // lfo + + int lfo_cnt1[2]; + int lfo_cnt2[2]; + + int lfo_dlatch; + int lfo_dlatch_load; + int lfo_inc_latch[2]; + + // pg + int pg_fnum[2][2]; + int pg_kcode[2][2]; + int pg_fnum_lfo1; + int pg_fnum_lfo2; + int pg_lfo_shift; + int pg_lfo_sign; + int pg_lfo; + int pg_freq1; + int pg_freq2; + int pg_freq3; + int pg_freq4; + int pg_freq5[2]; + int pg_freq6; + int pg_freq_m1; + int pg_block; + int pg_dt[2]; + int pg_detune[2]; + int pg_multi[2][2]; + int pg_multi2; + int pg_inc[2]; + int pg_inc_mask[2]; + int pg_phase[20][2]; + int pg_reset_latch[2]; + int pg_debug[2]; + int pg_reset[2]; + + // eg + int eg_prescaler[2]; + int eg_prescaler_clock_l[2]; + int eg_prescaler_l; + int eg_clock_delay[2]; + int eg_step[2]; + int eg_timer_load; + int eg_timer[2]; + int eg_timer_carry[2]; + int eg_timer_mask[2]; + int eg_timer_masked[2]; + int eg_timer_low_lock; + int eg_shift_lock; + int eg_level[10][2]; + int eg_level_latch[2]; + int eg_level_latch_inv; + int eg_state[2][2]; + int eg_ssg_dir[2]; + int eg_ssg_inv[2]; + int eg_ssg_holdup[2]; + int eg_ssg_enable[2]; + int eg_ssg_pgreset[2]; + int eg_ssg_pgrepeat[2]; + int eg_key[2]; + int eg_rate_nonzero[2]; + int eg_rate; + int eg_ksv; + int eg_rate2; + int eg_inc1; + int eg_inc2; + int eg_rate12; + int eg_rate13; + int eg_rate14; + int eg_rate15; + int eg_maxrate[2]; + int eg_incsh0; + int eg_incsh1; + int eg_incsh2; + int eg_incsh3; + int eg_incsh_nonzero[2]; + int eg_inc_total; + int eg_level_ssg[2]; + int eg_sl[2][2]; + int eg_nextlevel[2]; + int eg_kon_csm[2]; + int eg_kon_latch[2]; + int eg_tl[2][2]; + int eg_ams; + int eg_lfo[2]; + int eg_ch3_latch[2]; + int eg_out; + int eg_out_tl; + int eg_out_total; + int eg_debug[2]; + + // op + int op_mod[10][2]; + int op_phase[2]; + int op_logsin_base[2]; + int op_logsin_delta[2]; + int op_logsin_add_delta[2]; + int op_atten[2]; + int op_env[2]; + int op_pow_base[2]; + int op_pow_delta[2]; + int op_pow_add_delta[2]; + int op_shift[2]; + int op_sign[2]; + int op_output[2]; + int op_op1[2][14][2]; + int op_op2[14][2]; + int op_mod_sum[2]; + int op_dofeedback[2]; + + // accumulator + + int ch_accm[14][2]; + int ch_out[9][2]; + int ch_out_dlatch; + int ch_out_pan_dlatch; + int ch_dac_load; + int ch_out_debug[2]; + int ch_accm_l[2]; + int ch_accm_r[2]; + + // timers + int timer_dlatch; + int timer_a_cnt[2]; + int timer_a_load_latch[2]; + int timer_a_load_old[2]; + int timer_a_load_dlatch; + int timer_a_of[2]; + int timer_a_status[2]; + int timer_b_subcnt[2]; + int timer_b_subcnt_of[2]; + int timer_b_cnt[2]; + int timer_b_load_latch[2]; + int timer_b_load_old[2]; + int timer_b_load_dlatch; + int timer_b_of[2]; + int timer_b_status[2]; + int timer_csm_key_dlatch; + + // fm algorithm + int alg_mod_op1_0; + int alg_mod_op1_1; + int alg_mod_op2; + int alg_mod_prev_0; + int alg_mod_prev_1; + int alg_output; + int alg_mod_op1_0_l; + int alg_mod_op1_1_l; + int alg_mod_op2_l; + int alg_mod_prev_0_l; + int alg_mod_prev_1_l; + int alg_output_l; + + // fsm + int fsm_cnt1[2]; + int fsm_cnt2[2]; + // fsm table output + int fsm_clock_eg; + int fsm_clock_timers1; + int fsm_clock_timers; + int fsm_op4_sel; + int fsm_op1_sel; + int fsm_op2_sel; + int fsm_op3_sel; + int fsm_sel2; + int fsm_sel23; + int fsm_ch3_sel; + int fsm_dac_load; + int fsm_dac_out_sel; + int fsm_dac_ch6; + + // ymf276 + int fsm_clock_eg_l; + int fsm_op1_sel_l; + int fsm_sel1_l; + int fsm_sel2_l; + int fsm_sel23_l; + int fsm_ch3_sel_l; + int fsm_dac_load_l; + int fsm_dac_out_sel_l; + int fsm_dac_ch6_l; + int fsm_lro_l[2]; + int fsm_wco_l[2]; + int fsm_lro_l2[2]; + int fsm_wco_l2[2]; + int fsm_op1_sel_l2[2]; + int fsm_op1_sel_l3[2]; + int fsm_shifter_ctrl[2]; + int fsm_load_l; + int fsm_load_r; + + int dac_shifter[2]; + int dac_so_l[2]; + int o_bco; + int o_wco; + int o_lro; + int o_so; +} fmopn2_t; + + +int FMOPN2_ReadStatus(fmopn2_t *chip); + +void FMOPN2_Clock(fmopn2_t *chip, int phi); diff --git a/src/gui/about.cpp b/src/gui/about.cpp index d664e9a1e..c667e1ec0 100644 --- a/src/gui/about.cpp +++ b/src/gui/about.cpp @@ -179,7 +179,7 @@ const char* aboutLine[]={ "backward-cpp by Google", "adpcm by superctr", "Nuked-OPL3/OPLL/OPM/OPN2/PSG by nukeykt", - "YM3812-LLE and YMF262-LLE by nukeykt", + "YM3812-LLE, YMF262-LLE and YMF276-LLE by nukeykt", "ymfm by Aaron Giles", "MAME SN76496 by Nicola Salmoria", "MAME AY-3-8910 by Couriersud", diff --git a/src/main.cpp b/src/main.cpp index e32f747d7..b3b9f3b04 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -217,6 +217,7 @@ TAParamResult pVersion(String) { printf("- Nuked-PSG (modified version) by nukeykt (GPLv2)\n"); printf("- YM3812-LLE by nukeykt (GPLv2)\n"); printf("- YMF262-LLE by nukeykt (GPLv2)\n"); + printf("- YMF276-LLE by nukeykt (GPLv2)\n"); printf("- ymfm by Aaron Giles (BSD 3-clause)\n"); printf("- adpcm by superctr (public domain)\n"); printf("- MAME SN76496 emulation core by Nicola Salmoria (BSD 3-clause)\n");