mirror of
https://github.com/holub/mame
synced 2025-05-23 22:20:01 +03:00

a region to a generic type pointer and have it automatically convert. Also added a bytes() method which is safe if the region is NULL (useful for saying machine->region("foo")->bytes() and not crashing if foo doesn't exist). Changed the region field in the device_config to be a region_info *, and removed the regionbytes field. Updated all users of these fields to use the new casting operators and bytes() methods instead. Added subdevice and subregion methods to the device_config class, so you can easily query for devices and regions that are device-specific. The device prefix ("devicename:") is automatically prepended.
727 lines
20 KiB
C
727 lines
20 KiB
C
/*
|
|
vlm5030.c
|
|
|
|
VLM5030 emulator
|
|
|
|
Written by Tatsuyuki Satoh
|
|
Based on TMS5220 simulator (tms5220.c)
|
|
|
|
note:
|
|
memory read cycle(==sampling rate) = 122.9u(440clock)
|
|
interpolator (LC8109 = 2.5ms) = 20 * samples(125us)
|
|
frame time (20ms) = 4 * interpolator
|
|
9bit DAC is composed of 5bit Physical and 3bitPWM.
|
|
|
|
todo:
|
|
Noise Generator circuit without 'mame_rand()' function.
|
|
|
|
----------- command format (Analytical result) ----------
|
|
|
|
1)end of speech (8bit)
|
|
:00000011:
|
|
|
|
2)silent some frame (8bit)
|
|
:????SS01:
|
|
|
|
SS : number of silent frames
|
|
00 = 2 frame
|
|
01 = 4 frame
|
|
10 = 6 frame
|
|
11 = 8 frame
|
|
|
|
3)-speech frame (48bit)
|
|
function: 6th : 5th : 4th : 3rd : 2nd : 1st :
|
|
end : --- : --- : --- : --- : --- :00000011:
|
|
silent : --- : --- : --- : --- : --- :0000SS01:
|
|
speech :11111122:22233334:44455566:67778889:99AAAEEE:EEPPPPP0:
|
|
|
|
EEEEE : energy : volume 0=off,0x1f=max
|
|
PPPPP : pitch : 0=noize , 1=fast,0x1f=slow
|
|
111111 : K1 : 48=off
|
|
22222 : K2 : 0=off,1=+min,0x0f=+max,0x10=off,0x11=+max,0x1f=-min
|
|
: 16 == special function??
|
|
3333 : K3 : 0=off,1=+min,0x07=+max,0x08=-max,0x0f=-min
|
|
4444 : K4 :
|
|
555 : K5 : 0=off,1=+min,0x03=+max,0x04=-max,0x07=-min
|
|
666 : K6 :
|
|
777 : K7 :
|
|
888 : K8 :
|
|
999 : K9 :
|
|
AAA : K10 :
|
|
|
|
---------- chirp table information ----------
|
|
|
|
DAC PWM cycle == 88system clock , (11clock x 8 pattern) = 40.6KHz
|
|
one chirp == 5 x PWM cycle == 440systemclock(8,136Hz)
|
|
|
|
chirp 0 : volume 10- 8 : with filter
|
|
chirp 1 : volume 8- 6 : with filter
|
|
chirp 2 : volume 6- 4 : with filter
|
|
chirp 3 : volume 4 : no filter ??
|
|
chirp 4- 5: volume 4- 2 : with filter
|
|
chirp 6-11: volume 2- 0 : with filter
|
|
chirp 12-..: vokume 0 : silent
|
|
|
|
---------- digial output information ----------
|
|
when ME pin = high , some status output to A0..15 pins
|
|
|
|
A0..8 : DAC output value (abs)
|
|
A9 : DAC sign flag , L=minus,H=Plus
|
|
A10 : energy reload flag (pitch pulse)
|
|
A11..15 : unknown
|
|
|
|
[DAC output value(signed 6bit)] = A9 ? A0..8 : -(A0..8)
|
|
|
|
*/
|
|
#include "emu.h"
|
|
#include "streams.h"
|
|
#include "vlm5030.h"
|
|
|
|
/* interpolator per frame */
|
|
#define FR_SIZE 4
|
|
/* samples per interpolator */
|
|
#define IP_SIZE_SLOWER (240/FR_SIZE)
|
|
#define IP_SIZE_SLOW (200/FR_SIZE)
|
|
#define IP_SIZE_NORMAL (160/FR_SIZE)
|
|
#define IP_SIZE_FAST (120/FR_SIZE)
|
|
#define IP_SIZE_FASTER ( 80/FR_SIZE)
|
|
|
|
typedef struct _vlm5030_state vlm5030_state;
|
|
struct _vlm5030_state
|
|
{
|
|
const device_config *device;
|
|
const vlm5030_interface *intf;
|
|
|
|
sound_stream * channel;
|
|
|
|
/* need to save state */
|
|
|
|
UINT8 *rom;
|
|
int address_mask;
|
|
UINT16 address;
|
|
UINT8 pin_BSY;
|
|
UINT8 pin_ST;
|
|
UINT8 pin_VCU;
|
|
UINT8 pin_RST;
|
|
UINT8 latch_data;
|
|
UINT16 vcu_addr_h;
|
|
UINT8 parameter;
|
|
UINT8 phase;
|
|
|
|
/* state of option paramter */
|
|
int frame_size;
|
|
int pitch_offset;
|
|
UINT8 interp_step;
|
|
|
|
UINT8 interp_count; /* number of interp periods */
|
|
UINT8 sample_count; /* sample number within interp */
|
|
UINT8 pitch_count;
|
|
|
|
/* these contain data describing the current and previous voice frames */
|
|
UINT16 old_energy;
|
|
UINT8 old_pitch;
|
|
INT16 old_k[10];
|
|
UINT16 target_energy;
|
|
UINT8 target_pitch;
|
|
INT16 target_k[10];
|
|
|
|
UINT16 new_energy;
|
|
UINT8 new_pitch;
|
|
INT16 new_k[10];
|
|
|
|
/* these are all used to contain the current state of the sound generation */
|
|
unsigned int current_energy;
|
|
unsigned int current_pitch;
|
|
int current_k[10];
|
|
|
|
INT32 x[10];
|
|
};
|
|
|
|
/* phase value */
|
|
enum {
|
|
PH_RESET,
|
|
PH_IDLE,
|
|
PH_SETUP,
|
|
PH_WAIT,
|
|
PH_RUN,
|
|
PH_STOP,
|
|
PH_END
|
|
};
|
|
|
|
/*
|
|
speed parameter
|
|
SPC SPB SPA
|
|
1 0 1 more slow (05h) : 42ms (150%) : 60sample
|
|
1 1 x slow (06h,07h) : 34ms (125%) : 50sample
|
|
x 0 0 normal (00h,04h) : 25.6ms (100%) : 40samplme
|
|
0 0 1 fast (01h) : 20.2ms (75%) : 30sample
|
|
0 1 x more fast (02h,03h) : 12.2ms (50%) : 20sample
|
|
*/
|
|
static const int vlm5030_speed_table[8] =
|
|
{
|
|
IP_SIZE_NORMAL,
|
|
IP_SIZE_FAST,
|
|
IP_SIZE_FASTER,
|
|
IP_SIZE_FASTER,
|
|
IP_SIZE_NORMAL,
|
|
IP_SIZE_SLOWER,
|
|
IP_SIZE_SLOW,
|
|
IP_SIZE_SLOW
|
|
};
|
|
|
|
static const char VLM_NAME[] = "VLM5030";
|
|
|
|
/* ROM Tables */
|
|
|
|
/* This is the energy lookup table */
|
|
|
|
/* sampled from real chip */
|
|
static const unsigned short energytable[0x20] =
|
|
{
|
|
0, 2, 4, 6, 10, 12, 14, 18, /* 0-7 */
|
|
22, 26, 30, 34, 38, 44, 48, 54, /* 8-15 */
|
|
62, 68, 76, 84, 94,102,114,124, /* 16-23 */
|
|
136,150,164,178,196,214,232,254 /* 24-31 */
|
|
};
|
|
|
|
/* This is the pitch lookup table */
|
|
static const unsigned char pitchtable [0x20]=
|
|
{
|
|
1, /* 0 : random mode */
|
|
22, /* 1 : start=22 */
|
|
23, 24, 25, 26, 27, 28, 29, 30, /* 2- 9 : 1step */
|
|
32, 34, 36, 38, 40, 42, 44, 46, /* 10-17 : 2step */
|
|
50, 54, 58, 62, 66, 70, 74, 78, /* 18-25 : 4step */
|
|
86, 94, 102,110,118,126 /* 26-31 : 8step */
|
|
};
|
|
|
|
static const INT16 K1_table[] = {
|
|
-24898, -25672, -26446, -27091, -27736, -28252, -28768, -29155,
|
|
-29542, -29929, -30316, -30574, -30832, -30961, -31219, -31348,
|
|
-31606, -31735, -31864, -31864, -31993, -32122, -32122, -32251,
|
|
-32251, -32380, -32380, -32380, -32509, -32509, -32509, -32509,
|
|
24898, 23995, 22963, 21931, 20770, 19480, 18061, 16642,
|
|
15093, 13416, 11610, 9804, 7998, 6063, 3999, 1935,
|
|
0, -1935, -3999, -6063, -7998, -9804, -11610, -13416,
|
|
-15093, -16642, -18061, -19480, -20770, -21931, -22963, -23995
|
|
};
|
|
static const INT16 K2_table[] = {
|
|
0, -3096, -6321, -9417, -12513, -15351, -18061, -20770,
|
|
-23092, -25285, -27220, -28897, -30187, -31348, -32122, -32638,
|
|
0, 32638, 32122, 31348, 30187, 28897, 27220, 25285,
|
|
23092, 20770, 18061, 15351, 12513, 9417, 6321, 3096
|
|
};
|
|
static const INT16 K3_table[] = {
|
|
0, -3999, -8127, -12255, -16384, -20383, -24511, -28639,
|
|
32638, 28639, 24511, 20383, 16254, 12255, 8127, 3999
|
|
};
|
|
static const INT16 K5_table[] = {
|
|
0, -8127, -16384, -24511, 32638, 24511, 16254, 8127
|
|
};
|
|
|
|
INLINE vlm5030_state *get_safe_token(const device_config *device)
|
|
{
|
|
assert(device != NULL);
|
|
assert(device->token != NULL);
|
|
assert(device->type == SOUND);
|
|
assert(sound_get_type(device) == SOUND_VLM5030);
|
|
return (vlm5030_state *)device->token;
|
|
}
|
|
|
|
static int get_bits(vlm5030_state *chip, int sbit,int bits)
|
|
{
|
|
int offset = chip->address + (sbit>>3);
|
|
int data;
|
|
|
|
data = chip->rom[offset&chip->address_mask] +
|
|
(((int)chip->rom[(offset+1)&chip->address_mask])*256);
|
|
data >>= (sbit&7);
|
|
data &= (0xff>>(8-bits));
|
|
|
|
return data;
|
|
}
|
|
|
|
/* get next frame */
|
|
static int parse_frame (vlm5030_state *chip)
|
|
{
|
|
unsigned char cmd;
|
|
int i;
|
|
|
|
/* remember previous frame */
|
|
chip->old_energy = chip->new_energy;
|
|
chip->old_pitch = chip->new_pitch;
|
|
for(i=0;i<=9;i++)
|
|
chip->old_k[i] = chip->new_k[i];
|
|
|
|
/* command byte check */
|
|
cmd = chip->rom[chip->address&chip->address_mask];
|
|
if( cmd & 0x01 )
|
|
{ /* extend frame */
|
|
chip->new_energy = chip->new_pitch = 0;
|
|
for(i=0;i<=9;i++)
|
|
chip->new_k[i] = 0;
|
|
chip->address++;
|
|
if( cmd & 0x02 )
|
|
{ /* end of speech */
|
|
|
|
/* logerror("VLM5030 %04X end \n",chip->address ); */
|
|
return 0;
|
|
}
|
|
else
|
|
{ /* silent frame */
|
|
int nums = ( (cmd>>2)+1 )*2;
|
|
/* logerror("VLM5030 %04X silent %d frame\n",chip->address,nums ); */
|
|
return nums * FR_SIZE;
|
|
}
|
|
}
|
|
/* pitch */
|
|
chip->new_pitch = ( pitchtable[get_bits(chip, 1,5)] + chip->pitch_offset )&0xff;
|
|
/* energy */
|
|
chip->new_energy = energytable[get_bits(chip, 6,5)];
|
|
|
|
/* 10 K's */
|
|
chip->new_k[9] = K5_table[get_bits(chip,11,3)];
|
|
chip->new_k[8] = K5_table[get_bits(chip,14,3)];
|
|
chip->new_k[7] = K5_table[get_bits(chip,17,3)];
|
|
chip->new_k[6] = K5_table[get_bits(chip,20,3)];
|
|
chip->new_k[5] = K5_table[get_bits(chip,23,3)];
|
|
chip->new_k[4] = K5_table[get_bits(chip,26,3)];
|
|
chip->new_k[3] = K3_table[get_bits(chip,29,4)];
|
|
chip->new_k[2] = K3_table[get_bits(chip,33,4)];
|
|
chip->new_k[1] = K2_table[get_bits(chip,37,5)];
|
|
chip->new_k[0] = K1_table[get_bits(chip,42,6)];
|
|
|
|
chip->address+=6;
|
|
logerror("VLM5030 %04X voice \n",chip->address );
|
|
return FR_SIZE;
|
|
}
|
|
|
|
/* decode and buffering data */
|
|
static STREAM_UPDATE( vlm5030_update_callback )
|
|
{
|
|
vlm5030_state *chip = (vlm5030_state *)param;
|
|
int buf_count=0;
|
|
int interp_effect;
|
|
int i;
|
|
int u[11];
|
|
stream_sample_t *buffer = outputs[0];
|
|
|
|
/* running */
|
|
if( chip->phase == PH_RUN || chip->phase == PH_STOP )
|
|
{
|
|
/* playing speech */
|
|
while (samples > 0)
|
|
{
|
|
int current_val;
|
|
|
|
/* check new interpolator or new frame */
|
|
if( chip->sample_count == 0 )
|
|
{
|
|
if( chip->phase == PH_STOP )
|
|
{
|
|
chip->phase = PH_END;
|
|
chip->sample_count = 1;
|
|
goto phase_stop; /* continue to end phase */
|
|
}
|
|
chip->sample_count = chip->frame_size;
|
|
/* interpolator changes */
|
|
if ( chip->interp_count == 0 )
|
|
{
|
|
/* change to new frame */
|
|
chip->interp_count = parse_frame(chip); /* with change phase */
|
|
if ( chip->interp_count == 0 )
|
|
{ /* end mark found */
|
|
chip->interp_count = FR_SIZE;
|
|
chip->sample_count = chip->frame_size; /* end -> stop time */
|
|
chip->phase = PH_STOP;
|
|
}
|
|
/* Set old target as new start of frame */
|
|
chip->current_energy = chip->old_energy;
|
|
chip->current_pitch = chip->old_pitch;
|
|
for(i=0;i<=9;i++)
|
|
chip->current_k[i] = chip->old_k[i];
|
|
/* is this a zero energy frame? */
|
|
if (chip->current_energy == 0)
|
|
{
|
|
/*mame_printf_debug("processing frame: zero energy\n");*/
|
|
chip->target_energy = 0;
|
|
chip->target_pitch = chip->current_pitch;
|
|
for(i=0;i<=9;i++)
|
|
chip->target_k[i] = chip->current_k[i];
|
|
}
|
|
else
|
|
{
|
|
/*mame_printf_debug("processing frame: Normal\n");*/
|
|
/*mame_printf_debug("*** Energy = %d\n",chip->current_energy);*/
|
|
/*mame_printf_debug("proc: %d %d\n",last_fbuf_head,fbuf_head);*/
|
|
chip->target_energy = chip->new_energy;
|
|
chip->target_pitch = chip->new_pitch;
|
|
for(i=0;i<=9;i++)
|
|
chip->target_k[i] = chip->new_k[i];
|
|
}
|
|
}
|
|
/* next interpolator */
|
|
/* Update values based on step values 25% , 50% , 75% , 100% */
|
|
chip->interp_count -= chip->interp_step;
|
|
/* 3,2,1,0 -> 1,2,3,4 */
|
|
interp_effect = FR_SIZE - (chip->interp_count%FR_SIZE);
|
|
chip->current_energy = chip->old_energy + (chip->target_energy - chip->old_energy) * interp_effect / FR_SIZE;
|
|
if (chip->old_pitch > 1)
|
|
chip->current_pitch = chip->old_pitch + (chip->target_pitch - chip->old_pitch) * interp_effect / FR_SIZE;
|
|
for (i = 0; i <= 9 ; i++)
|
|
chip->current_k[i] = chip->old_k[i] + (chip->target_k[i] - chip->old_k[i]) * interp_effect / FR_SIZE;
|
|
}
|
|
/* calcrate digital filter */
|
|
if (chip->old_energy == 0)
|
|
{
|
|
/* generate silent samples here */
|
|
current_val = 0x00;
|
|
}
|
|
else if (chip->old_pitch <= 1)
|
|
{ /* generate unvoiced samples here */
|
|
current_val = (mame_rand(chip->device->machine)&1) ? chip->current_energy : -chip->current_energy;
|
|
}
|
|
else
|
|
{
|
|
/* generate voiced samples here */
|
|
current_val = ( chip->pitch_count == 0) ? chip->current_energy : 0;
|
|
}
|
|
|
|
/* Lattice filter here */
|
|
u[10] = current_val;
|
|
for (i = 9; i >= 0; i--)
|
|
u[i] = u[i+1] - ((chip->current_k[i] * chip->x[i]) / 32768);
|
|
for (i = 9; i >= 1; i--)
|
|
chip->x[i] = chip->x[i-1] + ((chip->current_k[i-1] * u[i-1]) / 32768);
|
|
chip->x[0] = u[0];
|
|
|
|
/* clipping, buffering */
|
|
if (u[0] > 511)
|
|
buffer[buf_count] = 511<<6;
|
|
else if (u[0] < -511)
|
|
buffer[buf_count] = -511<<6;
|
|
else
|
|
buffer[buf_count] = (u[0] << 6);
|
|
buf_count++;
|
|
|
|
/* sample count */
|
|
chip->sample_count--;
|
|
/* pitch */
|
|
chip->pitch_count++;
|
|
if (chip->pitch_count >= chip->current_pitch )
|
|
chip->pitch_count = 0;
|
|
/* size */
|
|
samples--;
|
|
}
|
|
/* return;*/
|
|
}
|
|
/* stop phase */
|
|
phase_stop:
|
|
switch( chip->phase )
|
|
{
|
|
case PH_SETUP:
|
|
if( chip->sample_count <= samples)
|
|
{
|
|
chip->sample_count = 0;
|
|
/* logerror("VLM5030 BSY=H\n" ); */
|
|
/* pin_BSY = 1; */
|
|
chip->phase = PH_WAIT;
|
|
}
|
|
else
|
|
{
|
|
chip->sample_count -= samples;
|
|
}
|
|
break;
|
|
case PH_END:
|
|
if( chip->sample_count <= samples)
|
|
{
|
|
chip->sample_count = 0;
|
|
/* logerror("VLM5030 BSY=L\n" ); */
|
|
chip->pin_BSY = 0;
|
|
chip->phase = PH_IDLE;
|
|
}
|
|
else
|
|
{
|
|
chip->sample_count -= samples;
|
|
}
|
|
}
|
|
/* silent buffering */
|
|
while (samples > 0)
|
|
{
|
|
buffer[buf_count++] = 0x00;
|
|
samples--;
|
|
}
|
|
}
|
|
|
|
/* realtime update */
|
|
static void vlm5030_update(vlm5030_state *chip)
|
|
{
|
|
stream_update(chip->channel);
|
|
}
|
|
|
|
/* setup parameteroption when RST=H */
|
|
static void vlm5030_setup_parameter(vlm5030_state *chip, UINT8 param)
|
|
{
|
|
/* latch parameter value */
|
|
chip->parameter = param;
|
|
|
|
/* bit 0,1 : 4800bps / 9600bps , interporator step */
|
|
if(param&2) /* bit 1 = 1 , 9600bps */
|
|
chip->interp_step = 4; /* 9600bps : no interporator */
|
|
else if(param&1) /* bit1 = 0 & bit0 = 1 , 4800bps */
|
|
chip->interp_step = 2; /* 4800bps : 2 interporator */
|
|
else /* bit1 = bit0 = 0 : 2400bps */
|
|
chip->interp_step = 1; /* 2400bps : 4 interporator */
|
|
|
|
/* bit 3,4,5 : speed (frame size) */
|
|
chip->frame_size = vlm5030_speed_table[(param>>3) &7];
|
|
|
|
/* bit 6,7 : low / high pitch */
|
|
if(param&0x80) /* bit7=1 , high pitch */
|
|
chip->pitch_offset = -8;
|
|
else if(param&0x40) /* bit6=1 , low pitch */
|
|
chip->pitch_offset = 8;
|
|
else
|
|
chip->pitch_offset = 0;
|
|
}
|
|
|
|
|
|
static STATE_POSTLOAD( vlm5030_restore_state )
|
|
{
|
|
vlm5030_state *chip = (vlm5030_state *)param;
|
|
int i;
|
|
|
|
int interp_effect = FR_SIZE - (chip->interp_count%FR_SIZE);
|
|
/* restore parameter data */
|
|
vlm5030_setup_parameter(chip, chip->parameter);
|
|
|
|
/* restore current energy,pitch & filter */
|
|
chip->current_energy = chip->old_energy + (chip->target_energy - chip->old_energy) * interp_effect / FR_SIZE;
|
|
if (chip->old_pitch > 1)
|
|
chip->current_pitch = chip->old_pitch + (chip->target_pitch - chip->old_pitch) * interp_effect / FR_SIZE;
|
|
for (i = 0; i <= 9 ; i++)
|
|
chip->current_k[i] = chip->old_k[i] + (chip->target_k[i] - chip->old_k[i]) * interp_effect / FR_SIZE;
|
|
}
|
|
|
|
|
|
static void vlm5030_reset(vlm5030_state *chip)
|
|
{
|
|
chip->phase = PH_RESET;
|
|
chip->address = 0;
|
|
chip->vcu_addr_h = 0;
|
|
chip->pin_BSY = 0;
|
|
|
|
chip->old_energy = chip->old_pitch = 0;
|
|
chip->new_energy = chip->new_pitch = 0;
|
|
chip->current_energy = chip->current_pitch = 0;
|
|
chip->target_energy = chip->target_pitch = 0;
|
|
memset(chip->old_k, 0, sizeof(chip->old_k));
|
|
memset(chip->new_k, 0, sizeof(chip->new_k));
|
|
memset(chip->current_k, 0, sizeof(chip->current_k));
|
|
memset(chip->target_k, 0, sizeof(chip->target_k));
|
|
chip->interp_count = chip->sample_count = chip->pitch_count = 0;
|
|
memset(chip->x, 0, sizeof(chip->x));
|
|
/* reset parameters */
|
|
vlm5030_setup_parameter(chip, 0x00);
|
|
}
|
|
|
|
static DEVICE_RESET( vlm5030 )
|
|
{
|
|
vlm5030_reset(get_safe_token(device));
|
|
}
|
|
|
|
|
|
/* set speech rom address */
|
|
void vlm5030_set_rom(const device_config *device, void *speech_rom)
|
|
{
|
|
vlm5030_state *chip = get_safe_token(device);
|
|
chip->rom = (UINT8 *)speech_rom;
|
|
}
|
|
|
|
/* get BSY pin level */
|
|
int vlm5030_bsy(const device_config *device)
|
|
{
|
|
vlm5030_state *chip = get_safe_token(device);
|
|
vlm5030_update(chip);
|
|
return chip->pin_BSY;
|
|
}
|
|
|
|
/* latch contoll data */
|
|
WRITE8_DEVICE_HANDLER( vlm5030_data_w )
|
|
{
|
|
vlm5030_state *chip = get_safe_token(device);
|
|
chip->latch_data = (UINT8)data;
|
|
}
|
|
|
|
/* set RST pin level : reset / set table address A8-A15 */
|
|
void vlm5030_rst (const device_config *device, int pin )
|
|
{
|
|
vlm5030_state *chip = get_safe_token(device);
|
|
if( chip->pin_RST )
|
|
{
|
|
if( !pin )
|
|
{ /* H -> L : latch parameters */
|
|
chip->pin_RST = 0;
|
|
vlm5030_setup_parameter(chip, chip->latch_data);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if( pin )
|
|
{ /* L -> H : reset chip */
|
|
chip->pin_RST = 1;
|
|
if( chip->pin_BSY )
|
|
{
|
|
vlm5030_reset(chip);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* set VCU pin level : ?? unknown */
|
|
void vlm5030_vcu(const device_config *device, int pin)
|
|
{
|
|
vlm5030_state *chip = get_safe_token(device);
|
|
/* direct mode / indirect mode */
|
|
chip->pin_VCU = pin;
|
|
return;
|
|
}
|
|
|
|
/* set ST pin level : set table address A0-A7 / start speech */
|
|
void vlm5030_st(const device_config *device, int pin )
|
|
{
|
|
vlm5030_state *chip = get_safe_token(device);
|
|
int table;
|
|
|
|
if( chip->pin_ST != pin )
|
|
{
|
|
/* pin level is change */
|
|
if( !pin )
|
|
{ /* H -> L */
|
|
chip->pin_ST = 0;
|
|
|
|
if( chip->pin_VCU )
|
|
{ /* direct access mode & address High */
|
|
chip->vcu_addr_h = ((int)chip->latch_data<<8) + 0x01;
|
|
}
|
|
else
|
|
{
|
|
/* start speech */
|
|
/* check access mode */
|
|
if( chip->vcu_addr_h )
|
|
{ /* direct access mode */
|
|
chip->address = (chip->vcu_addr_h&0xff00) + chip->latch_data;
|
|
chip->vcu_addr_h = 0;
|
|
}
|
|
else
|
|
{ /* indirect accedd mode */
|
|
table = (chip->latch_data&0xfe) + (((int)chip->latch_data&1)<<8);
|
|
chip->address = (((int)chip->rom[table&chip->address_mask])<<8)
|
|
| chip->rom[(table+1)&chip->address_mask];
|
|
#if 0
|
|
/* show unsupported parameter message */
|
|
if( chip->interp_step != 1)
|
|
popmessage("No %d %dBPS parameter",table/2,chip->interp_step*2400);
|
|
#endif
|
|
}
|
|
vlm5030_update(chip);
|
|
/* logerror("VLM5030 %02X start adr=%04X\n",table/2,chip->address ); */
|
|
/* reset process status */
|
|
chip->sample_count = chip->frame_size;
|
|
chip->interp_count = FR_SIZE;
|
|
/* clear filter */
|
|
/* start after 3 sampling cycle */
|
|
chip->phase = PH_RUN;
|
|
}
|
|
}
|
|
else
|
|
{ /* L -> H */
|
|
chip->pin_ST = 1;
|
|
/* setup speech , BSY on after 30ms? */
|
|
chip->phase = PH_SETUP;
|
|
chip->sample_count = 1; /* wait time for busy on */
|
|
chip->pin_BSY = 1; /* */
|
|
}
|
|
}
|
|
}
|
|
|
|
/* start VLM5030 with sound rom */
|
|
/* speech_rom == 0 -> use sampling data mode */
|
|
static DEVICE_START( vlm5030 )
|
|
{
|
|
const vlm5030_interface defintrf = { 0 };
|
|
int emulation_rate;
|
|
vlm5030_state *chip = get_safe_token(device);
|
|
|
|
chip->device = device;
|
|
chip->intf = (device->static_config != NULL) ? (const vlm5030_interface *)device->static_config : &defintrf;
|
|
|
|
emulation_rate = device->clock / 440;
|
|
|
|
/* reset input pins */
|
|
chip->pin_RST = chip->pin_ST = chip->pin_VCU= 0;
|
|
chip->latch_data = 0;
|
|
|
|
vlm5030_reset(chip);
|
|
chip->phase = PH_IDLE;
|
|
|
|
chip->rom = *device->region;
|
|
/* memory size */
|
|
if( chip->intf->memory_size == 0)
|
|
chip->address_mask = device->region->bytes()-1;
|
|
else
|
|
chip->address_mask = chip->intf->memory_size-1;
|
|
|
|
chip->channel = stream_create(device, 0, 1, emulation_rate,chip,vlm5030_update_callback);
|
|
|
|
/* don't restore "UINT8 *chip->rom" when use vlm5030_set_rom() */
|
|
|
|
state_save_register_device_item(device,0,chip->address);
|
|
state_save_register_device_item(device,0,chip->pin_BSY);
|
|
state_save_register_device_item(device,0,chip->pin_ST);
|
|
state_save_register_device_item(device,0,chip->pin_VCU);
|
|
state_save_register_device_item(device,0,chip->pin_RST);
|
|
state_save_register_device_item(device,0,chip->latch_data);
|
|
state_save_register_device_item(device,0,chip->vcu_addr_h);
|
|
state_save_register_device_item(device,0,chip->parameter);
|
|
state_save_register_device_item(device,0,chip->phase);
|
|
state_save_register_device_item(device,0,chip->interp_count);
|
|
state_save_register_device_item(device,0,chip->sample_count);
|
|
state_save_register_device_item(device,0,chip->pitch_count);
|
|
state_save_register_device_item(device,0,chip->old_energy);
|
|
state_save_register_device_item(device,0,chip->old_pitch);
|
|
state_save_register_device_item_array(device,0,chip->old_k);
|
|
state_save_register_device_item(device,0,chip->target_energy);
|
|
state_save_register_device_item(device,0,chip->target_pitch);
|
|
state_save_register_device_item_array(device,0,chip->target_k);
|
|
state_save_register_device_item_array(device,0,chip->x);
|
|
state_save_register_postload(device->machine, vlm5030_restore_state, chip);
|
|
}
|
|
|
|
|
|
/**************************************************************************
|
|
* Generic get_info
|
|
**************************************************************************/
|
|
|
|
DEVICE_GET_INFO( vlm5030 )
|
|
{
|
|
switch (state)
|
|
{
|
|
/* --- the following bits of info are returned as 64-bit signed integers --- */
|
|
case DEVINFO_INT_TOKEN_BYTES: info->i = sizeof(vlm5030_state); break;
|
|
|
|
/* --- the following bits of info are returned as pointers to data or functions --- */
|
|
case DEVINFO_FCT_START: info->start = DEVICE_START_NAME( vlm5030 ); break;
|
|
case DEVINFO_FCT_STOP: /* Nothing */ break;
|
|
case DEVINFO_FCT_RESET: info->reset = DEVICE_RESET_NAME( vlm5030 ); break;
|
|
|
|
/* --- the following bits of info are returned as NULL-terminated strings --- */
|
|
case DEVINFO_STR_NAME: strcpy(info->s, "VLM5030"); break;
|
|
case DEVINFO_STR_FAMILY: strcpy(info->s, "VLM speech"); break;
|
|
case DEVINFO_STR_VERSION: strcpy(info->s, "1.0"); break;
|
|
case DEVINFO_STR_SOURCE_FILE: strcpy(info->s, __FILE__); break;
|
|
case DEVINFO_STR_CREDITS: strcpy(info->s, "Copyright Nicola Salmoria and the MAME Team"); break;
|
|
}
|
|
}
|
|
|