* See COPYING file in the top-level directory.\r
*/\r
\r
+#include <assert.h>\r
#include "pico_int.h"\r
#include "memory.h"\r
+#include "state.h"\r
\r
#include "sound/ym2612.h"\r
#include "sound/sn76496.h"\r
//elprintf(EL_STATUS, "%03i dac w %08x z80 %i", cycles, d, is_from_z80);\r
if (ym2612.dacen)\r
PsndDoDAC(cycles);\r
- ym2612.dacout = ((int)d - 0x80) << 6;\r
+ ym2612.dacout = ((int)d - 0x80) << DAC_SHIFT;\r
return 0;\r
}\r
case 0x2b: { /* DAC Sel (YM2612) */\r
return ym2612.OPN.ST.status;\r
}\r
\r
-void ym2612_pack_state(void)\r
+int ym2612_pack_timers(void *buf, size_t size)\r
{\r
// timers are saved as tick counts, in 16.16 int format\r
int tac, tat = 0, tbc, tbt = 0, busy = 0;\r
+ size_t b = 0;\r
tac = 1024 - ym2612.OPN.ST.TA;\r
tbc = 256 - ym2612.OPN.ST.TB;\r
if (Pico.t.ym2612_busy > 0)\r
tbt = ((Pico.t.timer_b_step - Pico.t.timer_b_next_oflow) * ((1LL<<32)/TIMER_B_TICK_ZCYCLES+1))>>16;\r
elprintf(EL_YMTIMER, "save: timer a %i/%i", tat >> 16, tac);\r
elprintf(EL_YMTIMER, "save: timer b %i/%i", tbt >> 16, tbc);\r
-\r
#ifdef __GP2X__\r
if (PicoIn.opt & POPT_EXT_FM)\r
YM2612PicoStateSave2_940(tat, tbt);\r
else\r
#endif\r
- YM2612PicoStateSave2(tat, tbt, busy);\r
+ {\r
+ //YM2612PicoStateSave2(tat, tbt, busy);\r
+ assert(size >= 16);\r
+ save_u16(buf, &b, ym2612.OPN.ST.TA);\r
+ save_u16(buf, &b, ym2612.OPN.ST.TB);\r
+ save_u32(buf, &b, tat);\r
+ save_u32(buf, &b, tbt);\r
+ save_u32(buf, &b, busy);\r
+ }\r
+ return b;\r
}\r
\r
-void ym2612_unpack_state(void)\r
+void ym2612_unpack_state_old(void)\r
{\r
- int i, ret, tac, tat, tbc, tbt, busy = 0;\r
+ int i, ret, tat, tbt, busy = 0;\r
YM2612PicoStateLoad();\r
Pico.t.m68c_frame_start = SekCyclesDone();\r
\r
elprintf(EL_STATUS, "old ym2612 state");\r
return; // no saved timers\r
}\r
+ {\r
+ u8 tmp[16];\r
+ size_t b = 0;\r
+ save_u16(tmp, &b, ym2612.OPN.ST.TA);\r
+ save_u16(tmp, &b, ym2612.OPN.ST.TB);\r
+ save_u32(tmp, &b, tat);\r
+ save_u32(tmp, &b, tbt);\r
+ save_u32(tmp, &b, busy);\r
+ ym2612_unpack_timers(tmp, b);\r
+ }\r
+}\r
\r
+void ym2612_unpack_timers(const void *buf, size_t size)\r
+{\r
+ int tac, tat, tbc, tbt, busy;\r
+ size_t b = 0;\r
+ assert(size >= 16);\r
+ if (size < 16)\r
+ return;\r
+ ym2612.OPN.ST.TA = load_u16(buf, &b);\r
+ ym2612.OPN.ST.TB = load_u16(buf, &b);\r
+ tat = load_u32(buf, &b);\r
+ tbt = load_u32(buf, &b);\r
+ busy = load_u32(buf, &b);\r
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
\r
//#include <stdio.h>\r
\r
+#include <assert.h>\r
#include <string.h>\r
#include <math.h>\r
\r
#define FREQ_SH 16 /* 16.16 fixed point (frequency calculations) */\r
#define EG_SH 16 /* 16.16 fixed point (envelope generator timing) */\r
#define LFO_SH 24 /* 8.24 fixed point (LFO calculations) */\r
-#define TIMER_SH 16 /* 16.16 fixed point (timers calculations) */\r
\r
#define ENV_BITS 10\r
#define ENV_LEN (1<<ENV_BITS)\r
but LFO works with one more bit of a precision so we really need 4096 elements */\r
static UINT32 fn_table[4096]; /* fnumber->increment counter */\r
\r
-static int g_lfo_ampm;\r
-\r
/* register number to channel number , slot offset */\r
#define OPN_CHAN(N) (N&3)\r
#define OPN_SLOT(N) ((N>>2)&3)\r
static void chan_render_prep(void)\r
{\r
crct.eg_timer_add = ym2612.OPN.eg_timer_add;\r
- crct.lfo_init_sft16 = g_lfo_ampm << 16;\r
+ crct.lfo_init_sft16 = ym2612.OPN.lfo_ampm << 16;\r
crct.lfo_inc = ym2612.OPN.lfo_inc;\r
}\r
\r
\r
ym2612.OPN.ST.mode = 0; /* normal mode */\r
ym2612.OPN.ST.TA = 0;\r
- ym2612.OPN.ST.TAC = 0;\r
+ //ym2612.OPN.ST.TAC = 0;\r
ym2612.OPN.ST.TB = 0;\r
- ym2612.OPN.ST.TBC = 0;\r
+ //ym2612.OPN.ST.TBC = 0;\r
\r
for( c = 0 ; c < 6 ; c++ )\r
{\r
if (ym2612.slot_mask & 0x00f000) active_chs |= chan_render(buffer, length, 3, flags|((pan&0x0c0)>>2)) << 3;\r
BIT_IF(flags, 1, (ym2612.ssg_mask & 0x0f0000) && (ym2612.OPN.ST.flags & 1));\r
if (ym2612.slot_mask & 0x0f0000) active_chs |= chan_render(buffer, length, 4, flags|((pan&0x300)>>4)) << 4;\r
- g_lfo_ampm = crct.pack >> 16; // need_save; now because ch5 might skip updating it\r
+ ym2612.OPN.lfo_ampm = crct.pack >> 16; // need_save; now because ch5 might skip updating it\r
BIT_IF(flags, 1, (ym2612.ssg_mask & 0xf00000) && (ym2612.OPN.ST.flags & 1));\r
if (ym2612.slot_mask & 0xf00000) active_chs |= chan_render(buffer, length, 5, flags|((pan&0xc00)>>6)|(!!ym2612.dacen<<2)) << 5;\r
#undef BIT_IF\r
ym2612.OPN.eg_cnt = 0;\r
ym2612.OPN.lfo_inc = 0;\r
ym2612.OPN.lfo_cnt = 0;\r
- g_lfo_ampm = 126 << 8;\r
+ ym2612.OPN.lfo_ampm = 126 << 8;\r
ym2612.OPN.ST.status = 0;\r
\r
reset_channels( &ym2612.CH[0] );\r
{\r
ym2612.OPN.lfo_inc = 0;\r
ym2612.OPN.lfo_cnt = 0;\r
- g_lfo_ampm = 126 << 8;\r
+ ym2612.OPN.lfo_ampm = 126 << 8;\r
}\r
break;\r
#if 0 // handled elsewhere\r
break;\r
}\r
case 0x2a: /* DAC data (YM2612) */\r
- ym2612.dacout = ((int)v - 0x80) << 6; /* level unknown (notaz: 8 seems to be too much) */\r
+ ym2612.dacout = ((int)v - 0x80) << DAC_SHIFT;\r
ret=0;\r
break;\r
case 0x2b: /* DAC Sel (YM2612) */\r
}\r
\r
/* rather stupid design because I wanted to fit in unused register "space" */\r
+// TODO remove all this along with ym2612.REGS\r
typedef struct\r
{\r
UINT32 state_phase;\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
sa.eg_cnt = ym2612.OPN.eg_cnt;\r
sa.eg_timer = ym2612.OPN.eg_timer;\r
sa.lfo_cnt = ym2612.OPN.lfo_cnt;\r
- sa.lfo_ampm = g_lfo_ampm;\r
+ sa.lfo_ampm = ym2612.OPN.lfo_ampm;\r
sa.busy_timer = busy;\r
//sa.keyon_field = ym2612.slot_mask;\r
memcpy(ptr, &sa, sizeof(sa)); // 0x30 max\r
ym2612.OPN.eg_cnt = sa.eg_cnt;\r
ym2612.OPN.eg_timer = sa.eg_timer;\r
ym2612.OPN.lfo_cnt = sa.lfo_cnt;\r
- g_lfo_ampm = sa.lfo_ampm;\r
+ ym2612.OPN.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
return 0;\r
}\r
\r
+#include "../state.h"\r
+\r
+#define SLOT_SIZE_MIN 46\r
+#define CH_SIZE_MIN 16\r
+#define OTHER_SIZE_MIN 35\r
+\r
+static size_t save_slot(u8 *buf, const FM_SLOT *slot)\r
+{\r
+ size_t tmp, b = 0;\r
+\r
+ b++; // length, assumes slot state won't grow beyond 255\r
+ tmp = (slot->DT - ym2612.OPN.ST.dt_tab[0]) / sizeof(ym2612.OPN.ST.dt_tab[0]);\r
+ save_u8_(buf, &b, tmp);\r
+ save_u8_(buf, &b, slot->ar);\r
+ save_u8_(buf, &b, slot->d1r);\r
+ save_u8_(buf, &b, slot->d2r);\r
+ save_u8_(buf, &b, slot->rr);\r
+ save_u8_(buf, &b, slot->mul);\r
+ save_u32(buf, &b, slot->phase);\r
+ save_u32(buf, &b, slot->Incr);\r
+ save_u8_(buf, &b, slot->KSR);\r
+ save_u8_(buf, &b, slot->ksr);\r
+ save_u8_(buf, &b, slot->key);\r
+ save_u8_(buf, &b, slot->state);\r
+ save_u8_(buf, &b, slot->tl >> (ENV_BITS-7));\r
+ save_u16(buf, &b, slot->volume);\r
+ save_u32(buf, &b, slot->sl);\r
+ save_u32(buf, &b, slot->eg_pack_rr);\r
+ save_u32(buf, &b, slot->eg_pack_d2r);\r
+ save_u32(buf, &b, slot->eg_pack_d1r);\r
+ save_u32(buf, &b, slot->eg_pack_ar);\r
+ save_u8_(buf, &b, slot->ssg);\r
+ save_u8_(buf, &b, slot->ssgn);\r
+ save_u8_(buf, &b, slot->ar_ksr);\r
+ save_u16(buf, &b, slot->vol_out);\r
+\r
+ //printf("slot size: %zd\n", b);\r
+ assert(b >= SLOT_SIZE_MIN);\r
+ assert(b < 256u);\r
+ buf[0] = b - 1;\r
+ return b;\r
+}\r
+\r
+static void load_slot(const u8 *buf, FM_SLOT *slot)\r
+{\r
+ size_t b = 0;\r
+ u8 dt_reg;\r
+\r
+ dt_reg = load_u8_(buf, &b);\r
+ slot->ar = load_u8_(buf, &b);\r
+ slot->d1r = load_u8_(buf, &b);\r
+ slot->d2r = load_u8_(buf, &b);\r
+ slot->rr = load_u8_(buf, &b);\r
+ slot->mul = load_u8_(buf, &b);\r
+ slot->phase = load_u32(buf, &b);\r
+ slot->Incr = load_u32(buf, &b);\r
+ slot->KSR = load_u8_(buf, &b);\r
+ slot->ksr = load_u8_(buf, &b);\r
+ slot->key = load_u8_(buf, &b);\r
+ slot->state = load_u8_(buf, &b);\r
+ slot->tl = load_u8_(buf, &b) << (ENV_BITS-7);\r
+ slot->volume = load_s16(buf, &b);\r
+ slot->sl = load_u32(buf, &b);\r
+ slot->eg_pack_rr = load_u32(buf, &b);\r
+ slot->eg_pack_d2r = load_u32(buf, &b);\r
+ slot->eg_pack_d1r = load_u32(buf, &b);\r
+ slot->eg_pack_ar = load_u32(buf, &b);\r
+ slot->ssg = load_u8_(buf, &b);\r
+ slot->ssgn = load_u8_(buf, &b);\r
+ slot->ar_ksr = load_u8_(buf, &b);\r
+ slot->vol_out = load_u16(buf, &b);\r
+\r
+ assert(dt_reg < 8);\r
+ slot->DT = ym2612.OPN.ST.dt_tab[dt_reg & 7];\r
+}\r
+\r
+static size_t save_channel(u8 *buf, const FM_CH *ch)\r
+{\r
+ int i, size_pos;\r
+ size_t b = 0;\r
+\r
+ for (i = 0; i < 4; i++)\r
+ b += save_slot(&buf[b], &ch->SLOT[i]);\r
+ size_pos = b++;\r
+ save_u8_(buf, &b, ch->ALGO);\r
+ save_u8_(buf, &b, ch->FB);\r
+ save_u32(buf, &b, ch->op1_out);\r
+ save_s16(buf, &b, ch->mem_value); // fits in 16bit\r
+ save_u8_(buf, &b, ch->pms); // max 7*32\r
+ save_u8_(buf, &b, ch->ams);\r
+ save_u8_(buf, &b, ch->kcode);\r
+ save_u8_(buf, &b, ch->upd_cnt);\r
+ // ch->fc is derived from .block_fnum\r
+ save_u16(buf, &b, ch->block_fnum);\r
+ save_u8_(buf, &b, ch->AMmasks);\r
+\r
+ assert(b - size_pos - 1 < 256u);\r
+ buf[size_pos] = b - size_pos - 1;\r
+ return b;\r
+}\r
+\r
+static size_t load_channel(const u8 *buf, size_t size, FM_CH *ch)\r
+{\r
+ size_t i, b = 0, slot_size = 0, ch_size;\r
+ u32 fn, blk;\r
+\r
+ for (i = 0; i < 4; i++) {\r
+ u8 size_next = load_u8_(buf, &slot_size);\r
+ if (size_next < SLOT_SIZE_MIN)\r
+ return 0;\r
+ if (slot_size + size_next > size)\r
+ return 0;\r
+ load_slot(&buf[slot_size], &ch->SLOT[i]);\r
+ slot_size += size_next;\r
+ }\r
+ if (slot_size + CH_SIZE_MIN > size)\r
+ return 0;\r
+ b = slot_size;\r
+ ch_size = load_u8_(buf, &b);\r
+ ch->ALGO = load_u8_(buf, &b);\r
+ ch->FB = load_u8_(buf, &b);\r
+ ch->op1_out = load_u32(buf, &b);\r
+ ch->mem_value = load_s16(buf, &b);\r
+ ch->pms = load_u8_(buf, &b);\r
+ ch->ams = load_u8_(buf, &b);\r
+ ch->kcode = load_u8_(buf, &b);\r
+ ch->upd_cnt = load_u8_(buf, &b);\r
+ ch->block_fnum = load_u16(buf, &b) & 0x3fff;\r
+ ch->AMmasks = load_u8_(buf, &b);\r
+\r
+ fn = ch->block_fnum & 0x7ff;\r
+ blk = ch->block_fnum >> 11;\r
+ ch->fc = fn_table[fn*2] >> (7 - blk);\r
+\r
+ assert(ch_size >= b - slot_size - 1);\r
+ return slot_size + 1 + ch_size;\r
+}\r
+\r
+size_t YM2612PicoStateSave3(void *buf_, size_t size)\r
+{\r
+ size_t i, b = 0;\r
+ u8 *buf = buf_;\r
+ u8 lfo_inc_reg = 0;\r
+\r
+ for (i = 0; i < 8; i++) {\r
+ if (ym2612.OPN.lfo_inc == ym2612.OPN.lfo_freq[i]) {\r
+ lfo_inc_reg = i + 1;\r
+ break;\r
+ }\r
+ }\r
+ assert(ym2612.OPN.lfo_inc == 0 || i < 8);\r
+\r
+ for (i = 0; i < 6; i++)\r
+ b += save_channel(&buf[b], &ym2612.CH[i]);\r
+ save_u8_(buf, &b, ym2612.OPN.ST.address);\r
+ save_u8_(buf, &b, ym2612.OPN.ST.status);\r
+ save_u8_(buf, &b, ym2612.OPN.ST.mode);\r
+ save_u8_(buf, &b, ym2612.OPN.ST.flags);\r
+ // (timers are saved in CHUNK_FM_TIMERS)\r
+ save_u8_(buf, &b, ym2612.OPN.ST.fn_h);\r
+ save_u8_(buf, &b, ym2612.OPN.SL3.fn_h);\r
+ for (i = 0; i < 3; i++) {\r
+ // ym2612.OPN.SL3.fc is derived from .block_fnum\r
+ save_u8_(buf, &b, ym2612.OPN.SL3.kcode[i]);\r
+ save_u16(buf, &b, ym2612.OPN.SL3.block_fnum[i]);\r
+ }\r
+ save_u16(buf, &b, ym2612.OPN.pan);\r
+ save_u16(buf, &b, ym2612.OPN.eg_cnt);\r
+ save_u16(buf, &b, ym2612.OPN.eg_timer);\r
+ save_u32(buf, &b, ym2612.OPN.lfo_cnt);\r
+ save_u16(buf, &b, ym2612.OPN.lfo_ampm);\r
+ save_u8_(buf, &b, lfo_inc_reg);\r
+ save_u8_(buf, &b, ym2612.addr_A1);\r
+ save_u8_(buf, &b, ym2612.dacen);\r
+ save_s8_(buf, &b, ym2612.dacout >> DAC_SHIFT);\r
+ save_u32(buf, &b, ym2612.ssg_mask);\r
+\r
+ //printf("ym2612 state size: %zu\n", b);\r
+ assert(b <= size);\r
+ return b;\r
+}\r
+\r
+void YM2612PicoStateLoad3(const void *buf_, size_t size)\r
+{\r
+ const u8 *buf = buf_;\r
+ size_t i, b = 0;\r
+ u8 lfo_inc_reg = 0;\r
+\r
+ for (i = 0; i < 6; i++) {\r
+ size_t r = load_channel(&buf[b], size - b, &ym2612.CH[i]);\r
+ if (!r)\r
+ goto broken;\r
+ b += r;\r
+ }\r
+ if (b + OTHER_SIZE_MIN > size)\r
+ goto broken;\r
+ ym2612.OPN.ST.address = load_u8_(buf, &b);\r
+ ym2612.OPN.ST.status = load_u8_(buf, &b);\r
+ ym2612.OPN.ST.mode = load_u8_(buf, &b);\r
+ ym2612.OPN.ST.flags = load_u8_(buf, &b);\r
+ ym2612.OPN.ST.fn_h = load_u8_(buf, &b);\r
+ ym2612.OPN.SL3.fn_h = load_u8_(buf, &b);\r
+ for (i = 0; i < 3; i++) {\r
+ u32 fn, blk;\r
+ ym2612.OPN.SL3.kcode[i] = load_u8_(buf, &b);\r
+ ym2612.OPN.SL3.block_fnum[i] = load_u16(buf, &b) & 0x3fff;\r
+\r
+ fn = ym2612.OPN.SL3.block_fnum[i] & 0x7ff;\r
+ blk = ym2612.OPN.SL3.block_fnum[i] >> 11;\r
+ ym2612.OPN.SL3.fc[i] = fn_table[fn*2] >> (7 - blk);\r
+ }\r
+ ym2612.OPN.pan = load_u16(buf, &b);\r
+ ym2612.OPN.eg_cnt = load_u16(buf, &b);\r
+ ym2612.OPN.eg_timer = load_u16(buf, &b);\r
+ ym2612.OPN.lfo_cnt = load_u32(buf, &b);\r
+ ym2612.OPN.lfo_ampm = load_u16(buf, &b);\r
+ lfo_inc_reg = load_u8_(buf, &b);\r
+ ym2612.addr_A1 = load_u8_(buf, &b);\r
+ ym2612.dacen = load_u8_(buf, &b);\r
+ ym2612.dacout = load_s8_(buf, &b);\r
+ ym2612.ssg_mask = load_u32(buf, &b);\r
+\r
+ assert(lfo_inc_reg < 9u);\r
+ ym2612.OPN.lfo_inc = 0;\r
+ if (lfo_inc_reg)\r
+ ym2612.OPN.lfo_inc = ym2612.OPN.lfo_freq[--lfo_inc_reg & 7];\r
+ ym2612.dacout = (u32)ym2612.dacout << DAC_SHIFT;\r
+ ym2612.slot_mask = 0xffffff;\r
+ //printf("ym2612 state size: %zu\n", b);\r
+ return;\r
+broken:\r
+ elprintf(EL_STATUS, "broken ym2612 state");\r
+}\r
+\r
void *YM2612GetRegs(void)\r
{\r
return ym2612.REGS;\r