summaryrefslogtreecommitdiffstatshomepage
path: root/src/emu/sound/tms5110.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/emu/sound/tms5110.c')
-rw-r--r--src/emu/sound/tms5110.c731
1 files changed, 731 insertions, 0 deletions
diff --git a/src/emu/sound/tms5110.c b/src/emu/sound/tms5110.c
new file mode 100644
index 00000000000..a1e3ee5131c
--- /dev/null
+++ b/src/emu/sound/tms5110.c
@@ -0,0 +1,731 @@
+/**********************************************************************************************
+
+ TMS5110 simulator (modified from TMS5220 by Jarek Burczynski)
+
+ Written for MAME by Frank Palazzolo
+ With help from Neill Corlett
+ Additional tweaking by Aaron Giles
+ Various fixes by Lord Nightmare
+
+***********************************************************************************************/
+
+#include "sndintrf.h"
+#include "tms5110.h"
+
+
+/* Pull in the ROM tables */
+#include "tms5110r.c"
+
+
+struct tms5110
+{
+ /* these contain data that describes the 64 bits FIFO */
+ #define FIFO_SIZE 64
+ UINT8 fifo[FIFO_SIZE];
+ UINT8 fifo_head;
+ UINT8 fifo_tail;
+ UINT8 fifo_count;
+
+ /* these contain global status bits */
+ UINT8 PDC;
+ UINT8 CTL_pins;
+ UINT8 speaking_now;
+ UINT8 speak_delay_frames;
+ UINT8 talk_status;
+
+
+ int (*M0_callback)(void);
+
+ /* these contain data describing the current and previous voice frames */
+ UINT16 old_energy;
+ UINT16 old_pitch;
+ INT32 old_k[10];
+
+ UINT16 new_energy;
+ UINT16 new_pitch;
+ INT32 new_k[10];
+
+
+ /* these are all used to contain the current state of the sound generation */
+ UINT16 current_energy;
+ UINT16 current_pitch;
+ INT32 current_k[10];
+
+ UINT16 target_energy;
+ UINT16 target_pitch;
+ INT32 target_k[10];
+
+ UINT8 interp_count; /* number of interp periods (0-7) */
+ UINT8 sample_count; /* sample number within interp (0-24) */
+ INT32 pitch_count;
+
+ INT32 u[11];
+ INT32 x[10];
+
+ INT32 RNG; /* the random noise generator configuration is: 1 + x + x^3 + x^4 + x^13 */
+};
+
+
+/* Static function prototypes */
+static void parse_frame(struct tms5110 *tms);
+
+
+#define DEBUG_5110 0
+
+
+void *tms5110_create(int index)
+{
+ struct tms5110 *tms;
+
+ tms = malloc_or_die(sizeof(*tms));
+ memset(tms, 0, sizeof(*tms));
+
+ state_save_register_item_array("tms5110", index, tms->fifo);
+ state_save_register_item("tms5110", index, tms->fifo_head);
+ state_save_register_item("tms5110", index, tms->fifo_tail);
+ state_save_register_item("tms5110", index, tms->fifo_count);
+
+ state_save_register_item("tms5110", index, tms->PDC);
+ state_save_register_item("tms5110", index, tms->CTL_pins);
+ state_save_register_item("tms5110", index, tms->speaking_now);
+ state_save_register_item("tms5110", index, tms->speak_delay_frames);
+ state_save_register_item("tms5110", index, tms->talk_status);
+
+ state_save_register_item("tms5110", index, tms->old_energy);
+ state_save_register_item("tms5110", index, tms->old_pitch);
+ state_save_register_item_array("tms5110", index, tms->old_k);
+
+ state_save_register_item("tms5110", index, tms->new_energy);
+ state_save_register_item("tms5110", index, tms->new_pitch);
+ state_save_register_item_array("tms5110", index, tms->new_k);
+
+ state_save_register_item("tms5110", index, tms->current_energy);
+ state_save_register_item("tms5110", index, tms->current_pitch);
+ state_save_register_item_array("tms5110", index, tms->current_k);
+
+ state_save_register_item("tms5110", index, tms->target_energy);
+ state_save_register_item("tms5110", index, tms->target_pitch);
+ state_save_register_item_array("tms5110", index, tms->target_k);
+
+ state_save_register_item("tms5110", index, tms->interp_count);
+ state_save_register_item("tms5110", index, tms->sample_count);
+ state_save_register_item("tms5110", index, tms->pitch_count);
+
+ state_save_register_item_array("tms5110", index, tms->u);
+ state_save_register_item_array("tms5110", index, tms->x);
+
+ state_save_register_item("tms5110", index, tms->RNG);
+
+ return tms;
+}
+
+
+void tms5110_destroy(void *chip)
+{
+ free(chip);
+}
+
+
+
+
+/**********************************************************************************************
+
+ tms5110_reset -- resets the TMS5110
+
+***********************************************************************************************/
+
+void tms5110_reset_chip(void *chip)
+{
+ struct tms5110 *tms = chip;
+
+ /* initialize the FIFO */
+ memset(tms->fifo, 0, sizeof(tms->fifo));
+ tms->fifo_head = tms->fifo_tail = tms->fifo_count = 0;
+
+ /* initialize the chip state */
+ tms->speaking_now = tms->speak_delay_frames = tms->talk_status = 0;
+ tms->CTL_pins = 0;
+ tms->RNG = 0x1fff;
+
+ /* initialize the energy/pitch/k states */
+ tms->old_energy = tms->new_energy = tms->current_energy = tms->target_energy = 0;
+ tms->old_pitch = tms->new_pitch = tms->current_pitch = tms->target_pitch = 0;
+ memset(tms->old_k, 0, sizeof(tms->old_k));
+ memset(tms->new_k, 0, sizeof(tms->new_k));
+ memset(tms->current_k, 0, sizeof(tms->current_k));
+ memset(tms->target_k, 0, sizeof(tms->target_k));
+
+ /* initialize the sample generators */
+ tms->interp_count = tms->sample_count = tms->pitch_count = 0;
+ memset(tms->u, 0, sizeof(tms->u));
+ memset(tms->x, 0, sizeof(tms->x));
+}
+
+
+
+/******************************************************************************************
+
+ tms5110_set_M0_callback -- set M0 callback for the TMS5110
+
+******************************************************************************************/
+
+void tms5110_set_M0_callback(void *chip, int (*func)(void))
+{
+ struct tms5110 *tms = chip;
+ tms->M0_callback = func;
+}
+
+
+/******************************************************************************************
+
+ FIFO_data_write -- handle bit data write to the TMS5110 (as a result of toggling M0 pin)
+
+******************************************************************************************/
+static void FIFO_data_write(struct tms5110 *tms, int data)
+{
+ /* add this bit to the FIFO */
+ if (tms->fifo_count < FIFO_SIZE)
+ {
+ tms->fifo[tms->fifo_tail] = (data&1); /* set bit to 1 or 0 */
+
+ tms->fifo_tail = (tms->fifo_tail + 1) % FIFO_SIZE;
+ tms->fifo_count++;
+
+ if (DEBUG_5110) logerror("Added bit to FIFO (size=%2d)\n", tms->fifo_count);
+ }
+ else
+ {
+ if (DEBUG_5110) logerror("Ran out of room in the FIFO!\n");
+ }
+}
+
+/******************************************************************************************
+
+ extract_bits -- extract a specific number of bits from the FIFO
+
+******************************************************************************************/
+
+static int extract_bits(struct tms5110 *tms, int count)
+{
+ int val = 0;
+
+ while (count--)
+ {
+ val = (val << 1) | (tms->fifo[tms->fifo_head] & 1);
+ tms->fifo_count--;
+ tms->fifo_head = (tms->fifo_head + 1) % FIFO_SIZE;
+ }
+ return val;
+}
+
+static void request_bits(struct tms5110 *tms, int no)
+{
+int i;
+ for (i=0; i<no; i++)
+ {
+ if (tms->M0_callback)
+ {
+ int data = (*tms->M0_callback)();
+ FIFO_data_write(tms, data);
+ }
+ else
+ if (DEBUG_5110) logerror("-->ERROR: TMS5110 missing M0 callback function\n");
+ }
+}
+
+static void perform_dummy_read(struct tms5110 *tms)
+{
+ if (tms->M0_callback)
+ {
+ int data = (*tms->M0_callback)();
+ if (DEBUG_5110) logerror("TMS5110 performing dummy read; value read = %1i\n", data&1);
+ }
+ else
+ if (DEBUG_5110) logerror("-->ERROR: TMS5110 missing M0 callback function\n");
+}
+
+/**********************************************************************************************
+
+ tms5110_status_read -- read status from the TMS5110
+
+ bit 0 = TS - Talk Status is active (high) when the VSP is processing speech data.
+ Talk Status goes active at the initiation of a SPEAK command.
+ It goes inactive (low) when the stop code (Energy=1111) is processed, or
+ immediately(?????? not TMS5110) by a RESET command.
+ TMS5110 datasheets mention this is only available as a result of executing
+ TEST TALK command.
+
+
+***********************************************************************************************/
+
+int tms5110_status_read(void *chip)
+{
+ struct tms5110 *tms = chip;
+ if (DEBUG_5110) logerror("Status read: TS=%d\n", tms->talk_status);
+
+ return (tms->talk_status << 0); /*CTL1 = still talking ? */
+}
+
+
+
+/**********************************************************************************************
+
+ tms5110_ready_read -- returns the ready state of the TMS5110
+
+***********************************************************************************************/
+
+int tms5110_ready_read(void *chip)
+{
+ struct tms5110 *tms = chip;
+ return (tms->fifo_count < FIFO_SIZE-1);
+}
+
+
+
+/**********************************************************************************************
+
+ tms5110_process -- fill the buffer with a specific number of samples
+
+***********************************************************************************************/
+
+void tms5110_process(void *chip, INT16 *buffer, unsigned int size)
+{
+ struct tms5110 *tms = chip;
+ int buf_count=0;
+ int i, interp_period, cliptemp;
+
+ /* if we're not speaking, fill with nothingness */
+ if (!tms->speaking_now)
+ goto empty;
+
+ /* if we're to speak, but haven't started */
+ if (!tms->talk_status)
+ {
+
+ /* a "dummy read" is mentioned in the tms5200 datasheet */
+ /* The Bagman speech roms data are organized in such a way that
+ ** the bit at address 0 is NOT a speech data. The bit at address 1
+ ** is the speech data. It seems that the tms5110 performs a dummy read
+ ** just before it executes a SPEAK command.
+ */
+ perform_dummy_read(tms);
+
+ /* clear out the new frame parameters (it will become old frame just before the first call to parse_frame() ) */
+ tms->new_energy = 0;
+ tms->new_pitch = 0;
+ for (i = 0; i < 10; i++)
+ tms->new_k[i] = 0;
+
+ tms->talk_status = 1;
+ }
+
+
+ /* loop until the buffer is full or we've stopped speaking */
+ while ((size > 0) && tms->speaking_now)
+ {
+ int current_val;
+
+ /* if we're ready for a new frame */
+ if ((tms->interp_count == 0) && (tms->sample_count == 0))
+ {
+
+ /* remember previous frame */
+ tms->old_energy = tms->new_energy;
+ tms->old_pitch = tms->new_pitch;
+ for (i = 0; i < 10; i++)
+ tms->old_k[i] = tms->new_k[i];
+
+
+ /* if the old frame was a stop frame, exit and do not process any more frames */
+ if (tms->old_energy == energytable[15])
+ {
+ /*if (DEBUG_5110) logerror("processing frame: stop frame\n");*/
+ tms->target_energy = tms->current_energy = 0;
+ tms->speaking_now = tms->talk_status = 0;
+ tms->interp_count = tms->sample_count = tms->pitch_count = 0;
+ goto empty;
+ }
+
+
+ /* Parse a new frame into the new_energy, new_pitch and new_k[] */
+ parse_frame(tms);
+
+
+ /* Set old target as new start of frame */
+ tms->current_energy = tms->old_energy;
+ tms->current_pitch = tms->old_pitch;
+ for (i = 0; i < 10; i++)
+ tms->current_k[i] = tms->old_k[i];
+
+
+ /* is this the stop (ramp down) frame? */
+ if (tms->new_energy == energytable[15])
+ {
+ /*logerror("processing frame: ramp down\n");*/
+ tms->target_energy = 0;
+ tms->target_pitch = tms->old_pitch;
+ for (i = 0; i < 10; i++)
+ tms->target_k[i] = tms->old_k[i];
+ }
+ else if ((tms->old_energy == 0) && (tms->new_energy != 0)) /* was the old frame a zero-energy frame? */
+ {
+ /* if so, and if the new frame is non-zero energy frame then the new parameters
+ should become our current and target parameters immediately,
+ i.e. we should NOT interpolate them slowly in.
+ */
+
+ /*logerror("processing non-zero energy frame after zero-energy frame\n");*/
+ tms->target_energy = tms->new_energy;
+ tms->target_pitch = tms->current_pitch = tms->new_pitch;
+ for (i = 0; i < 10; i++)
+ tms->target_k[i] = tms->current_k[i] = tms->new_k[i];
+ }
+ else if ((tms->old_pitch == 0) && (tms->new_pitch != 0)) /* is this a change from unvoiced to voiced frame ? */
+ {
+ /* if so, then the new parameters should become our current and target parameters immediately,
+ i.e. we should NOT interpolate them slowly in.
+ */
+ /*if (DEBUG_5110) logerror("processing frame: UNVOICED->VOICED frame change\n");*/
+ tms->target_energy = tms->new_energy;
+ tms->target_pitch = tms->current_pitch = tms->new_pitch;
+ for (i = 0; i < 10; i++)
+ tms->target_k[i] = tms->current_k[i] = tms->new_k[i];
+ }
+ else if ((tms->old_pitch != 0) && (tms->new_pitch == 0)) /* is this a change from voiced to unvoiced frame ? */
+ {
+ /* if so, then the new parameters should become our current and target parameters immediately,
+ i.e. we should NOT interpolate them slowly in.
+ */
+ /*if (DEBUG_5110) logerror("processing frame: VOICED->UNVOICED frame change\n");*/
+ tms->target_energy = tms->new_energy;
+ tms->target_pitch = tms->current_pitch = tms->new_pitch;
+ for (i = 0; i < 10; i++)
+ tms->target_k[i] = tms->current_k[i] = tms->new_k[i];
+ }
+ else
+ {
+ /*logerror("processing frame: Normal\n");*/
+ /*logerror("*** Energy = %d\n",current_energy);*/
+ /*logerror("proc: %d %d\n",last_fbuf_head,fbuf_head);*/
+
+ tms->target_energy = tms->new_energy;
+ tms->target_pitch = tms->new_pitch;
+ for (i = 0; i < 10; i++)
+ tms->target_k[i] = tms->new_k[i];
+ }
+ }
+ else if (tms->interp_count == 0)
+ {
+ /* interpolate (update) values based on step values */
+ /*logerror("\n");*/
+
+ interp_period = tms->sample_count / 25;
+ tms->current_energy += (tms->target_energy - tms->current_energy) / interp_coeff[interp_period];
+ tms->current_pitch += (tms->target_pitch - tms->current_pitch) / interp_coeff[interp_period];
+
+ /*logerror("*** Energy = %d\n",current_energy);*/
+
+ for (i = 0; i < 10; i++)
+ {
+ tms->current_k[i] += (tms->target_k[i] - tms->current_k[i]) / interp_coeff[interp_period];
+ }
+ }
+
+
+
+
+
+ /* calculate the output */
+
+ if (tms->current_energy == 0)
+ {
+ /* generate silent samples here */
+ current_val = 0x00;
+ }
+ else if (tms->old_pitch == 0)
+ {
+ int bitout, randbit;
+
+ /* generate unvoiced samples here */
+ if (tms->RNG&1)
+ randbit = -64; /* according to the patent it is (either + or -) half of the maximum value in the chirp table */
+ else
+ randbit = 64;
+
+ bitout = ((tms->RNG>>12)&1) ^
+ ((tms->RNG>>10)&1) ^
+ ((tms->RNG>> 9)&1) ^
+ ((tms->RNG>> 0)&1);
+ tms->RNG >>= 1;
+ tms->RNG |= (bitout<<12);
+
+ current_val = (randbit * tms->current_energy) / 256;
+ }
+ else
+ {
+ /* generate voiced samples here */
+ current_val = (chirptable[tms->pitch_count%sizeof(chirptable)] * tms->current_energy) / 256;
+ }
+
+
+ /* Lattice filter here */
+
+ tms->u[10] = current_val;
+
+ for (i = 9; i >= 0; i--)
+ {
+ tms->u[i] = tms->u[i+1] - ((tms->current_k[i] * tms->x[i]) / 32768);
+ }
+ for (i = 9; i >= 1; i--)
+ {
+ tms->x[i] = tms->x[i-1] + ((tms->current_k[i-1] * tms->u[i-1]) / 32768);
+ }
+
+ tms->x[0] = tms->u[0];
+
+
+ /* clipping & wrapping, just like the patent */
+
+ cliptemp = tms->u[0];
+ if (cliptemp > 2047) cliptemp = -2048 + (cliptemp-2047);
+ else if (cliptemp < -2048) cliptemp = 2047 - (cliptemp+2048);
+
+ if (cliptemp > 511)
+ buffer[buf_count] = 127<<8;
+ else if (cliptemp < -512)
+ buffer[buf_count] = -128<<8;
+ else
+ buffer[buf_count] = cliptemp << 6;
+
+ /* Update all counts */
+
+ tms->sample_count = (tms->sample_count + 1) % 200;
+
+ if (tms->current_pitch != 0)
+ tms->pitch_count = (tms->pitch_count + 1) % tms->current_pitch;
+ else
+ tms->pitch_count = 0;
+
+ tms->interp_count = (tms->interp_count + 1) % 25;
+
+ buf_count++;
+ size--;
+ }
+
+empty:
+
+ while (size > 0)
+ {
+ tms->sample_count = (tms->sample_count + 1) % 200;
+ tms->interp_count = (tms->interp_count + 1) % 25;
+
+ buffer[buf_count] = 0x00;
+ buf_count++;
+ size--;
+ }
+}
+
+
+
+
+/******************************************************************************************
+
+ CTL_set -- set CTL pins named CTL1, CTL2, CTL4 and CTL8
+
+******************************************************************************************/
+
+void tms5110_CTL_set(void *chip, int data)
+{
+ struct tms5110 *tms = chip;
+ tms->CTL_pins = data & 0xf;
+}
+
+
+/******************************************************************************************
+
+ PDC_set -- set Processor Data Clock. Execute CTL_pins command on hi-lo transition.
+
+******************************************************************************************/
+
+void tms5110_PDC_set(void *chip, int data)
+{
+ struct tms5110 *tms = chip;
+ if (tms->PDC != (data & 0x1) )
+ {
+ tms->PDC = data & 0x1;
+ if (tms->PDC == 0) /* toggling 1->0 processes command on CTL_pins */
+ {
+ /* the only real commands we handle now are SPEAK and RESET */
+
+ switch (tms->CTL_pins & 0xe) /*CTL1 - don't care*/
+ {
+ case TMS5110_CMD_SPEAK:
+ tms->speaking_now = 1;
+
+ //should FIFO be cleared now ?????
+
+ break;
+
+ case TMS5110_CMD_RESET:
+ tms->speaking_now = 0;
+ tms->talk_status = 0;
+ break;
+
+ default:
+ break;
+ }
+ }
+ }
+}
+
+
+
+/******************************************************************************************
+
+ parse_frame -- parse a new frame's worth of data; returns 0 if not enough bits in buffer
+
+******************************************************************************************/
+
+static void parse_frame(struct tms5110 *tms)
+{
+ int bits, indx, i, rep_flag;
+
+
+ /* count the total number of bits available */
+ bits = tms->fifo_count;
+
+
+ /* attempt to extract the energy index */
+ bits -= 4;
+ if (bits < 0)
+ {
+ request_bits( tms,-bits ); /* toggle M0 to receive needed bits */
+ bits = 0;
+ }
+ indx = extract_bits(tms,4);
+ tms->new_energy = energytable[indx];
+
+
+ /* if the energy index is 0 or 15, we're done */
+
+ if ((indx == 0) || (indx == 15))
+ {
+ if (DEBUG_5110) logerror(" (4-bit energy=%d frame)\n",tms->new_energy);
+
+ /* clear the k's */
+ if (indx == 0)
+ {
+ for (i = 0; i < 10; i++)
+ tms->new_k[i] = 0;
+ }
+
+ /* clear fifo if stop frame encountered */
+ if (indx == 15)
+ {
+ if (DEBUG_5110) logerror(" (4-bit energy=%d STOP frame)\n",tms->new_energy);
+ tms->fifo_head = tms->fifo_tail = tms->fifo_count = 0;
+ //speaking_now = talk_status = 0;
+ }
+ return;
+ }
+
+
+ /* attempt to extract the repeat flag */
+ bits -= 1;
+ if (bits < 0)
+ {
+ request_bits( tms,-bits ); /* toggle M0 to receive needed bits */
+ bits = 0;
+ }
+ rep_flag = extract_bits(tms,1);
+
+ /* attempt to extract the pitch */
+ bits -= 5;
+ if (bits < 0)
+ {
+ request_bits( tms,-bits ); /* toggle M0 to receive needed bits */
+ bits = 0;
+ }
+ indx = extract_bits(tms,5);
+ tms->new_pitch = pitchtable[indx];
+
+
+ /* if this is a repeat frame, just copy the k's */
+ if (rep_flag)
+ {
+ //actually, we do nothing because the k's were already loaded (on parsing the previous frame)
+
+ if (DEBUG_5110) logerror(" (10-bit energy=%d pitch=%d rep=%d frame)\n", tms->new_energy, tms->new_pitch, rep_flag);
+ return;
+ }
+
+
+ /* if the pitch index was zero, we need 4 k's */
+ if (indx == 0)
+ {
+ /* attempt to extract 4 K's */
+ bits -= 18;
+ if (bits < 0)
+ {
+ request_bits( tms,-bits ); /* toggle M0 to receive needed bits */
+ bits = 0;
+ }
+ tms->new_k[0] = k1table[extract_bits(tms,5)];
+ tms->new_k[1] = k2table[extract_bits(tms,5)];
+ tms->new_k[2] = k3table[extract_bits(tms,4)];
+ tms->new_k[3] = k4table[extract_bits(tms,4)];
+
+ /* and clear the rest of the new_k[] */
+ for (i = 4; i < 10; i++)
+ tms->new_k[i] = 0;
+
+ if (DEBUG_5110) logerror(" (28-bit energy=%d pitch=%d rep=%d 4K frame)\n", tms->new_energy, tms->new_pitch, rep_flag);
+ return;
+ }
+
+ /* else we need 10 K's */
+ bits -= 39;
+ if (bits < 0)
+ {
+ request_bits( tms,-bits ); /* toggle M0 to receive needed bits */
+ bits = 0;
+ }
+ tms->new_k[0] = k1table[extract_bits(tms,5)];
+ tms->new_k[1] = k2table[extract_bits(tms,5)];
+ tms->new_k[2] = k3table[extract_bits(tms,4)];
+ tms->new_k[3] = k4table[extract_bits(tms,4)];
+ tms->new_k[4] = k5table[extract_bits(tms,4)];
+ tms->new_k[5] = k6table[extract_bits(tms,4)];
+ tms->new_k[6] = k7table[extract_bits(tms,4)];
+ tms->new_k[7] = k8table[extract_bits(tms,3)];
+ tms->new_k[8] = k9table[extract_bits(tms,3)];
+ tms->new_k[9] = k10table[extract_bits(tms,3)];
+
+ if (DEBUG_5110) logerror(" (49-bit energy=%d pitch=%d rep=%d 10K frame)\n", tms->new_energy, tms->new_pitch, rep_flag);
+
+}
+
+
+
+#if 0
+/*This is an example word TEN taken from the TMS5110A datasheet*/
+static unsigned int example_word_TEN[619]={
+/* 1*/1,0,0,0, 0, 0,0,0,0,0, 1,1,0,0,0, 0,0,0,1,0, 0,1,1,1, 0,1,0,1,
+/* 2*/1,0,0,0, 0, 0,0,0,0,0, 1,0,0,1,0, 0,0,1,1,0, 0,0,1,1, 0,1,0,1,
+/* 3*/1,1,0,0, 0, 1,0,0,0,0, 1,0,1,0,0, 0,1,0,1,0, 0,1,0,0, 1,0,1,0, 1,0,0,0, 1,0,0,1, 0,1,0,1, 0,0,1, 0,1,0, 0,1,1,
+/* 4*/1,1,1,0, 0, 0,1,1,1,1, 1,0,1,0,1, 0,1,1,1,0, 0,1,0,1, 0,1,1,1, 0,1,1,1, 1,0,1,1, 1,0,1,0, 0,1,1, 0,1,0, 0,1,1,
+/* 5*/1,1,1,0, 0, 1,0,0,0,0, 1,0,1,0,0, 0,1,1,1,0, 0,1,0,1, 1,0,1,0, 1,0,0,0, 1,1,0,0, 1,0,1,1, 1,0,0, 0,1,0, 0,1,1,
+/* 6*/1,1,1,0, 0, 1,0,0,0,1, 1,0,1,0,1, 0,1,1,0,1, 0,1,1,0, 0,1,1,1, 0,1,1,1, 1,0,1,0, 1,0,1,0, 1,1,0, 0,0,1, 1,0,0,
+/* 7*/1,1,1,0, 0, 1,0,0,1,0, 1,0,1,1,1, 0,1,1,1,0, 0,1,1,1, 0,1,1,1, 0,1,0,1, 0,1,1,0, 1,0,0,1, 1,1,0, 0,1,0, 0,1,1,
+/* 8*/1,1,1,0, 1, 1,0,1,0,1,
+/* 9*/1,1,1,0, 0, 1,1,0,0,1, 1,0,1,1,1, 0,1,0,1,1, 1,0,1,1, 0,1,1,1, 0,1,0,0, 1,0,0,0, 1,0,0,0, 1,1,0, 0,1,1, 0,1,1,
+/*10*/1,1,0,1, 0, 1,1,0,1,0, 1,0,1,0,1, 0,1,1,0,1, 1,0,1,1, 0,1,0,1, 0,1,0,0, 1,0,0,0, 1,0,1,0, 1,1,0, 0,1,0, 1,0,0,
+/*11*/1,0,1,1, 0, 1,1,0,1,1, 1,0,0,1,1, 1,0,0,1,0, 0,1,1,0, 0,0,1,1, 0,1,0,1, 1,0,0,1, 1,0,1,0, 1,0,0, 0,1,1, 0,1,1,
+/*12*/1,0,0,0, 0, 1,1,1,0,0, 1,0,0,1,1, 0,0,1,1,0, 0,1,0,0, 0,1,1,0, 1,1,0,0, 0,1,0,1, 1,0,0,0, 1,0,0, 0,1,0, 1,0,1,
+/*13*/0,1,1,1, 1, 1,1,1,0,1,
+/*14*/0,1,1,1, 0, 1,1,1,1,0, 1,0,0,1,1, 0,0,1,1,1, 0,1,0,1, 0,1,0,1, 1,1,0,0, 0,1,1,1, 1,0,0,0, 1,0,0, 0,1,0, 1,0,1,
+/*15*/0,1,1,0, 0, 1,1,1,1,0, 1,0,1,0,1, 0,0,1,1,0, 0,1,0,0, 0,0,1,1, 1,1,0,0, 1,0,0,1, 0,1,1,1, 1,0,1, 0,1,0, 1,0,1,
+/*16*/1,1,1,1
+};
+#endif
+