From patchwork Wed Oct 28 16:50:53 2009 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: =?utf-8?b?5q2m55SwID0/SVNPLTIwMjItSlA/Qj9JQnNrUWoxVFRHa2JLRUk9Pz0=?= X-Patchwork-Id: 37137 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [199.232.76.165]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id 00D711008B4 for ; Thu, 29 Oct 2009 08:54:03 +1100 (EST) Received: from localhost ([127.0.0.1]:51660 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1N3Cnb-0001ix-A7 for incoming@patchwork.ozlabs.org; Wed, 28 Oct 2009 13:59:07 -0400 Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.43) id 1N3Bwh-00089H-QL for qemu-devel@nongnu.org; Wed, 28 Oct 2009 13:04:27 -0400 Received: from exim by lists.gnu.org with spam-scanned (Exim 4.43) id 1N3Bwd-00084X-IS for qemu-devel@nongnu.org; Wed, 28 Oct 2009 13:04:26 -0400 Received: from [199.232.76.173] (port=52299 helo=monty-python.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1N3Bwc-000848-Ah for qemu-devel@nongnu.org; Wed, 28 Oct 2009 13:04:22 -0400 Received: from smtp-vip.mem.interq.net ([210.157.1.50]:32323 helo=smtp01.mem.internal-gmo) by monty-python.gnu.org with esmtp (Exim 4.60) (envelope-from ) id 1N3Bwa-0004kQ-SE for qemu-devel@nongnu.org; Wed, 28 Oct 2009 13:04:21 -0400 Received: (from root@localhost) by smtp01.mem.internal-gmo (8.13.8/8.12.6) id n9SH4JCC019238 for qemu-devel@nongnu.org; Thu, 29 Oct 2009 02:04:19 +0900 (JST) Received: (from root@localhost) by smtp01.mem.internal-gmo (8.13.8/8.12.6) id n9SGsIWu018836 for qemu-devel@nongnu.org; Thu, 29 Oct 2009 01:54:18 +0900 (JST) Received: (from root@localhost) by smtp01.mem.internal-gmo (8.13.8/8.12.6) id n9SGsAft018801 for qemu-devel@nongnu.org; Thu, 29 Oct 2009 01:54:10 +0900 (JST) Received: from YOUR-BD18D6DD63.m1.interq.or.jp (ntymns039132.ymns.nt.ftth.ppp.infoweb.ne.jp [121.92.167.132]) by smtp01.mem.internal-gmo with ESMTP id n9SGs5Zl018647 for ; (me101664 for with PLAIN) Thu, 29 Oct 2009 01:54:09 +0900 (JST) Message-Id: <200910281650.AA00168@YOUR-BD18D6DD63.m1.interq.or.jp> Date: Thu, 29 Oct 2009 01:50:53 +0900 To: qemu-devel From: "TAKEDA, toshiya" MIME-Version: 1.0 X-Mailer: AL-Mail32 Version 1.13 X-detected-operating-system: by monty-python.gnu.org: Solaris 10 (beta) Subject: [Qemu-devel] [PATCH v3 25/25] ymdeltat: YM2608 core forked from MAME 0.59 X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: qemu-devel.nongnu.org List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org diff --git a/qemu/hw/ymdeltat.c b/qemu/hw/ymdeltat.c new file mode 100644 index 0000000..5fa593c --- /dev/null +++ b/qemu/hw/ymdeltat.c @@ -0,0 +1,335 @@ +/* +** +** File: ymdeltat.c +** +** YAMAHA DELTA-T adpcm sound emulation subroutine +** used by fmopl.c(v0.37c-) and fm.c(v0.37a-) +** +** Base program is YM2610 emulator by Hiromitsu Shioya. +** Written by Tatsuyuki Satoh +** +** History: +** 05-08-2001 Jarek Burczynski: +** - now_step is initialized with 0 at the start of play. +** 12-06-2001 Jarek Burczynski: +** - corrected end of sample bug in YM_DELTAT_ADPCM_CALC. +** Checked on real YM2610 chip - address register is 24 bits wide. +** Thanks go to Stefan Jokisch (stefan.jokisch@gmx.de) for tracking down the problem. +** +** TO DO: +** Check size of the address register on the other chips.... +** +** Version 0.37e +** +** sound chips that have this unit +** +** YM2608 OPNA +** YM2610/B OPNB +** Y8950 MSX AUDIO +** +** +*/ + +/* This version of ay8910.c is a fork of the MAME 0.59 one, relicensed under the LGPL. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see . + */ + +#ifndef YM_INLINE_BLOCK + +#include "ymdeltat.h" + +#define INLINE static inline + +/* -------------------- log output -------------------- */ +/* log output level */ +#define LOG_ERR 3 /* ERROR */ +#define LOG_WAR 2 /* WARNING */ +#define LOG_INF 1 /* INFORMATION */ +#define LOG_LEVEL LOG_ERR + +#define LOG(n,x) + +UINT8 *ym_deltat_memory; /* memory pointer */ + +/* Forecast to next Forecast (rate = *8) */ +/* 1/8 , 3/8 , 5/8 , 7/8 , 9/8 , 11/8 , 13/8 , 15/8 */ +const INT32 ym_deltat_decode_tableB1[16] = { + 1, 3, 5, 7, 9, 11, 13, 15, + -1, -3, -5, -7, -9, -11, -13, -15, +}; +/* delta to next delta (rate= *64) */ +/* 0.9 , 0.9 , 0.9 , 0.9 , 1.2 , 1.6 , 2.0 , 2.4 */ +const INT32 ym_deltat_decode_tableB2[16] = { + 57, 57, 57, 57, 77, 102, 128, 153, + 57, 57, 57, 57, 77, 102, 128, 153 +}; + +/* DELTA-T-ADPCM write register */ +void YM_DELTAT_ADPCM_Write(YM_DELTAT *DELTAT,int r,int v) +{ + if(r>=0x10) return; + DELTAT->reg[r] = v; /* stock data */ + + switch( r ){ + case 0x00: /* START,REC,MEMDATA,REPEAT,SPOFF,--,--,RESET */ +#if 0 + case 0x60: /* write buffer MEMORY from PCM data port */ + case 0x20: /* read buffer MEMORY to PCM data port */ +#endif + if( v&0x80 ){ + DELTAT->portstate = v&0x90; /* start req,memory mode,repeat flag copy */ + /**** start ADPCM ****/ + DELTAT->volume_w_step = (double)DELTAT->volume * DELTAT->step / (1<now_addr = (DELTAT->start)<<1; + DELTAT->now_step = 0; + DELTAT->acc = 0; + DELTAT->adpcml = 0; + DELTAT->adpcmd = YM_DELTAT_DELTA_DEF; + DELTAT->next_leveling=0; + + if( !DELTAT->step ) + { + DELTAT->portstate = 0x00; + } + /**** PCM memory check & limit check ****/ + if(DELTAT->memory == 0){ /* Check memory Mapped */ + LOG(LOG_ERR,("YM Delta-T ADPCM rom not mapped\n")); + DELTAT->portstate = 0x00; + }else{ + if( DELTAT->end >= DELTAT->memory_size ) + { /* Check End in Range */ + LOG(LOG_ERR,("YM Delta-T ADPCM end out of range: $%08x\n",DELTAT->end)); + DELTAT->end = DELTAT->memory_size - 1; + } + if( DELTAT->start >= DELTAT->memory_size ) + { /* Check Start in Range */ + LOG(LOG_ERR,("YM Delta-T ADPCM start out of range: $%08x\n",DELTAT->start)); + DELTAT->portstate = 0x00; + } + } + } else if( v&0x01 ){ + DELTAT->portstate = 0x00; + } + break; + case 0x01: /* L,R,-,-,SAMPLE,DA/AD,RAMTYPE,ROM */ + DELTAT->pan = &DELTAT->output_pointer[(v>>6)&0x03]; + break; + case 0x02: /* Start Address L */ + case 0x03: /* Start Address H */ + DELTAT->start = (DELTAT->reg[0x3]*0x0100 | DELTAT->reg[0x2]) << DELTAT->portshift; + /*logerror("DELTAT start: 02=%2x 03=%2x addr=%8x\n",DELTAT->reg[0x2], DELTAT->reg[0x3],DELTAT->start );*/ + break; + case 0x04: /* Stop Address L */ + case 0x05: /* Stop Address H */ + DELTAT->end = (DELTAT->reg[0x5]*0x0100 | DELTAT->reg[0x4]) << DELTAT->portshift; + DELTAT->end += (1<portshift) - 1; + /*logerror("DELTAT end : 04=%2x 05=%2x addr=%8x\n",DELTAT->reg[0x4], DELTAT->reg[0x5],DELTAT->end );*/ + break; + case 0x06: /* Prescale L (PCM and Recoard frq) */ + case 0x07: /* Proscale H */ + case 0x08: /* ADPCM data */ + break; + case 0x09: /* DELTA-N L (ADPCM Playback Prescaler) */ + case 0x0a: /* DELTA-N H */ + DELTAT->delta = (DELTAT->reg[0xa]*0x0100 | DELTAT->reg[0x9]); + /*logerror("DELTAT deltan:09=%2x 0a=%2x\n",DELTAT->reg[0x9], DELTAT->reg[0xa]);*/ + DELTAT->step = (UINT32)( (double)(DELTAT->delta /* *(1<<(YM_DELTAT_SHIFT-16)) */ ) * (DELTAT->freqbase) ); + DELTAT->volume_w_step = (double)DELTAT->volume * DELTAT->step / (1<volume; + DELTAT->volume = (v&0xff) * (DELTAT->output_range/256) / YM_DELTAT_DECODE_RANGE; +// v * ((1<<16)>>8) >> 15; +// thus: v * (1<<8) >> 15; +// thus: output_range must be (1 << (15+8)) at least +// v * ((1<<23)>>8) >> 15; +// v * (1<<15) >> 15; + /*logerror("DELTAT vol = %2x\n",v&0xff);*/ + if( oldvol != 0 ) + { + DELTAT->adpcml = (int)((double)DELTAT->adpcml / (double)oldvol * (double)DELTAT->volume); + DELTAT->resample_step = (int)((double)DELTAT->resample_step / (double)oldvol * (double)DELTAT->volume); + } + DELTAT->volume_w_step = (double)DELTAT->volume * DELTAT->step / (1<now_addr = 0; + DELTAT->now_step = 0; + DELTAT->step = 0; + DELTAT->start = 0; + DELTAT->end = 0; + /* F2610->adpcm[i].delta = 21866; */ + DELTAT->volume = 0; + DELTAT->pan = &DELTAT->output_pointer[pan]; + /* DELTAT->flagMask = 0; */ + DELTAT->acc = 0; + DELTAT->adpcmd = 127; + DELTAT->adpcml = 0; + DELTAT->volume_w_step = 0; + DELTAT->next_leveling = 0; + DELTAT->portstate = 0; + /* DELTAT->portshift = 8; */ +} + +void YM_DELTAT_postload(YM_DELTAT *DELTAT,UINT8 *regs) +{ + int r; + + /* to keep adpcml and resample_step */ + DELTAT->volume = 0; + /* update */ + for(r=1;r<16;r++) + YM_DELTAT_ADPCM_Write(DELTAT,r,regs[r]); + DELTAT->reg[0] = regs[0]; + /* current rom data */ + DELTAT->now_data = *(ym_deltat_memory+(DELTAT->now_addr>>1)); + +} + +void YM_DELTAT_savestate(QEMUFile* f, YM_DELTAT *DELTAT) +{ + qemu_put_8s(f, &DELTAT->portstate); + qemu_put_be32s(f, &DELTAT->now_addr); + qemu_put_be32s(f, &DELTAT->now_step); + qemu_put_be32s(f, &DELTAT->acc); + qemu_put_be32s(f, &DELTAT->adpcmd); + qemu_put_be32s(f, &DELTAT->adpcml); + qemu_put_be32s(f, &DELTAT->next_leveling); + qemu_put_be32s(f, &DELTAT->resample_step); +} + +int YM_DELTAT_loadstate(QEMUFile* f, YM_DELTAT *DELTAT) +{ + qemu_get_8s(f, &DELTAT->portstate); + qemu_get_be32s(f, &DELTAT->now_addr); + qemu_get_be32s(f, &DELTAT->now_step); + qemu_get_be32s(f, &DELTAT->acc); + qemu_get_be32s(f, &DELTAT->adpcmd); + qemu_get_be32s(f, &DELTAT->adpcml); + qemu_get_be32s(f, &DELTAT->next_leveling); + qemu_get_be32s(f, &DELTAT->resample_step); + + return 0; +} +#else /* YM_INLINE_BLOCK */ + +/* ---------- inline block ---------- */ + +/* DELTA-T particle adjuster */ +#define YM_DELTAT_DELTA_MAX (24576) +#define YM_DELTAT_DELTA_MIN (127) +#define YM_DELTAT_DELTA_DEF (127) + +#define YM_DELTAT_DECODE_RANGE 32768 +#define YM_DELTAT_DECODE_MIN (-(YM_DELTAT_DECODE_RANGE)) +#define YM_DELTAT_DECODE_MAX ((YM_DELTAT_DECODE_RANGE)-1) + +extern const INT32 ym_deltat_decode_tableB1[]; +extern const INT32 ym_deltat_decode_tableB2[]; + +#define YM_DELTAT_Limit(val,max,min) \ +{ \ + if ( val > max ) val = max; \ + else if ( val < min ) val = min; \ +} + +/**** ADPCM B (Delta-T control type) ****/ +INLINE void YM_DELTAT_ADPCM_CALC(YM_DELTAT *DELTAT) +{ + UINT32 step; + int data; + INT32 prev_acc; + INT32 now_leveling; + + DELTAT->now_step += DELTAT->step; + if ( DELTAT->now_step >= (1<now_step >> YM_DELTAT_SHIFT; + DELTAT->now_step &= (1<now_addr == (DELTAT->end<<1) ) { /* 12-06-2001 JB: corrected comparison. Was > instead of == */ + if( DELTAT->portstate&0x10 ){ + /**** repeat start ****/ + DELTAT->now_addr = DELTAT->start<<1; + DELTAT->acc = 0; + DELTAT->adpcmd = YM_DELTAT_DELTA_DEF; + DELTAT->next_leveling = 0; + }else{ + if(DELTAT->arrivedFlagPtr) + (*DELTAT->arrivedFlagPtr) |= DELTAT->flagMask; + DELTAT->portstate = 0; + DELTAT->adpcml = 0; + now_leveling = 0; + return; + } + } + if( DELTAT->now_addr&1 ) data = DELTAT->now_data & 0x0f; + else + { + DELTAT->now_data = *(ym_deltat_memory+(DELTAT->now_addr>>1)); + data = DELTAT->now_data >> 4; + } + + DELTAT->now_addr++; + /* 12-06-2001 JB: */ + /* YM2610 address register is 24 bits wide.*/ + /* The "+1" is there because we use 1 bit more for nibble calculations.*/ + /* WARNING: */ + /* Side effect: we should take the size of the mapped ROM into account */ + DELTAT->now_addr &= ( (1<<(24+1))-1); + + /* store accumulator value */ + prev_acc = DELTAT->acc; + /* Forecast to next Forecast */ + DELTAT->acc += (ym_deltat_decode_tableB1[data] * DELTAT->adpcmd / 8); + YM_DELTAT_Limit(DELTAT->acc,YM_DELTAT_DECODE_MAX, YM_DELTAT_DECODE_MIN); + /* delta to next delta */ + DELTAT->adpcmd = (DELTAT->adpcmd * ym_deltat_decode_tableB2[data] ) / 64; + YM_DELTAT_Limit(DELTAT->adpcmd,YM_DELTAT_DELTA_MAX, YM_DELTAT_DELTA_MIN ); + /* calulate new leveling value */ + now_leveling = DELTAT->next_leveling; + DELTAT->next_leveling = prev_acc + ((DELTAT->acc - prev_acc) / 2 ); + + }while(--step); + +/* #define YM_DELTAT_CUT_RE_SAMPLING */ +#ifdef YM_DELTAT_CUT_RE_SAMPLING + DELTAT->adpcml = DELTAT->next_leveling * DELTAT->volume; + DELTAT->adpcml = DELTAT->acc * DELTAT->volume; + } +#else + /* delta step of resampling */ + DELTAT->resample_step = (DELTAT->next_leveling - now_leveling) * DELTAT->volume_w_step; +// DELTAT->resample_step = (DELTAT->next_leveling - now_leveling) * +// ((double)DELTAT->volume * DELTAT->step / (1<adpcml = now_leveling * DELTAT->volume; + /* adjust to now */ + DELTAT->adpcml += (int)((double)DELTAT->resample_step * ((double)DELTAT->now_step/(double)DELTAT->step)); + } + DELTAT->adpcml += DELTAT->resample_step; +#endif + /* output for work of output channels (outd[OPNxxxx])*/ + *(DELTAT->pan) += DELTAT->adpcml; +} + +#endif /* YM_INLINE_BLOCK */ diff --git a/qemu/hw/ymdeltat.h b/qemu/hw/ymdeltat.h new file mode 100644 index 0000000..9fea8f1 --- /dev/null +++ b/qemu/hw/ymdeltat.h @@ -0,0 +1,58 @@ +#ifndef __YMDELTAT_H_ +#define __YMDELTAT_H_ + +#include "hw.h" +#include "fm_def.h" + +#define YM_DELTAT_SHIFT (16) + +/* adpcm type A and type B struct */ +typedef struct deltat_adpcm_state { + UINT8 *memory; + int memory_size; + double freqbase; + INT32 *output_pointer; /* pointer of output pointers */ + int output_range; + + UINT8 reg[16]; /* adpcm registers */ + UINT8 portstate; /* port status : stop==0*/ + int portshift; /* address shift bits */ + UINT8 now_data; /* current rom data */ + UINT32 now_addr; /* current address */ + UINT32 now_step; /* currect step */ + UINT32 step; /* step */ + UINT32 start; /* start address */ + UINT32 end; /* end address */ + UINT32 delta; /* delta scale */ + INT32 volume; /* current volume */ + INT32 *pan; /* pan : &output_pointer[pan] */ + INT32 acc; /* shift Measurement value */ + INT32 adpcmd; /* next Forecast */ + INT32 adpcml; /* current value */ + /* leveling and re-sampling state for DELTA-T */ + INT32 volume_w_step; /* volume with step rate */ + INT32 next_leveling; /* leveling value */ + INT32 resample_step; /* step of re-sampling */ + /* external flag controll (for YM2610) */ + UINT8 flagMask; /* arrived flag mask */ + UINT8 *arrivedFlagPtr; /* pointer of arrived end address flag */ +}YM_DELTAT; + +/* static state */ +extern UINT8 *ym_deltat_memory; /* memory pointer */ + +/* before YM_DELTAT_ADPCM_CALC(YM_DELTAT *DELTAT); */ +#define YM_DELTAT_DECODE_PRESET(DELTAT) {ym_deltat_memory = DELTAT->memory;} + +void YM_DELTAT_ADPCM_Write(YM_DELTAT *DELTAT,int r,int v); +void YM_DELTAT_ADPCM_Reset(YM_DELTAT *DELTAT,int pan); +void YM_DELTAT_postload(YM_DELTAT *DELTAT,UINT8 *regs); +void YM_DELTAT_savestate(QEMUFile* f, YM_DELTAT *DELTAT); +int YM_DELTAT_loadstate(QEMUFile* f, YM_DELTAT *DELTAT); + +/* INLINE void YM_DELTAT_ADPCM_CALC(YM_DELTAT *DELTAT); */ +#define YM_INLINE_BLOCK +#include "ymdeltat.c" /* include inline function section */ +#undef YM_INLINE_BLOCK + +#endif