core, fix ym2612 save state
authorkub <derkub@gmail.com>
Thu, 6 Mar 2025 19:15:08 +0000 (20:15 +0100)
committerkub <derkub@gmail.com>
Fri, 7 Mar 2025 08:22:45 +0000 (09:22 +0100)
pico/memory.c
pico/sound/ym2612.c

index e59c1e4..4ed955c 100644 (file)
@@ -1401,6 +1401,7 @@ void ym2612_unpack_state(void)
 {\r
   int i, ret, tac, tat, tbc, tbt, busy = 0;\r
   YM2612PicoStateLoad();\r
+  Pico.t.m68c_frame_start = SekCyclesDone();\r
 \r
   // feed all the registers and update internal state\r
   for (i = 0x20; i < 0xA0; i++) {\r
@@ -1438,8 +1439,6 @@ void ym2612_unpack_state(void)
   Pico.t.ym2612_busy = cycles_68k_to_z80(busy);\r
   tac = (1024 - ym2612.OPN.ST.TA) << 16;\r
   tbc = (256  - ym2612.OPN.ST.TB) << 16;\r
-  Pico.t.timer_a_step = TIMER_A_TICK_ZCYCLES * (tac>>16);\r
-  Pico.t.timer_b_step = TIMER_B_TICK_ZCYCLES * (tbc>>16);\r
   if (ym2612.OPN.ST.mode & 1)\r
     Pico.t.timer_a_next_oflow = (1LL * (tac-tat) * TIMER_A_TICK_ZCYCLES)>>16;\r
   else\r
index ee84da2..efa2c10 100644 (file)
@@ -912,7 +912,7 @@ typedef struct
        UINT32 eg_timer;\r
        UINT32 eg_timer_add;\r
        UINT32 pack;     // 4c: stereo, lastchan, disabled, lfo_enabled | pan_r, pan_l, ams[2] | AMmasks[4] | FB[4] | lfo_ampm[16]\r
-       UINT32 algo;     /* 50: algo[3], was_update, unsued, upd_cnt[2], dac */\r
+       UINT32 algo;     /* 50: algo[3], was_update, unused, upd_cnt[2], dac */\r
        INT32  op1_out;\r
 #ifdef _MIPS_ARCH_ALLEGREX\r
        UINT32 pad1[3+8];\r
@@ -2033,7 +2033,7 @@ void YM2612PicoStateLoad_(void)
 typedef struct\r
 {\r
        UINT32  state_phase;\r
-       INT16   volume;\r
+       INT16   ssg_volume;\r
 } ym_save_addon_slot;\r
 \r
 typedef struct\r
@@ -2042,37 +2042,39 @@ typedef struct
        UINT8   address;\r
        UINT8   status;\r
        UINT8   addr_A1;\r
-       UINT8   unused;\r
-       int     TAT;\r
-       int     TBT;\r
+       UINT8   version;\r
+       INT32   TAT;\r
+       INT32   TBT;\r
        UINT32  eg_cnt;         // 10\r
        UINT32  eg_timer;\r
        UINT32  lfo_cnt;\r
        UINT16  lfo_ampm;\r
        INT16   busy_timer;\r
        UINT32  keyon_field;    // 20\r
-       UINT32  kcode_fc_sl3_3;\r
-       UINT32  reserved[2];\r
+       INT16   mem_value[6];\r
 } ym_save_addon;\r
 \r
 typedef struct\r
 {\r
-       UINT16  block_fnum[6];\r
-       UINT16  block_fnum_sl3[3];\r
-       UINT16  reserved[7];\r
+       UINT16  op1_out_l[6];\r
+       UINT16  unused_sl3[3];\r
+       UINT16  op1_out_h[6];\r
+       UINT16  fn_h;\r
 } ym_save_addon2;\r
+#define _block_fnum op1_out_l\r
+#define _block_fnum_sl3 unused_sl3\r
 \r
 \r
 void YM2612PicoStateSave2(int tat, int tbt, int busy)\r
 {\r
        ym_save_addon_slot ss;\r
-       ym_save_addon2 sa2;\r
-       ym_save_addon sa;\r
+       ym_save_addon2 sa2 = { 0 };\r
+       ym_save_addon sa = { 0 };\r
        unsigned char *ptr;\r
        int c, s;\r
 \r
-       memset(&sa, 0, sizeof(sa));\r
-       memset(&sa2, 0, sizeof(sa2));\r
+       sa.magic = 0x41534d59; // 'YMSA'\r
+       sa.version = 1;\r
 \r
        // chans 1,2,3\r
        ptr = &ym2612.REGS[0x0b8];\r
@@ -2080,13 +2082,25 @@ void YM2612PicoStateSave2(int tat, int tbt, int busy)
        {\r
                for (s = 0; s < 4; s++) {\r
                        ss.state_phase = (ym2612.CH[c].SLOT[s].state << 29) | (ym2612.CH[c].SLOT[s].phase >> 3);\r
-                       ss.volume = ym2612.CH[c].SLOT[s].volume;\r
+                       ss.ssg_volume = (ym2612.CH[c].SLOT[s].volume & 0x7ff);\r
+                       if (sa.version)\r
+                               ss.ssg_volume |= (ym2612.CH[c].SLOT[s].ssg << 11) | (ym2612.CH[c].SLOT[s].ssgn << 13);\r
                        if (ym2612.CH[c].SLOT[s].key)\r
                                sa.keyon_field |= 1 << (c*4 + s);\r
                        memcpy(ptr, &ss, 6);\r
                        ptr += 6;\r
                }\r
-               sa2.block_fnum[c] = ym2612.CH[c].block_fnum;\r
+               if (sa.version) {\r
+                       sa2.op1_out_h[c] = ym2612.CH[c].op1_out >> 16;\r
+                       sa2.op1_out_l[c] = ym2612.CH[c].op1_out;\r
+                       sa.mem_value[c] = ym2612.CH[c].mem_value;\r
+               } else {\r
+                       sa2._block_fnum[c] = ym2612.CH[c].block_fnum;\r
+                       sa2._block_fnum_sl3[c] = ym2612.OPN.SL3.block_fnum[c];\r
+               }\r
+               ym2612.REGS[0x63 + 4*c] = ym2612.CH[c].upd_cnt;\r
+               ym2612.REGS[0x43 + 4*c] = ym2612.CH[c].block_fnum >> 8;\r
+               ym2612.REGS[0x33 + 4*c] = ym2612.OPN.SL3.block_fnum[c] >> 8;\r
        }\r
        // chans 4,5,6\r
        ptr = &ym2612.REGS[0x1b8];\r
@@ -2094,24 +2108,30 @@ void YM2612PicoStateSave2(int tat, int tbt, int busy)
        {\r
                for (s = 0; s < 4; s++) {\r
                        ss.state_phase = (ym2612.CH[c].SLOT[s].state << 29) | (ym2612.CH[c].SLOT[s].phase >> 3);\r
-                       ss.volume = ym2612.CH[c].SLOT[s].volume;\r
+                       ss.ssg_volume = (ym2612.CH[c].SLOT[s].volume & 0x7ff);\r
+                       if (sa.version)\r
+                               ss.ssg_volume |= (ym2612.CH[c].SLOT[s].ssg << 11) | (ym2612.CH[c].SLOT[s].ssgn << 13);\r
                        if (ym2612.CH[c].SLOT[s].key)\r
                                sa.keyon_field |= 1 << (c*4 + s);\r
                        memcpy(ptr, &ss, 6);\r
                        ptr += 6;\r
                }\r
-               sa2.block_fnum[c] = ym2612.CH[c].block_fnum;\r
-       }\r
-       for (c = 0; c < 3; c++)\r
-       {\r
-               sa2.block_fnum_sl3[c] = ym2612.OPN.SL3.block_fnum[c];\r
+               if (sa.version) {\r
+                       sa2.op1_out_h[c] = ym2612.CH[c].op1_out >> 16;\r
+                       sa2.op1_out_l[c] = ym2612.CH[c].op1_out;\r
+                       sa.mem_value[c] = ym2612.CH[c].mem_value;\r
+               } else {\r
+                       sa2._block_fnum[c] = ym2612.CH[c].block_fnum;\r
+               }\r
+               ym2612.REGS[0x63 + 4*c] = ym2612.CH[c].upd_cnt;\r
+               ym2612.REGS[0x43 + 4*c] = ym2612.CH[c].block_fnum >> 8;\r
        }\r
+       sa2.fn_h = ym2612.OPN.ST.fn_h | (ym2612.OPN.SL3.fn_h<<8);\r
 \r
        memcpy(&ym2612.REGS[0], &sa2, sizeof(sa2)); // 0x20 max\r
 \r
        // other things\r
        ptr = &ym2612.REGS[0x100];\r
-       sa.magic = 0x41534d59; // 'YMSA'\r
        sa.address = ym2612.OPN.ST.address;\r
        sa.status  = ym2612.OPN.ST.status;\r
        sa.addr_A1 = ym2612.addr_A1;\r
@@ -2122,6 +2142,7 @@ void YM2612PicoStateSave2(int tat, int tbt, int busy)
        sa.lfo_cnt  = ym2612.OPN.lfo_cnt;\r
        sa.lfo_ampm = g_lfo_ampm;\r
        sa.busy_timer = busy;\r
+       //sa.keyon_field = ym2612.slot_mask;\r
        memcpy(ptr, &sa, sizeof(sa)); // 0x30 max\r
 }\r
 \r
@@ -2131,9 +2152,8 @@ int YM2612PicoStateLoad2(int *tat, int *tbt, int *busy)
        ym_save_addon2 sa2;\r
        ym_save_addon sa;\r
        unsigned char *ptr;\r
-       UINT32 fn;\r
-       UINT8 blk;\r
        int c, s;\r
+       UINT8 fn_h, fn_h_sl3;\r
 \r
        ptr = &ym2612.REGS[0x100];\r
        memcpy(&sa, ptr, sizeof(sa)); // 0x30 max\r
@@ -2149,30 +2169,44 @@ int YM2612PicoStateLoad2(int *tat, int *tbt, int *busy)
        ym2612.OPN.eg_timer = sa.eg_timer;\r
        ym2612.OPN.lfo_cnt = sa.lfo_cnt;\r
        g_lfo_ampm = sa.lfo_ampm;\r
+       ym2612.slot_mask = sa.keyon_field;\r
        if (tat != NULL) *tat = sa.TAT;\r
        if (tbt != NULL) *tbt = sa.TBT;\r
        if (busy != NULL) *busy = sa.busy_timer;\r
 \r
+       fn_h = ym2612.OPN.ST.fn_h;\r
+       fn_h_sl3 = ym2612.OPN.SL3.fn_h;\r
+\r
        // chans 1,2,3\r
        ptr = &ym2612.REGS[0x0b8];\r
        for (c = 0; c < 3; c++)\r
        {\r
                for (s = 0; s < 4; s++) {\r
                        memcpy(&ss, ptr, 6);\r
-                       ym2612.CH[c].SLOT[s].state = ss.state_phase >> 29;\r
+                       ym2612.CH[c].SLOT[s].state = (ss.state_phase >> 29) & 7;\r
                        ym2612.CH[c].SLOT[s].phase = ss.state_phase << 3;\r
-                       ym2612.CH[c].SLOT[s].volume = ss.volume;\r
+                       ym2612.CH[c].SLOT[s].volume = ss.ssg_volume & 0x7ff;\r
+                       ym2612.CH[c].SLOT[s].ssg = (ss.ssg_volume >> 11) & 0xf;\r
+                       ym2612.CH[c].SLOT[s].ssgn = (ss.ssg_volume >> 13) & 0x4;\r
                        ym2612.CH[c].SLOT[s].key = (sa.keyon_field & (1 << (c*4 + s))) ? 1 : 0;\r
                        ym2612.CH[c].SLOT[s].ksr = (UINT8)-1;\r
+                       recalc_volout( &ym2612.CH[c].SLOT[s] );\r
                        ptr += 6;\r
                }\r
                ym2612.CH[c].SLOT[SLOT1].Incr=-1;\r
-               ym2612.CH[c].block_fnum = sa2.block_fnum[c];\r
-               fn = ym2612.CH[c].block_fnum & 0x7ff;\r
-               blk = ym2612.CH[c].block_fnum >> 11;\r
-               ym2612.CH[c].kcode= (blk<<2) | opn_fktable[fn >> 7];\r
-               ym2612.CH[c].fc = fn_table[fn*2]>>(7-blk);\r
-               refresh_fc_eg_chan( &ym2612.CH[c] );\r
+               if (sa.version) {\r
+                       ym2612.CH[c].op1_out = (sa2.op1_out_h[c] << 16) | sa2.op1_out_l[c];\r
+                       ym2612.CH[c].mem_value = sa.mem_value[c];\r
+                       ym2612.CH[c].upd_cnt = ym2612.REGS[0x63 + 4*c] & 3;\r
+                       ym2612.OPN.ST.fn_h = ym2612.REGS[0x43 + 4*c] & 0x3f;\r
+                       ym2612.OPN.SL3.fn_h = ym2612.REGS[0x33 + 4*c] & 0x3f;\r
+               } else {\r
+                       ym2612.OPN.ST.fn_h = sa2._block_fnum[c] >> 8;\r
+                       ym2612.OPN.SL3.fn_h = sa2._block_fnum_sl3[c] >> 8;\r
+               }\r
+\r
+               OPNWriteReg(0xa0 + (c&3), ym2612.REGS[0xa0 + (c&3)]);\r
+               OPNWriteReg(0xa8 + (c&3), ym2612.REGS[0xa8 + (c&3)]);\r
        }\r
        // chans 4,5,6\r
        ptr = &ym2612.REGS[0x1b8];\r
@@ -2180,28 +2214,34 @@ int YM2612PicoStateLoad2(int *tat, int *tbt, int *busy)
        {\r
                for (s = 0; s < 4; s++) {\r
                        memcpy(&ss, ptr, 6);\r
-                       ym2612.CH[c].SLOT[s].state = ss.state_phase >> 29;\r
+                       ym2612.CH[c].SLOT[s].state = (ss.state_phase >> 29) & 7;\r
                        ym2612.CH[c].SLOT[s].phase = ss.state_phase << 3;\r
-                       ym2612.CH[c].SLOT[s].volume = ss.volume;\r
+                       ym2612.CH[c].SLOT[s].volume = ss.ssg_volume & 0x7ff;\r
+                       ym2612.CH[c].SLOT[s].ssg = (ss.ssg_volume >> 11) & 0xf;\r
+                       ym2612.CH[c].SLOT[s].ssgn = (ss.ssg_volume >> 13) & 0x4;\r
                        ym2612.CH[c].SLOT[s].key = (sa.keyon_field & (1 << (c*4 + s))) ? 1 : 0;\r
                        ym2612.CH[c].SLOT[s].ksr = (UINT8)-1;\r
+                       recalc_volout( &ym2612.CH[c].SLOT[s] );\r
                        ptr += 6;\r
                }\r
                ym2612.CH[c].SLOT[SLOT1].Incr=-1;\r
-               ym2612.CH[c].block_fnum = sa2.block_fnum[c];\r
-               fn = ym2612.CH[c].block_fnum & 0x7ff;\r
-               blk = ym2612.CH[c].block_fnum >> 11;\r
-               ym2612.CH[c].kcode= (blk<<2) | opn_fktable[fn >> 7];\r
-               ym2612.CH[c].fc = fn_table[fn*2]>>(7-blk);\r
-               refresh_fc_eg_chan( &ym2612.CH[c] );\r
+               if (sa.version) {\r
+                       ym2612.CH[c].op1_out = (sa2.op1_out_h[c] << 16) | sa2.op1_out_l[c];\r
+                       ym2612.CH[c].mem_value = sa.mem_value[c];\r
+                       ym2612.CH[c].upd_cnt = ym2612.REGS[0x63 + 4*c] & 3;\r
+                       ym2612.OPN.ST.fn_h = ym2612.REGS[0x43 + 4*c] & 0x3f;\r
+               } else {\r
+                       ym2612.OPN.ST.fn_h = sa2._block_fnum[c] >> 8;\r
+               }\r
+\r
+               OPNWriteReg(0x1a0 + ((c-3)&3), ym2612.REGS[0x1a0 + ((c-3)&3)]);\r
        }\r
-       for (c = 0; c < 3; c++)\r
-       {\r
-               ym2612.OPN.SL3.block_fnum[c] = sa2.block_fnum_sl3[c];\r
-               fn = ym2612.OPN.SL3.block_fnum[c] & 0x7ff;\r
-               blk = ym2612.OPN.SL3.block_fnum[c] >> 11;\r
-               ym2612.OPN.SL3.kcode[c]= (blk<<2) | opn_fktable[fn >> 7];\r
-               ym2612.OPN.SL3.fc[c] = fn_table[fn*2]>>(7-blk);\r
+       if (sa.version) {\r
+               ym2612.OPN.ST.fn_h = sa2.fn_h;\r
+               ym2612.OPN.SL3.fn_h = sa2.fn_h >> 8;\r
+       } else {\r
+               ym2612.OPN.ST.fn_h = fn_h;\r
+               ym2612.OPN.SL3.fn_h = fn_h_sl3;\r
        }\r
 \r
        return 0;\r