#include <assert.h>
#include "driver.h"
#include "cpu/m6800/m6800.h"
#include "cpu/m6809/m6809.h"
#include "cpu/adsp2100/adsp2100.h"
#include "machine/6821pia.h"
#include "sound/2151intf.h"
#include "sound/hc55516.h"
#include "sound/dac.h"
#include "core.h"
#include "sndbrd.h"
#include "s11.h"
#include "wpc.h"
#include "wmssnd.h"
#ifdef __MINGW32__
 #include <windef.h>
#endif

// Enables some subtle low pass on the DCS output to avoid a bit of noise. 
// As the real HW also has a bunch of lowpass filters, it would be interesting to 
// check the direct output of the DCS chip on real hardware if it also features a 
// bit of noise or not at that stage (e.g. before all the filters).
//
// [MJR - Yes, it would definitely have lots of noise, namely quantization noise,
// given that a DAC is involved and the sampling rate is fairly low.  The real 
// boards have a chain of four Sallen-Key low-pass filters with a cutoff frequency
// of 18875 Hz.  "Cutoff" in this context doesn't mean a brick wall; it's just the
// corner frequency in the low-pass rolloff curve, which is pretty shallow for 
// Sallen-Key filters.  They use four chained filters to steepen the curve, to cut
// out most of the output above 18875 Hz, which is probably right around the Nyquist
// limit for the sampling rate they're using.
#define DCS_LOWPASS 

#ifdef DCS_LOWPASS
 #include "sound/filter.h"
#endif


// The PREDCS_FIRQ_HACK explained and fixed - MJR 5/3/2019
//
// It took 16 years for someone to look into this, but someone finally did!
//
// The reason for the pitch change observed in the pre-DCS hack (see below) was NOT that
// the FIRQ interrupt rate changed in the absence of YM2151 music.  The YM2151 emulation
// kept cranking out timer A interrupts at a steady pace, as it should have.  The problem,
// rather, was that a certain percentage of the properly generated interrupts were 
// "missed".
//
// What's a missed interrupt?  To understand that, we have to understand how the 6809
// processes interrupts.  The 6809 handles IRQ and FIRQ lines by latching them at the 
// start of each instruction cycle.  If IRQ or FIRQ is ON (in hardware, low), AND the 
// corresponding CC "inhibit interrupt" flag bit is CLEAR, the processor takes the 
// interrupt.  If a line is ON and the corresponding CC inhibit interrupt flag bit is 
// SET, the processor ignores the interrupt line status for the duration of this 
// instruction cycle.  It checks again at the start of the next instruction cycle, 
// latching the new status of the line.  The latch status is renewed on each instruction
// cycle.  That means that if an interrupt line turns ON during a section of code where
// the "inhibit" flag is SET, and then turns OFF again before the "inhibit" flag is 
// CLEARed, the signal on the line will never cause a CPU interrupt.  The interrupt
// is missed.  It's as though the electrical IRQ/FIRQ signal never happened.
//
// That's *what* was happening.  In the absence of FM music, we missed about 15% of
// timer A interrupts from the YM2151.  When FM music *was* playing, we missed about 
// 1% of them.  The slow-down effect was actually occurring ALL THE TIME; it was just
// so small when FM music was playing that it was practically inaudible and no one
// noticed.  I only noticed because I instrumented the code and observed the ratio of
// missed interrupts directly.
//
// *Why* it was happening is pretty subtle, but once you see the reason, it becomes
// clear why the missed interrupt ratio depends on whether or not FM music playing.
// The problem isn't a core MAME timing bug as SJE supposed; it's an inaccuracy in 
// the YM2151 emulation, specifically a tiny detail of the original hardware's timing 
// that wasn't faithfully reproduced in the emulation.  It turns out that the Williams 
// DCS89 sound board software is written in such a way that it relies on this particular
// tiny detail.  I think it's arguable that the bug is actually in the Williams DCS89 
// sound board software, because to modern eyes it looks like a classic race condition. 
// I'd be willing to believe that the Williams programmer who wrote this code wrote 
// this part intentionally, based on the known timing of the YM2151 hardware, but I 
// tend to think not; I tend to think that it was just a bad bit of design that
// happened to work because of the hardware timing.
//
// Let's look at the Williams sound board code in question.  In the Williams code,
// the main idle loop looks something like this:
//
//  do
//    check for and process any commands received from the main board
//    process FM command output
//    reset the YM2115 clock settings
//  forever
//
// That "reset the YM2115 clock settings" part is responsible for all of our woes.
// I'm not entirely sure why that's even there, but I'm guessing it was for fault 
// tolerance, to make sure that the YM clock keeps running even if something gets 
// screwed up elsewhere in the software and we somehow manage to get the YM chip
// into a wedged state.  The YM chip has some twitchy command timing rules, so maybe
// they found that commands would sometimes get lost on the wire, and they wanted 
// to make sure that the clock kept running come hell or high water.  The YM clock
// is critical to the whole sound system, since it drives the sample output process 
// for the DAC and HC55516 streams; if it stops, pretty much everything else stops.
//
// Drilling down into the "reset" code, we have this 6809 snippet:
//
//     ORCC $50    ; IF|II (inhibit FIRQ + IRQ)
// L0: LDA [2401]  ; YM2151 status register
//     BMI L0      ; loop until ready
//     LDA $14     ; register $14 - clock settings
//     STA [2400]  ; write YM2151 address
// L1: LDA [2401]  ; read YM2151 status
//     BMI L1      ; loop until ready
//     LDA $15     ; start timer A, enable timer A IRQ, clear timer A IRQ
//     STA [2401]  ; write YM2151 data register
//     ANDCC $AF   ; IF|II (enable FIRQ + IRQ)
//
// As you can see, this section of code runs with the CC "inhibit interrupts"
// flags set.   They're turning off interrupts beacuse it's absolutely required
// that we do these register writes to the YM chip atomically.  We have to make
// two writes, one to send the register address and one to send the data byte.
// If we got interrupted in the middle of this, the interrupt handler could
// send its own address/data sequence, which would leave the YM chip in a state
// where it's not ready to receive the second half of our write.  So we have to
// make sure that we can't get interrupted during this write.  They got this
// part right via the ORCC $50 at the top, which disables interrupts until
// further notice.   As discussed above, this means that the processor will 
// ignore any IRQ or FIRQ electrical signals during this stretch of code.
//
// The second-to-last instruction, STA [2401], is where we do the actual clock 
// reset: that writes $15 to the clock control register on the YM, which does 
// three things to timer A.  It starts the timer (or simply leaves it running,
// if it was running already), enables the timer's interrupt signal (so that
// the timer interrupt occurs whenever the timer rolls over, which is really
// the whole point), and clears its current interrupt flag (which turns off the
// IRQ output from the YM chip, and thus the FIRQ input to the 6809, if it was
// previously on).
//
// Now, suppose that YM timer A fires *while this code is running*.  The YM turns
// on its IRQ output line, which is connected to the 6809's FIRQ input line.  
// Normally, this would send us directly into the FIRQ interrupt handler code in
// the Williams software.  But during this little block, interrupts are disabled,
// so as each instruction starts, the CPU will observe the FIRQ line but will do
// nothing about it, since it sees that IF (inhibit FIRQ) is set in CC.  When
// we reach that penultimate instruction, STA [2401], we're telling the YM to
// clear its Timer A interrupt flag, which in turns makes the YM turn OFF its
// IRQ output and our FIRQ input.  We then reach the next instruction, where we
// re-enable interrupts.  At that point, the CPU will be ready to take the FIRQ.
// But we just turned it off!!!  That interrupt is missed.  Sorry, have to wait
// for the next one!
//
// What are the odds, though, right?  Well, it turns out that they're pretty
// good - about 15% when no FM commands are being sent.  And it even happens
// when FM samples AREN'T being sent, but it drops to about 1% probability.
// The reason for the difference - and why this APPEARED to be related to the
// FM playback - is pretty simple now that we see how the main loop is laid out. 
// When FM is idle, the main loop really doesn't have much else to do other 
// than executing that timer reset code over and over, so we spend A LOT of
// time there.  When FM is running, the part of the loop that says "process
// FM command output" takes up a lot more time, so the portion of time we 
// spend in the clock reset block decreases, and our ratio of missed interrupts
// drops accordingly.
//
// Okay, now that we understand the problem, the fix is clear: we just have to
// fix the original Williams code!  Um... no.  That defeats the whole purpose
// of emulation, which is to run the original software exactly as it was
// written.  Plus it would be a huge amount of work to find the right code
// section and patch it in all of the different ROMs.  So we want to fix the
// emulator, not the "emulatee".  More importantly, perhaps, we can see that
// the emulator is actually at fault here, not the original code, because this
// problem obviously didn't happen on the real hardware.  People would have 
// noticed.  So given that it doesn't happen on the hardware, why does it
// happen in the emulator?  Because the emulator, being an emulator, is an 
// imperfect imitation of the real thing.  Some of the details aren't perfect
// replicas.  In this case, the little detail that the emulator gets wrong is
// the finite amount of time that the STA [2401] operation takes before the
// change in FIRQ status propagates to the physical pin.  In the emulation, 
// this occurred instantaneously.  In the real hardware, there's a delay
// time.  It's not due to the time it takes electrons to go down the wire
// or anything silly like that; it's due to the internal architecture of
// the YM2151 chip and the amount of time it takes to process commands.
//
// Why does a delay in the IRQ output response matter here?  Because the
// Williams software clearly depends on there being a delay.  The ROM code
// enables interrupts on the next instruction after writing the register.  If 
// we count clock cycles, we see that it takes 3 clocks to perform the ANDCC, 
// so we can expect the CPU to sample the FIRQ input line again about 2us 
// after the register write.  As long as the YM doesn't drop the IRQ output
// signal for 2us or longer after the register write, the 6809 will see any
// FIRQ signal that came into effect while the "interrupts off" section was
// running, so we won't lose such FIRQs.  The immediate juxtaposition of the
// register write and interrupt restore makes it believable that this was
// actually intentional.  (My friend the chip designer tells me that it was
// quite common back in the 8-bit days for software engineers to take this
// kind of cavalier approach to race conditions, because the hardware back
// then was so preditable about timing and clocks were relatively slow.
// To modern eyes, accustomed as we are to pipelined architectures with
// timing that even the designers can't precisely predict, it looks like a
// blatant race condition bug.  But the 80s were a simpler time.)
//
// I can't find anything in the YM data sheet or application guide about the
// timing of the IRQ output signal change after writing register $14.  But
// the data sheet does document the amount of time it takes for the chip to
// finish processing ANY register write: 68 cycles of its 3.58MHz clock, or
// about 19us.  This is probably the time it takes for the thing to process
// some big internal shift register, so my bet is that the new registers are
// all latched at once 68 cycles after a write, and the EFFECTS of those new
// register settings propagate out to the rest of the chip some number of 
// clocks after that.  But even if some registers update faster than others, 
// I think we can safely infer from the Williams code that the IRQ change
// must take much longer than 2us - long enough that there's no risk from
// little clock wobbles that it'll sometimes be shorter than 2us.  Would
// a 5X margin be safe enough?  Okay, good, let's call it 10us.  
//
// The correct fix, then, is to change the YM2151 emulator code to add a 
// 10us delay on an IRQ CLEAR change taking effect.  With this change in
// effect, we can drop the 2400 Hz timer hack.
//
// Let's take a moment to look at why that 2400 Hz hack helped in the first
// place.  The problem is that we're losing a lot of interrupts.  The
// hack helped by forcing in a bunch of new ones to compensate for the
// original ones that got lost.  The YM interrupts happen every 178us, or
// about 5600 Hz, and the 2400 Hz timer was really just a 1200 Hz "set"
// cycle (as the "clear" half of its cycle had no effect).  Just like
// the original interrupts, some number of the "fake" interrupts got 
// lost, for the same reasons.  So the hack effectively added back maybe
// 850 Hz worth of interrupts.  You can see how the combination of the 
// real and fake interrupts averaged out to close to the original number 
// of interrupts that the Williams software was actually written for. 
//
// Given that the hack more or less restores the right interrupt count,
// why bother with something more elaborate?  Well, for one thing, it's
// just cleaner from a software design perspective to fix the problem at
// its source, in the YM code.  And it's more faithful to the hardware
// we're trying to emulate, which is surely a good thing.  But the real
// advantage of the YM fix is that it gets the interrupt PACING right.
// The hack got the total interrupt COUNT right, averaged over time,
// but due to the random nature of the missed interrupts, the timing
// of the interrupts as wildly erratic.  The hack didn't get rid of
// the missed interrupts; it just jammed in a bunch of new ones to
// make up for the missed ones.  The result was that the clock that
// drove the DAC and HC55516 was inconsistent.  I observed a range of
// a factor of about 30 in sample clock times to those chips.  That was
// part of the reason that the HC55516 output sounded so terrible in the
// past.  (A small part, though, as it turns out; the real culprit there
// is a whole different story, which you can find more about in the 
// HC55516 emulation code.)  Fixing the problem in the YM code makes
// the clock consistent like it was designed to be.
//
#define PREDCS_FIRQ_HACK_FIXED

//This awful hack WAS here to prevent a bug that caused the speech pitch to be too low on pre-dcs games when
//the YM2151 is not outputing music. In the hardware the YM2151's Timer A is set to control the FIRQ of the sound cpu 6809.
//The 6809 will output CVSD speech data based on the speed of the FIRQ. The faster the speed, the higher the
//pitch. For some reason [now known - see above], when the YM2151 is not outputting sound, the FIRQ rate goes down..
//[Or so it seemed - in fact the FIRQ rate was the same, but the Williams 6809 ROM code was written in such a way
//that a high percentage of interrupts occurred when interrupts were masked, making it seem like they weren't
//occuring.]  Def. some kind of MAME core bug with timing [turns out not really: it was actually an obscure 
//hardware detail about the YM2151 that wasn't being emulated properly and that the Williams sound board ROM 
//code implicitly depends upon - see above], but I can't find it. I really hope someone can fix this hack 
//someday..SJE 09/17/03 [wish granted! MJR 5/3/19]
#ifndef PREDCS_FIRQ_HACK_FIXED
#define PREDCS_FIRQ_HACK  // no longer needed! see above
#endif

#ifndef MIN
#define MIN(x,y) ((x)<(y)?(x):(y))
#endif

/*----------------------
/    System 3 - 7
/-----------------------*/
#define S67S_PIA0 6

/* sound board interface */
static void s67s_init(struct sndbrdData *brdData);
static WRITE_HANDLER(s67s_cmd_w);
static WRITE_HANDLER(s67s_ctrl_w);
static void s67s_diag(int button);

const struct sndbrdIntf s67sIntf = {
  "WMSS67", s67s_init, NULL, s67s_diag, s67s_cmd_w, s67s_cmd_w, NULL, s67s_ctrl_w, NULL, SNDBRD_NOCTRLSYNC
};

/* machine interface */
static MEMORY_READ_START(s67s_readmem )
  { 0x0000, 0x007f, MRA_RAM },
  { 0x0400, 0x0403, pia_r(S67S_PIA0) },
  { 0x3000, 0x7fff, MRA_ROM },
  { 0x8400, 0x8403, pia_r(S67S_PIA0) },
  { 0xb000, 0xffff, MRA_ROM },
MEMORY_END

static MEMORY_WRITE_START(s67s_writemem )
  { 0x0000, 0x007f, MWA_RAM },
  { 0x0400, 0x0403, pia_w(S67S_PIA0) },
  { 0x8400, 0x8403, pia_w(S67S_PIA0) },
MEMORY_END
static struct DACinterface      s67s_dacInt     = { 1, { 50 }};
static struct hc55516_interface s67s_hc55516Int = { 1, { 100 }, HC55516_FILTER_C8228 };

MACHINE_DRIVER_START(wmssnd_s67s)
  MDRV_CPU_ADD(M6808, 3579545./4.)
  MDRV_CPU_FLAGS(CPU_AUDIO_CPU)
  MDRV_CPU_MEMORY(s67s_readmem, s67s_writemem)
  MDRV_INTERLEAVE(50)
  MDRV_SOUND_ADD(DAC, s67s_dacInt)
  MDRV_SOUND_ADD(HC55516, s67s_hc55516Int)
  MDRV_SOUND_ADD(SAMPLES, samples_interface)
MACHINE_DRIVER_END

static struct {
  struct sndbrdData brdData;
  UINT8 sndCmd;
  UINT8 sndBitsA;
} s67slocals;

static READ_HANDLER(snd_r) {
  return s67slocals.sndCmd;
}

static void s67s_piaIrq(int state);
static const struct pia6821_interface s67s_pia = {
 /* PIA0  (0400)
    PA0-7  DAC
    PB0-7  Sound input
    CB1    Sound input != 0x1f
    CB2    Speech clock
    CA2    Speech data
    CA1    NC */
 /* in  : A/B,CA/B1,CA/B2 */ 0, snd_r, 0, 0, 0, 0,
 /* out : A/B,CA/B2       */ DAC_0_data_w, 0, hc55516_0_digit_w, hc55516_0_clock_w,
 /* irq : A/B             */ s67s_piaIrq, s67s_piaIrq
};

static void s67s_init(struct sndbrdData *brdData) {
  s67slocals.brdData = *brdData;
  pia_config(S67S_PIA0, PIA_STANDARD_ORDERING, &s67s_pia);
}

static WRITE_HANDLER(s67s_ctrl_w) {
  if (s67slocals.brdData.subType & (16 | 8)) {
    if (s67slocals.brdData.subType & 8) {      // + World Cup
      s67slocals.sndBitsA = ((data & 0x40) >> 1);
      s67slocals.sndCmd = (s67slocals.sndCmd & 0x9f) | s67slocals.sndBitsA | ((core_getDip(0) & 0x02) ? 0x00 : 0x40);
    }
    if (s67slocals.brdData.subType & 16) {     // + Disco Fever
      s67slocals.sndBitsA = ((data & 0x10) << 3);
      s67slocals.sndCmd = (s67slocals.sndCmd & 0x3f) | s67slocals.sndBitsA | ((core_getDip(0) & 0x02) ? 0x00 : 0x40);
    }
    pia_set_input_b(S67S_PIA0, s67slocals.sndCmd);
    pia_set_input_cb1(S67S_PIA0, !((s67slocals.sndCmd & 0xbf) == 0xbf));
  } else {
    s67slocals.sndBitsA = data;
  }
}

static WRITE_HANDLER(s67s_cmd_w) {
  if (s67slocals.brdData.subType & 1) { // don't use sound dips
    s67slocals.sndCmd = data & 0x7f;
  } else if (s67slocals.brdData.subType & 2) { // Contact, Phoenix, World Cup, Disco Fever and Disco Fever prototype
    s67slocals.sndCmd = 0x30 | (data & 0x0f) | ((data & 0x10) << 3) | ((core_getDip(0) & 0x02) ? 0x00 : 0x40);
    if (s67slocals.brdData.subType & 4)      // + World Cup, Disco Fever and Disco Fever prototype
      s67slocals.sndCmd = (s67slocals.sndCmd & 0xef) | ((data & 0x40) >> 2);
    if (s67slocals.brdData.subType & 8)      // + World Cup
      s67slocals.sndCmd = (s67slocals.sndCmd & 0xdf) | s67slocals.sndBitsA;
    if (s67slocals.brdData.subType & 16)     // + Disco Fever
      s67slocals.sndCmd = (s67slocals.sndCmd & 0x7f) | s67slocals.sndBitsA;
  } else {
    s67slocals.sndCmd = (data & 0x1f) | (core_getDip(0)<<5);
  }
//  logerror("s67s_cmd_w  data=%02x  sndCmd=%02x  sndBitsA=%02x  SndBrdSW2=%02x  CB1_old=%02x\n", data, s67slocals.sndCmd, s67slocals.sndBitsA, (core_getDip(0) << 5), pia_6_cb1_r(0) );
  pia_set_input_b(S67S_PIA0, s67slocals.sndCmd);
  if (s67slocals.brdData.subType & 1) {
    pia_set_input_cb1(S67S_PIA0, !((s67slocals.sndCmd & 0x7f) == 0x7f));
  } else if (s67slocals.brdData.subType & 2) {
    pia_set_input_cb1(S67S_PIA0, !((s67slocals.sndCmd & 0xbf) == 0xbf));
  } else {
    pia_set_input_cb1(S67S_PIA0, !((s67slocals.sndCmd & 0x1f) == 0x1f));
  }
}
static void s67s_diag(int button) {
  cpu_set_nmi_line(s67slocals.brdData.cpuNo, button ? ASSERT_LINE : CLEAR_LINE);
}

static void s67s_piaIrq(int state) {
  cpu_set_irq_line(s67slocals.brdData.cpuNo, M6808_IRQ_LINE, state ? ASSERT_LINE : CLEAR_LINE);
}

/*----------------------------
/  S11 CPU board sound
/-----------------------------*/
#define S11S_PIA0  6
#define S11S_BANK0 1
#define S11S_BANK1 2

/* sound board interface */
static void s11s_init(struct sndbrdData *brdData);
static void s11s_diag(int button);
static WRITE_HANDLER(s11s_manCmd_w);
static WRITE_HANDLER(s11s_bankSelect);
const struct sndbrdIntf s11sIntf = {
  "WMSS11", s11s_init, NULL, s11s_diag, s11s_manCmd_w, soundlatch_w, NULL, CAT3(pia_,S11S_PIA0,_ca1_w), NULL
};
/* machine interface */
static MEMORY_READ_START(s9s_readmem)
  { 0x0000, 0x0fff, MRA_RAM},
  { 0x2000, 0x2003, pia_r(S11S_PIA0)},
  { 0x8000, 0xffff, MRA_ROM}, /* U22 */
MEMORY_END

static WRITE_HANDLER(pia_snd_w) {
  if (core_gameData->hw.gameSpecific1 & S9_BREAKPIA) { // no idea why but the PIA A port only has 7 bits wired for scrazy!?
    pia_write(S11S_PIA0, offset, offset ? data : data & 0x7f);
  } else {
    pia_write(S11S_PIA0, offset, data);
  }
}

static MEMORY_WRITE_START(s9s_writemem)
  { 0x0000, 0x0fff, MWA_RAM },
  { 0x2000, 0x2003, pia_snd_w},
MEMORY_END

static struct DACinterface      s9s_dacInt     = { 1, { 50 }};
static struct hc55516_interface s9s_hc55516Int = { 1, { 100 }, HC55516_FILTER_C8228 };

MACHINE_DRIVER_START(wmssnd_s9s)
  MDRV_CPU_ADD(M6808, 1000000)
  MDRV_CPU_FLAGS(CPU_AUDIO_CPU)
  MDRV_CPU_MEMORY(s9s_readmem, s9s_writemem)
  MDRV_INTERLEAVE(50)
  MDRV_SOUND_ADD(DAC,    s9s_dacInt)
  MDRV_SOUND_ADD(HC55516,s9s_hc55516Int)
  MDRV_SOUND_ADD(SAMPLES, samples_interface)
MACHINE_DRIVER_END

static MEMORY_READ_START(s11s_readmem)
  { 0x0000, 0x0fff, MRA_RAM},
  { 0x2000, 0x2003, pia_r(S11S_PIA0) },
  { 0x8000, 0xbfff, MRA_BANKNO(S11S_BANK0)}, /* U22 */
  { 0xc000, 0xffff, MRA_BANKNO(S11S_BANK1)}, /* U21 */
MEMORY_END
static MEMORY_WRITE_START(s11s_writemem)
  { 0x0000, 0x0fff, MWA_RAM },
  { 0x1000, 0x1000, s11s_bankSelect},
  { 0x2000, 0x2003, pia_w(S11S_PIA0)},
MEMORY_END

static void s11cs_ym2151IRQ(int state);
static struct DACinterface      s11xs_dacInt2     = { 2, { 15, 15 }};
static struct hc55516_interface s11b2s_hc55516Int = { 1, { 100 }, HC55516_FILTER_SYS11 };
static struct hc55516_interface s11xs_hc55516Int2 = { 2, { 100, 100 }, HC55516_FILTER_SYS11 };

MACHINE_DRIVER_START(wmssnd_s11s)
  MDRV_CPU_ADD(M6808, 1000000)
  MDRV_CPU_FLAGS(CPU_AUDIO_CPU)
  MDRV_CPU_MEMORY(s11s_readmem, s11s_writemem)
  MDRV_INTERLEAVE(50)
  MDRV_SOUND_ADD(DAC,    s9s_dacInt)
  MDRV_SOUND_ADD(HC55516,s9s_hc55516Int)
  MDRV_SOUND_ADD(SAMPLES, samples_interface)
MACHINE_DRIVER_END

MACHINE_DRIVER_START(wmssnd_s11xs)
  MDRV_IMPORT_FROM(wmssnd_s11cs)
  MDRV_CPU_ADD(M6808, 1000000)
  MDRV_CPU_FLAGS(CPU_AUDIO_CPU)
  MDRV_CPU_MEMORY(s11s_readmem, s11s_writemem)
  MDRV_INTERLEAVE(50)
  MDRV_SOUND_REPLACE("dac",  DAC,    s11xs_dacInt2)
  MDRV_SOUND_REPLACE("cvsd", HC55516,s11xs_hc55516Int2)
MACHINE_DRIVER_END

MACHINE_DRIVER_START(wmssnd_s11b2s)
  MDRV_IMPORT_FROM(wmssnd_s11js)
  MDRV_CPU_ADD(M6808, 1000000)
  MDRV_CPU_FLAGS(CPU_AUDIO_CPU)
  MDRV_CPU_MEMORY(s11s_readmem, s11s_writemem)
  MDRV_INTERLEAVE(50)
  MDRV_SOUND_ADD_TAG("dac", DAC,    s11xs_dacInt2)
  MDRV_SOUND_ADD_TAG("cvsd",HC55516,s11b2s_hc55516Int)
MACHINE_DRIVER_END

static void s11s_piaIrq(int state);
static const struct pia6821_interface s11s_pia[] = {{
 /* PIA 0 (sound 2000) S11 */
 /* PA0 - PA7 (I) Sound Select Input (soundlatch) */
 /* PB0 - PB7 DAC */
 /* CA1       (I) Sound H.S */
 /* CB1       (I) 1ms */
 /* CA2       55516 Clk */
 /* CB2       55516 Dig */
 /* subType 0 and 4 for S9 and S11S */
 /* in  : A/B,CA/B1,CA/B2 */ soundlatch_r, 0, PIA_UNUSED_VAL(0), 0, 0, 0,
 /* out : A/B,CA/B2       */ 0, DAC_0_data_w, hc55516_0_clock_w, hc55516_0_digit_w,
 /* irq : A/B             */ s11s_piaIrq, s11s_piaIrq
},{
 /* subType 1 for S11X */
 /* in  : A/B,CA/B1,CA/B2 */ soundlatch_r, 0, 0, 0, 0, 0,
 /* out : A/B,CA/B2       */ 0, DAC_1_data_w, hc55516_1_clock_w, hc55516_1_digit_w,
 /* irq : A/B             */ s11s_piaIrq, s11s_piaIrq
},{
 /* subType 2 for S11B2 */
 /* in  : A/B,CA/B1,CA/B2 */ soundlatch_r, 0, 0, 0, 0, 0,
 /* out : A/B,CA/B2       */ 0, DAC_1_data_w, hc55516_0_clock_w, hc55516_0_digit_w,
 /* irq : A/B             */ s11s_piaIrq, s11s_piaIrq
}};

static struct {
  struct sndbrdData brdData;
} s11slocals;

static void s11s_init(struct sndbrdData *brdData) { // also Sys9 games use this one!
  s11slocals.brdData = *brdData;
  pia_config(S11S_PIA0, PIA_STANDARD_ORDERING, &s11s_pia[s11slocals.brdData.subType & 3]);
  if (s11slocals.brdData.subType) {
    cpu_setbank(S11S_BANK0, s11slocals.brdData.romRegion+0xc000);
    cpu_setbank(S11S_BANK1, s11slocals.brdData.romRegion+0x4000);
  }

  if (core_gameData->gen == GEN_S9) {
	// For S9 games, turn up the HC gain slightly. Note that we can't use
	// hw.gameSpecific2 to encode custom equalization for S9, because it's
    // already used for other purposes.  (Or at least was at some point; Space 
	// Shuttle defines a non-zero value there.  I suspect this is vestigial
	// because I can't find any references anywhere that actually use it.)
	hc55516_set_gain(0, 1.5);
  }
  else {
    // For S11 games, use hw.gameSpecific2 to encode game-specific custom equalization.
	int hcgain = (core_gameData->hw.gameSpecific2 & 0x1ffff);
	int ymvol = ((core_gameData->hw.gameSpecific2) >> 18) & 0x7f;
	int dacvol = ((core_gameData->hw.gameSpecific1) >> 25) & 0x7f;

	// The system 11 games sound better with the HC gain turned up a bit by default.
	if (hcgain == 0)
	  hcgain = 150;

    if (hcgain != 0)
      hc55516_set_gain(0, hcgain / 100.0);
    if (ymvol != 0)
	  YM2151_set_mixing_levels(0, ymvol, ymvol);
    if (dacvol != 0)
	  DAC_set_mixing_level(0, dacvol);
  }
}
static WRITE_HANDLER(s11s_manCmd_w) {
  soundlatch_w(0, data); pia_set_input_ca1(S11S_PIA0, 1); pia_set_input_ca1(S11S_PIA0, 0);
}
static WRITE_HANDLER(s11s_bankSelect) {
  cpu_setbank(S11S_BANK0, s11slocals.brdData.romRegion + 0x8000+((data&0x01)<<14));
  cpu_setbank(S11S_BANK1, s11slocals.brdData.romRegion + 0x0000+((data&0x02)<<13));
}

static void s11s_piaIrq(int state) {
  cpu_set_irq_line(s11slocals.brdData.cpuNo, M6808_IRQ_LINE, state ? ASSERT_LINE : CLEAR_LINE);
}

static void s11s_diag(int button) {
  cpu_set_nmi_line(s11slocals.brdData.cpuNo, button ? ASSERT_LINE : CLEAR_LINE);
}

/*--------------------------
/ Pennant Fever sound board.
/ Thanks to Destruk for
/ buying the schematics! :)
/---------------------------*/
#define S9P_PIA0    6

static struct {
  struct sndbrdData brdData;
} s9plocals;

static WRITE_HANDLER(s9p_hs_w) { pia_set_input_ca1(0, data); }
static WRITE_HANDLER(ext_hs_w) { pia_set_input_ca1(S9P_PIA0, data); }
static void s9p_piaIrq(int state) {
  cpu_set_irq_line(s9plocals.brdData.cpuNo, M6808_IRQ_LINE, state ? ASSERT_LINE : CLEAR_LINE);
}

static const struct pia6821_interface s9p_pia = {
 /* PIA 0 (4000) */
 /* PA0 - PA7 CPU interface (MDx) */
 /* PB0 - PB7 DAC */
 /* in  : A/B,CA/B1,CA/B2 */
  soundlatch_r, 0, 0, 0, 0, 0,
 /* out : A/B,CA/B2       */
  0, DAC_0_data_w, s9p_hs_w, 0,
 /* irq : A/B             */
  s9p_piaIrq, s9p_piaIrq
};

static void s9p_init(struct sndbrdData *brdData) {
  s9plocals.brdData = *brdData;
  pia_config(S9P_PIA0, PIA_STANDARD_ORDERING, &s9p_pia);
}

static void s9p_diag(int state) {
  cpu_set_nmi_line(s9plocals.brdData.cpuNo, state ? ASSERT_LINE : CLEAR_LINE);
}

static MEMORY_READ_START(s9p_readmem)
  { 0x0000, 0x00ff, MRA_RAM },
  { 0x4000, 0x4003, pia_r(S9P_PIA0) },
  { 0xc000, 0xffff, MRA_ROM },
MEMORY_END

static MEMORY_WRITE_START(s9p_writemem)
  { 0x0000, 0x00ff, MWA_RAM },
  { 0x4000, 0x4003, pia_w(S9P_PIA0) },
MEMORY_END

static struct DACinterface      s9p_dacInt      = { 1, { 60 }};

const struct sndbrdIntf s9psIntf = {
  "WMSS9P", s9p_init, NULL, s9p_diag, soundlatch_w, soundlatch_w, NULL, ext_hs_w
};

MACHINE_DRIVER_START(wmssnd_s9ps)
  MDRV_CPU_ADD(M6808, 1000000)
  MDRV_CPU_FLAGS(CPU_AUDIO_CPU)
  MDRV_CPU_MEMORY(s9p_readmem, s9p_writemem)
  MDRV_INTERLEAVE(50)
  MDRV_SOUND_ADD_TAG("dac",  DAC,    s9p_dacInt)
  MDRV_SOUND_ADD(SAMPLES, samples_interface)
MACHINE_DRIVER_END

/*--------------------------
/    System 11C sound board
/---------------------------*/
#define S11CS_PIA0    7
#define S11CS_BANK0   4

static void s11cs_piaIrqA(int state);
static void s11cs_piaIrqB(int state);
static WRITE_HANDLER(s11cs_pia0ca2_w);
static WRITE_HANDLER(s11cs_pia0cb2_w);
static WRITE_HANDLER(s11cs_rombank_w);
static WRITE_HANDLER(s11cs_manCmd_w);
static void s11cs_init(struct sndbrdData *brdData);

static struct {
  struct sndbrdData brdData;
  int ignore;
} s11clocals;

static WRITE_HANDLER(cslatch2_w) {
  if (!s11clocals.ignore)
    soundlatch2_w(offset, data);
  else s11clocals.ignore--;
}

const struct sndbrdIntf s11csIntf = {
  "WMSS11C", s11cs_init, NULL, NULL, s11cs_manCmd_w,
  cslatch2_w, soundlatch3_r,
  CAT3(pia_,S11CS_PIA0,_cb1_w), soundlatch3_r
};

static MEMORY_READ_START(s11cs_readmem)
  { 0x0000, 0x1fff, MRA_RAM },
  { 0x2001, 0x2001, YM2151_status_port_0_r }, /* 2001-2fff odd */
  { 0x4000, 0x4003, pia_r(S11CS_PIA0) },      /* 4000-4fff */
  { 0x8000, 0xffff, MRA_BANKNO(S11CS_BANK0) },
MEMORY_END

static MEMORY_WRITE_START(s11cs_writemem)
  { 0x0000, 0x1fff, MWA_RAM },
  { 0x2000, 0x2001, YM2151_word_0_w },              /* 2000-2ffe even *//* 2001-2fff odd */
  { 0x4000, 0x4003, pia_w(S11CS_PIA0) },            /* 4000-4fff */
  { 0x6000, 0x6000, hc55516_0_digit_clock_clear_w },/* 6000-67ff */
  { 0x6800, 0x6800, hc55516_0_clock_set_w },        /* 6800-6fff */
  { 0x7800, 0x7800, s11cs_rombank_w },              /* 7800-7fff */
  { 0x8000, 0xffff, MWA_NOP },
MEMORY_END

// Mixing volume levels for System 11. [mjr 8/2019]
//
// PinMAME's traditional mixing levels are 100% volume on the HC55516 (so 
// it's effectively the baseline), 50% on the DAC, and 20% on the YM2151.
//
// However, with the 5/2019 changes to the HC55516 emulator, the HC sounds
// quieter than it used to, so those values are no longer in balance, at
// least subjectively by ear.  My first pass at this had them at 100/50/15,
// but at least a few examples are way too quiet on the HC voice audio with
// those settings.  So I'm cranking the DAC and YM2151 down further to
// make the HC55516 sound relatively louder.  It also seems to help to
// crank up the HC55516 gain in s11s_init() - that's a separate way of
// increasing the loudness of the HC55516, by mapping the native dynamic
// range of the HC55516 pulse stream to the MAME PCM stream at greater 
// than 1:1 gain.
//
// (If we picked the levels based on schematics for the original hardware,
// judging by the voltages coming out of the op amp stages, it would look 
// something like this.  The HC55516 has 1.7V peak output and goes through an 
// op-amp stage with 4.19 gain -> 7.1V peak.  The YM2151 outputs 2.5V peak 
// and goes straight through to the output, so it's mixed at about 35% of the 
// HC voltage.  The DAC (IC1408) outputs 4.98V peak and connects straight 
// through as well, so it's mixed at 70% relative to the HC.  So in the
// actual hardware, it seems that the mixing levels relative to the HC are
// actually a bit higher than works for us.  The same analysis seems to 
// yield about the right results subjectively for WPC89, so I'm not sure
// why it doesn't work as well for System 11; maybe I'm misunderstanding
// the schematics, or missing some extra element in the audio chain that
// throws off the balance from what I see at the op-amp level.)
//
// Note that the mix levels can be overridden per game, in case the defaults
// don't sound good for a given game.  See WPCSND_HC55516_LEVELS in wmssnd.h
// for instructions.
static struct DACinterface      s11cs_dacInt      = { 1, { 15 }};
static struct hc55516_interface s11cs_hc55516Int  = { 1, { 100 }, HC55516_FILTER_SYS11 };
static struct YM2151interface   s11cs_ym2151Int = {
	1, 3579545, /* Hz */
	{ YM3012_VOL(8, MIXER_PAN_CENTER, 8, MIXER_PAN_CENTER) },
	{ s11cs_ym2151IRQ }
};

MACHINE_DRIVER_START(wmssnd_s11cs)
  MDRV_CPU_ADD(M6809, 2000000)
  MDRV_CPU_FLAGS(CPU_AUDIO_CPU)
  MDRV_CPU_MEMORY(s11cs_readmem, s11cs_writemem)
  MDRV_INTERLEAVE(50)
  MDRV_SOUND_ADD(YM2151, s11cs_ym2151Int)
  MDRV_SOUND_ADD_TAG("dac",  DAC,    s11cs_dacInt)
  MDRV_SOUND_ADD_TAG("cvsd", HC55516,s11cs_hc55516Int)
  MDRV_SOUND_ADD(SAMPLES, samples_interface)
MACHINE_DRIVER_END

static const struct pia6821_interface s11cs_pia = {
 /* PIA 0 (4000) */
 /* PA0 - PA7 DAC */
 /* PB0 - PB7 CPU interface (MDx) */
 /* CA1       YM2151 IRQ */
 /* CB1       (I) CPU interface (MCB2) */
 /* CA2       YM 2151 pin 3 (Reset ?) */
 /* CB2       CPU interface (MCB1) */
 /* in  : A/B,CA/B1,CA/B2 */
  0, soundlatch2_r, 0, 0, 0, 0,
 /* out : A/B,CA/B2       */
  DAC_0_data_w, soundlatch3_w, s11cs_pia0ca2_w, s11cs_pia0cb2_w,
 /* irq : A/B             */
  s11cs_piaIrqA, s11cs_piaIrqB
};

static WRITE_HANDLER(s11cs_rombank_w) {
  cpu_setbank(S11CS_BANK0, s11clocals.brdData.romRegion + 0x10000*((data & 0x03) + ((data & 0x08)>>1)) + 0x8000*((data & 0x04)>>2));
}
static void s11cs_init(struct sndbrdData *brdData) {
  s11clocals.brdData = *brdData;
  s11clocals.ignore = core_gameData->hw.gameSpecific1 & S11_SNDDELAY ? 7 : 0;
  pia_config(S11CS_PIA0, PIA_STANDARD_ORDERING, &s11cs_pia);
  cpu_setbank(S11CS_BANK0, s11clocals.brdData.romRegion);
}
static WRITE_HANDLER(s11cs_manCmd_w) {
  cslatch2_w(0, data); pia_set_input_cb1(S11CS_PIA0, 1); pia_set_input_cb1(S11CS_PIA0, 0);
}

static WRITE_HANDLER(s11cs_pia0ca2_w) { if (!data) YM2151_sh_reset(); }
static WRITE_HANDLER(s11cs_pia0cb2_w) { sndbrd_data_cb(s11clocals.brdData.boardNo,data); }

static void s11cs_ym2151IRQ(int state) { pia_set_input_ca1(S11CS_PIA0, !state); }
static void s11cs_piaIrqA(int state) {
  cpu_set_irq_line(s11clocals.brdData.cpuNo, M6809_FIRQ_LINE, state ? ASSERT_LINE : CLEAR_LINE);
}
static void s11cs_piaIrqB(int state) {
  cpu_set_nmi_line(s11clocals.brdData.cpuNo, state ? ASSERT_LINE : CLEAR_LINE);
}

/*--------------------------
/   S11 Jokerz sound board
/---------------------------*/
#define S11JS_BANK0   4

static void s11js_ym2151IRQ(int state);
static void s11js_init(struct sndbrdData *brdData);
static WRITE_HANDLER(s11js_reply_w);
static WRITE_HANDLER(s11js_rombank_w);
static WRITE_HANDLER(s11js_ctrl_w);
static WRITE_HANDLER(s11js_manCmd_w);

static struct {
  struct sndbrdData brdData;
  int irqen;
  int ignore;
} s11jlocals;

static WRITE_HANDLER(jlatch2_w) {
  if (!s11jlocals.ignore)
    soundlatch2_w(offset, data);
  else s11jlocals.ignore--;
}

const struct sndbrdIntf s11jsIntf = {
  "WMSS11J", s11js_init, NULL, NULL, s11js_manCmd_w,
  jlatch2_w, soundlatch3_r,
  s11js_ctrl_w, NULL, 0
};

static WRITE_HANDLER(s11js_odd_w) {
  logerror("%04x: Jokerz ROM write to 0xf8%02x = %02x\n", activecpu_get_previouspc(), offset, data);
}
static WRITE_HANDLER(s11js_dac_w) {
  logerror("%04x: Jokerz DAC write = %02x\n", activecpu_get_previouspc(), data);
}
static WRITE_HANDLER(s11js_sync_w) {
  logerror("%04x: Jokerz SYNC write = %02x\n", activecpu_get_previouspc(), data);
}
static READ_HANDLER(s11js_port_r) {
  s11jlocals.irqen = 0;
  cpu_set_irq_line(s11jlocals.brdData.cpuNo, M6809_IRQ_LINE, CLEAR_LINE);
  return soundlatch2_r(offset);
}

static MEMORY_READ_START(s11js_readmem)
  { 0x0000, 0x1fff, MRA_RAM },
  { 0x2001, 0x2001, YM2151_status_port_0_r }, /* 2001-2fff odd */
  { 0x3400, 0x3400, s11js_port_r },
  { 0x4000, 0xbfff, MRA_BANKNO(S11JS_BANK0) },
  { 0xc000, 0xffff, MRA_ROM },
MEMORY_END

static MEMORY_WRITE_START(s11js_writemem)
  { 0x0000, 0x1fff, MWA_RAM },
  { 0x2000, 0x2001, YM2151_word_0_w },              /* 2000-2ffe even *//* 2001-2fff odd */
  { 0x2800, 0x2800, s11js_reply_w },
  { 0x3000, 0x3000, s11js_dac_w },
  { 0x3800, 0x3800, s11js_rombank_w },
  { 0x3c00, 0x3c00, s11js_sync_w },
  { 0xf800, 0xf8ff, s11js_odd_w },
MEMORY_END

static struct YM2151interface   s11js_ym2151Int  = {
  1, 3579545, /* Hz */
  { YM3012_VOL(30,MIXER_PAN_LEFT,30,MIXER_PAN_RIGHT) }, // Jokerz features a unique stereo board
  { s11js_ym2151IRQ }
};

MACHINE_DRIVER_START(wmssnd_s11js)
  MDRV_CPU_ADD(M6809, 2000000)
  MDRV_CPU_FLAGS(CPU_AUDIO_CPU)
  MDRV_CPU_MEMORY(s11js_readmem, s11js_writemem)
  MDRV_SOUND_ATTRIBUTES(SOUND_SUPPORTS_STEREO)
  MDRV_SOUND_ADD(YM2151, s11js_ym2151Int)
  MDRV_SOUND_ADD(SAMPLES, samples_interface)
MACHINE_DRIVER_END

static WRITE_HANDLER(s11js_rombank_w) {
  cpu_setbank(S11JS_BANK0, s11jlocals.brdData.romRegion + 0x8000*(data & 0x01));
}
static void s11js_init(struct sndbrdData *brdData) {
  s11jlocals.brdData = *brdData;
  s11jlocals.ignore = 10;
//  cpu_setbank(S11JS_BANK0, s11jlocals.brdData.romRegion);
}
static WRITE_HANDLER(s11js_ctrl_w) {
  if (!s11jlocals.ignore) {
    if (!data) s11jlocals.irqen++;
    if (s11jlocals.irqen) cpu_set_irq_line(s11jlocals.brdData.cpuNo, M6809_IRQ_LINE, ASSERT_LINE);
  }
}
static WRITE_HANDLER(s11js_reply_w) {
  soundlatch3_w(0,data);
  sndbrd_data_cb(s11jlocals.brdData.boardNo, 0); sndbrd_data_cb(s11jlocals.brdData.boardNo, 1);
}
static WRITE_HANDLER(s11js_manCmd_w) {
//printf("m:%02x ", data); // the manual commands are not passed through, why???
  jlatch2_w(0, data); s11js_ctrl_w(0,0);
}
static void s11js_ym2151IRQ(int state) {
  cpu_set_irq_line(s11jlocals.brdData.cpuNo, M6809_FIRQ_LINE, state ? ASSERT_LINE : CLEAR_LINE);
}


/*----------------------------------------
/  WPC sound board (pre-DCS, aka WPC89)
/----------------------------------------*/
#define WPCS_BANK0  4

/*-- internal sound interface --*/
static WRITE_HANDLER(wpcs_latch_w);
static READ_HANDLER(wpcs_latch_r);

/*-- external interfaces --*/
static void wpcs_init(struct sndbrdData *brdData);
static READ_HANDLER(wpcs_data_r);
static WRITE_HANDLER(wpcs_data_w);
static READ_HANDLER(wpcs_ctrl_r);
static WRITE_HANDLER(wpcs_ctrl_w);
const struct sndbrdIntf wpcsIntf = { "WPCS", wpcs_init, NULL, NULL, wpcs_data_w, wpcs_data_w, wpcs_data_r, wpcs_ctrl_w, wpcs_ctrl_r };

/*-- other memory handlers --*/
static WRITE_HANDLER(wpcs_rombank_w);
static WRITE_HANDLER(wpcs_volume_w);
static void wpcs_ym2151IRQ(int state);

/*-- local data --*/
static struct {
  struct sndbrdData brdData;
  int replyAvail;
  int volume;
} locals;

static WRITE_HANDLER(wpcs_rombank_w) {
  /* the hardware can actually handle 1M chip but no games used it */
  /* if such ROM appears the region must be doubled and mask set to 0x1f */
  /* this would be much easier if the region was filled in opposite order */
  /* but I don't want to change it now */
  int bankBase = data & 0x0f;
#ifdef MAME_DEBUG
  /* this register can no be read but this makes debugging easier */
  *(memory_region(REGION_CPU1+locals.brdData.cpuNo) + 0x2000) = data;
#endif /* MAME_DEBUG */

  switch ((~data) & 0xe0) {
    case 0x80: /* U18 */
      bankBase |= 0x00; break;
    case 0x40: /* U15 */
      bankBase |= 0x10; break;
    case 0x20: /* U14 */
      bankBase |= 0x20; break;
    default:
      DBGLOG(("WPCS:Unknown bank %x\n",data)); return;
  }
  cpu_setbank(WPCS_BANK0, locals.brdData.romRegion + (bankBase<<15));
}

static WRITE_HANDLER(wpcs_volume_w) {
  if (data & 0x01) {
    if ((locals.volume > 0) && (data & 0x02))
      locals.volume -= 1;
    else if ((locals.volume < 0xff) && ((data & 0x02) == 0))
      locals.volume += 1;
    /* DBGLOG(("Volume set to %d\n",locals.volume)); */
    {
      int ch;
      for (ch = 0; ch < MIXER_MAX_CHANNELS; ch++) {
        if (mixer_get_name(ch) != NULL)
          mixer_set_volume(ch, locals.volume * 100 / 127);
      }
    }
  }
}

static WRITE_HANDLER(wpcs_latch_w) {
  locals.replyAvail = TRUE; soundlatch2_w(0,data);
  sndbrd_data_cb(locals.brdData.boardNo, data);
}

static READ_HANDLER(wpcs_latch_r) {
  cpu_set_irq_line(locals.brdData.cpuNo, M6809_IRQ_LINE, CLEAR_LINE);
  return soundlatch_r(0);
}

static void wpcs_ym2151IRQ(int state) {
  cpu_set_irq_line(locals.brdData.cpuNo, M6809_FIRQ_LINE, state ? ASSERT_LINE : CLEAR_LINE);
}

#ifdef PREDCS_FIRQ_HACK

	//This value is based on a lot of trial and error and comparing the same voice sample played with and without music playing
	#define FIRQ_HACK_RATE        2400

	extern int YM2151ReadOutputFlag(int chip);

	//Force the FIRQ to toggle @ the specified rate, but only while the 2151 is not outputting sound
	static void firq_hack(int data) {
		static int last = 0;
		if(!YM2151ReadOutputFlag(0)) {
			if(last)
			{
				cpu_set_irq_line(locals.brdData.cpuNo, M6809_FIRQ_LINE, CLEAR_LINE);
				last = 0;
			}
			else
			{
				cpu_set_irq_line(locals.brdData.cpuNo, M6809_FIRQ_LINE, ASSERT_LINE);
				last++;
			}
		}

	}
#endif

static MEMORY_READ_START(wpcs_readmem)
  { 0x0000, 0x1fff, MRA_RAM },
  { 0x2401, 0x2401, YM2151_status_port_0_r }, /* 2401-27ff odd */
  { 0x3000, 0x3000, wpcs_latch_r }, /* 3000-33ff */
  { 0x4000, 0xbfff, CAT2(MRA_BANK, WPCS_BANK0) }, //32K
  { 0xc000, 0xffff, MRA_ROM }, /* same as page 7f */	//16K
MEMORY_END

static MEMORY_WRITE_START(wpcs_writemem)
  { 0x0000, 0x1fff, MWA_RAM },
  { 0x2000, 0x2000, wpcs_rombank_w }, /* 2000-23ff */
  { 0x2400, 0x2401, YM2151_word_0_w }, /* 2400-27fe even *//* 2401-27ff odd */
  { 0x2800, 0x2800, DAC_0_data_w }, /* 2800-2bff */
  { 0x2c00, 0x2c00, hc55516_0_clock_set_w },  /* 2c00-2fff */
  { 0x3400, 0x3400, hc55516_0_digit_clock_clear_w }, /* 3400-37ff */
  { 0x3800, 0x3800, wpcs_volume_w }, /* 3800-3bff */
  { 0x3c00, 0x3c00, wpcs_latch_w },  /* 3c00-3fff */
MEMORY_END

// Relative mixing volumes for the WPC89 sound devices.  [mjr 5/2019] Adjusted the levels
// based on the original analog mixing levels inferred from the WPC89 schematics:
//
//  - HC55516 outputs 1.7V peak and goes through a 3.19 gain op-amp stage, for 5.4V peak
//  - YM2151 outputs 2.5V peak and goes through a 0.35 gain op-amp stage, for .86V peak
//  - DAC (AD7524) outputs 3.8V peak (Vref, 12V at 10k/4.7k divider), unity gain op-amp, 3.8V peak
//
// Taking the HC55516 as the 100% reference point, the YM2151 peak voltage is 16% and the
// DAC peak is 70%.  This seems about right subjectively, except that 16% for YM makes the
// music a little too loud relative to the others, so let's keep that at 15%.
//
// Note that we can individually override any games where this doesn't sound right, as the
// DAC and YM relative volume levels can be independently adjusted per game.  See
// WPCSND_HC55516_LEVELS() in wmssnd.h to see how.
//
//[OLD NOTE, before HC55516 rewrite: These volume levels sound really good compared to my own Funhouse and T2: Dac=100%,CVSD=80%,2151=15%]
static struct DACinterface      wpcs_dacInt     = { 1, { 70 }};
static struct hc55516_interface wpcs_hc55516Int = { 1, { 100 }, HC55516_FILTER_WPC89 };
static struct YM2151interface   wpcs_ym2151Int  = {
  1, 3579545, /* Hz */
  { YM3012_VOL(15,MIXER_PAN_CENTER,15,MIXER_PAN_CENTER) },
  { wpcs_ym2151IRQ }
};

MACHINE_DRIVER_START(wmssnd_wpcs)
  MDRV_CPU_ADD(M6809, 2000000)
  MDRV_CPU_FLAGS(CPU_AUDIO_CPU)
  MDRV_CPU_MEMORY(wpcs_readmem, wpcs_writemem)
  MDRV_INTERLEAVE(50)
  MDRV_SOUND_ADD(YM2151, wpcs_ym2151Int)
  MDRV_SOUND_ADD(DAC,    wpcs_dacInt)
  MDRV_SOUND_ADD(HC55516,wpcs_hc55516Int)
  MDRV_SOUND_ADD(SAMPLES, samples_interface)
#ifdef PREDCS_FIRQ_HACK
  //Force the FIRQ to toggle @ the specified rate, but only while the 2151 is not outputting sound
  MDRV_TIMER_ADD(firq_hack, FIRQ_HACK_RATE)
#endif
MACHINE_DRIVER_END

/*---------------------
/  Interface functions
/----------------------*/
static READ_HANDLER(wpcs_data_r) {
  locals.replyAvail = FALSE; return soundlatch2_r(0);
}

static WRITE_HANDLER(wpcs_data_w) {
  soundlatch_w(0, data); cpu_set_irq_line(locals.brdData.cpuNo, M6809_IRQ_LINE, ASSERT_LINE);
}

static READ_HANDLER(wpcs_ctrl_r) {
  return locals.replyAvail;
}

static WRITE_HANDLER(wpcs_ctrl_w) { /*-- a write here resets the CPU --*/
  cpunum_set_reset_line(locals.brdData.cpuNo, PULSE_LINE);
}

static void wpcs_init(struct sndbrdData *brdData) {
  int hcgain = (core_gameData->hw.gameSpecific2 & 0x1ffff);
  int ymvol = ((core_gameData->hw.gameSpecific2) >> 18) & 0x7f;
  int dacvol = ((core_gameData->hw.gameSpecific2) >> 25) & 0x7f;
  locals.brdData = *brdData;
  /* the non-paged ROM is at the end of the image. move it to its correct place */
  memcpy(memory_region(REGION_CPU1+locals.brdData.cpuNo) + 0x00c000, locals.brdData.romRegion + 0x07c000, 0x4000);
  wpcs_rombank_w(0,0);
  if (hcgain != 0)
	hc55516_set_gain(0, hcgain / 100.0);
  if (ymvol != 0)
	YM2151_set_mixing_levels(0, ymvol, ymvol);
  if (dacvol != 0)
	DAC_set_mixing_level(0, dacvol);
}

/*--------------------
/  DCS sound board
/---------------------*/
/*-- ADSP core functions --*/
static void adsp_init(data8_t *(*getBootROM)(int soft),
               void (*txData)(UINT16 start, UINT16 size, UINT16 memStep, double sRate));
static void adsp_boot(int soft);
static void adsp_txCallback(int port, INT32 data);
static WRITE16_HANDLER(adsp_control_w);

/*-- bank handlers --*/
static WRITE16_HANDLER(dcs1_ROMbankSelect1_w);
static WRITE16_HANDLER(dcs2_ROMbankSelect1_w);
static WRITE16_HANDLER(dcs2_ROMbankSelect2_w);
static WRITE16_HANDLER(dcs2_RAMbankSelect_w);
static READ16_HANDLER(dcs2_RAMbankSelect_r);
static READ16_HANDLER(dcs_ROMbank_r);
static READ16_HANDLER(dcs2_RAMbank_r);
static WRITE16_HANDLER(dcs2_RAMbank_w);

/*-- sound interface handlers --*/
/* once the ADSP core is updated to handle PM mapping */
/* these can be static */
/*static*/ READ16_HANDLER(dcs_latch_r);
/*static*/ WRITE16_HANDLER(dcs_latch_w);
/* ADSP patch need to know if we are using dcs95 soundboard */
int WPC_gWPC95;

/*-- sound generation --*/
static int dcs_custStart(const struct MachineSound *msound);
static void dcs_custStop(void);
static void dcs_dacUpdate(int num, INT16 *buffer, int length);
static void dcs_txData(UINT16 start, UINT16 size, UINT16 memStep, double sRate);

/*-- external interface --*/
static READ_HANDLER(dcs_data_r);
static WRITE_HANDLER(dcs_data_w);
static READ_HANDLER(dcs_ctrl_r);
static WRITE_HANDLER(dcs_ctrl_w);
static void dcs_init(struct sndbrdData *brdData);

/*-- local data --*/
#define DCS_BUFFER_SIZE	  8192  // Must be power of 2 because of how circular buffer works
#define DCS_BUFFER_MASK	  (DCS_BUFFER_SIZE - 1)
#define DCS_DEFAULT_SAMPLE_RATE 31250 // as found in Ask Uncle Willy #3: July 7, 1995

static struct {
 int     status;   // 0 = disabled, 1 playing, > 1 startup silence samples remaining
 int     sOut, sIn; // positions in sound buffer
 INT16  *buffer;
 int     stream;
#ifdef DCS_LOWPASS
 #define SALLEN_KEY // like real HW/sound board uses, 4x 3rd order Sallen-Key low pass filters
 #ifdef SALLEN_KEY
  // filter stages
  filter2_context f[8];
 #else
  filter *filter_f;
  filter_state *filter_state;
 #endif
#endif
} dcs_dac;

static struct {
  struct sndbrdData brdData;
  UINT8  *cpuRegion;
  UINT16  ROMbank1, ROMbank2;
  UINT16  RAMbank;
  UINT8  *ROMbankPtr;
  UINT16 *RAMbankPtr;
  int     replyAvail;
} dcslocals;

static struct CustomSound_interface dcs_custInt = { dcs_custStart, dcs_custStop, 0 };

static MEMORY_READ16_START(dcs1_readmem)
  { ADSP_DATA_ADDR_RANGE(0x0000, 0x1fff), MRA16_RAM },
  { ADSP_DATA_ADDR_RANGE(0x2000, 0x2fff), dcs_ROMbank_r },
  { ADSP_DATA_ADDR_RANGE(0x3800, 0x39ff), MRA16_RAM },
  { ADSP_PGM_ADDR_RANGE (0x0000, 0x0800), MRA16_RAM }, /* Internal boot RAM */
  { ADSP_PGM_ADDR_RANGE (0x1000, 0x2fff), MRA16_RAM }, /* External RAM */
  { ADSP_PGM_ADDR_RANGE (0x3000, 0x3000), dcs_latch_r },
MEMORY_END

static MEMORY_WRITE16_START(dcs1_writemem)
  { ADSP_DATA_ADDR_RANGE(0x0000, 0x1fff), MWA16_RAM },
  { ADSP_DATA_ADDR_RANGE(0x2000, 0x2fff), MWA16_ROM },
  { ADSP_DATA_ADDR_RANGE(0x3000, 0x3000), dcs1_ROMbankSelect1_w },
  { ADSP_DATA_ADDR_RANGE(0x3800, 0x39ff), MWA16_RAM },
  { ADSP_DATA_ADDR_RANGE(0x3fe0, 0x3fff), adsp_control_w },
  { ADSP_PGM_ADDR_RANGE (0x0000, 0x0800), MWA16_RAM },
  { ADSP_PGM_ADDR_RANGE (0x1000, 0x2fff), MWA16_RAM },
  { ADSP_PGM_ADDR_RANGE (0x3000, 0x3000), dcs_latch_w },
MEMORY_END

MACHINE_DRIVER_START(wmssnd_dcs1)
  MDRV_CPU_ADD(ADSP2105, 10000000)
  MDRV_CPU_FLAGS(CPU_AUDIO_CPU)
  MDRV_CPU_MEMORY(dcs1_readmem, dcs1_writemem)
  MDRV_INTERLEAVE(50)
  MDRV_SOUND_ADD(CUSTOM, dcs_custInt)
  MDRV_SOUND_ADD(SAMPLES, samples_interface)
MACHINE_DRIVER_END

static MEMORY_READ16_START(dcs2_readmem)
  { ADSP_DATA_ADDR_RANGE(0x0000, 0x07ff), dcs_ROMbank_r },
  { ADSP_DATA_ADDR_RANGE(0x1000, 0x1fff), MRA16_RAM },
  { ADSP_DATA_ADDR_RANGE(0x2000, 0x2fff), dcs2_RAMbank_r },
  { ADSP_DATA_ADDR_RANGE(0x3200, 0x3200), dcs2_RAMbankSelect_r },
  { ADSP_DATA_ADDR_RANGE(0x3300, 0x3300), dcs_latch_r },
  { ADSP_DATA_ADDR_RANGE(0x3800, 0x39ff), MRA16_RAM },
  { ADSP_PGM_ADDR_RANGE (0x0000, 0x0800), MRA16_RAM }, /* Internal boot RAM */
  { ADSP_PGM_ADDR_RANGE (0x1000, 0x3fff), MRA16_RAM }, /* External RAM */
MEMORY_END

static MEMORY_WRITE16_START(dcs2_writemem)
  { ADSP_DATA_ADDR_RANGE(0x0000, 0x07ff), MWA16_ROM },
  { ADSP_DATA_ADDR_RANGE(0x1000, 0x1fff), MWA16_RAM },
  { ADSP_DATA_ADDR_RANGE(0x2000, 0x2fff), dcs2_RAMbank_w },
  { ADSP_DATA_ADDR_RANGE(0x3000, 0x3000), dcs2_ROMbankSelect1_w },
  { ADSP_DATA_ADDR_RANGE(0x3100, 0x3100), dcs2_ROMbankSelect2_w },
  { ADSP_DATA_ADDR_RANGE(0x3200, 0x3200), dcs2_RAMbankSelect_w },
  { ADSP_DATA_ADDR_RANGE(0x3300, 0x3300), dcs_latch_w },
  { ADSP_DATA_ADDR_RANGE(0x3800, 0x39ff), MWA16_RAM },
  { ADSP_DATA_ADDR_RANGE(0x3fe0, 0x3fff), adsp_control_w },
  { ADSP_PGM_ADDR_RANGE (0x0000, 0x0800), MWA16_RAM }, /* Internal boot RAM */
  { ADSP_PGM_ADDR_RANGE (0x1000, 0x3fff), MWA16_RAM }, /* External RAM */
MEMORY_END

MACHINE_DRIVER_START(wmssnd_dcs2)
  MDRV_CPU_ADD(ADSP2105, 10000000)
  MDRV_CPU_FLAGS(CPU_AUDIO_CPU)
  MDRV_CPU_MEMORY(dcs2_readmem, dcs2_writemem)
  MDRV_INTERLEAVE(50)
  MDRV_SOUND_ADD(CUSTOM, dcs_custInt)
  MDRV_SOUND_ADD(SAMPLES, samples_interface)
MACHINE_DRIVER_END

/*----------------
/ Sound interface
/-----------------*/
const struct sndbrdIntf dcsIntf = { "DCS", dcs_init, NULL, NULL, dcs_data_w, dcs_data_w, dcs_data_r, dcs_ctrl_w, dcs_ctrl_r };

/*---------------
/  Bank handlers
/----------------*/
#define DCS1_ROMBANKBASE(bank) \
  (dcslocals.brdData.romRegion + (((bank) & 0x7ff)<<12))
#define DCS2_ROMBANKBASE(bankH, bankL) \
  (dcslocals.brdData.romRegion + (((bankH) & 0x1c)<<18) + (((bankH) & 0x01)<<19) + (((bankL) & 0xff)<<11))
#define DCS2_RAMBANKBASE(bank) \
  ((UINT16 *)(((bank) & 0x08) ? memory_region(DCS_BANKREGION) : \
              (dcslocals.cpuRegion + ADSP2100_DATA_OFFSET + (0x2000<<1))))

static WRITE16_HANDLER(dcs1_ROMbankSelect1_w) {
  dcslocals.ROMbank1 = data;
  dcslocals.ROMbankPtr = DCS1_ROMBANKBASE(dcslocals.ROMbank1);
}
static WRITE16_HANDLER(dcs2_ROMbankSelect1_w) {
  dcslocals.ROMbank1 = data;
  dcslocals.ROMbankPtr = DCS2_ROMBANKBASE(dcslocals.ROMbank2,dcslocals.ROMbank1);
}
static WRITE16_HANDLER(dcs2_ROMbankSelect2_w) {
  dcslocals.ROMbank2 = data;
  dcslocals.ROMbankPtr = DCS2_ROMBANKBASE(dcslocals.ROMbank2,dcslocals.ROMbank1);
}
static WRITE16_HANDLER(dcs2_RAMbankSelect_w) {
  dcslocals.RAMbank  = data;
  dcslocals.RAMbankPtr = DCS2_RAMBANKBASE(dcslocals.RAMbank);
}
static READ16_HANDLER (dcs2_RAMbankSelect_r) {
  return dcslocals.RAMbank;
}

static READ16_HANDLER(dcs_ROMbank_r)   { return dcslocals.ROMbankPtr[offset]; }

static READ16_HANDLER(dcs2_RAMbank_r)  { return dcslocals.RAMbankPtr[offset]; }

static WRITE16_HANDLER(dcs2_RAMbank_w) { dcslocals.RAMbankPtr[offset] = data; }

static data8_t *dcs_getBootROM(int soft) {
  return (data8_t *)(dcslocals.brdData.romRegion +
                    (soft ? ((dcslocals.ROMbank1 & 0xff)<<12) : 0));
}

/*----------------------
/ Other memory handlers
/-----------------------*/
/* These should be static but the patched ADSP core requires them */

/*static*/ READ16_HANDLER(dcs_latch_r) {
  cpu_set_irq_line(dcslocals.brdData.cpuNo, ADSP2105_IRQ2, CLEAR_LINE);
#if 1
  return soundlatch_r(0);
#else
  { int x = soundlatch_r(0); DBGLOG(("Latch_r: %02x\n",x)); return x; }
#endif
}

/*static*/ WRITE16_HANDLER(dcs_latch_w) {
  soundlatch2_w(0, (data8_t)data);
  dcslocals.replyAvail = TRUE;
  sndbrd_data_cb(dcslocals.brdData.boardNo, data);
}

static int dcs_custStart(const struct MachineSound *msound) {
  int i,fi;

  /*-- clear DAC data --*/
  memset(&dcs_dac,0,sizeof(dcs_dac));

  /*-- allocate a DAC stream --*/
  dcs_dac.stream = stream_init_float("DCS DAC", 100, DCS_DEFAULT_SAMPLE_RATE, 0, dcs_dacUpdate,
#ifdef DCS_LOWPASS
      1);
#else
      0);
#endif

  /*-- allocate memory for our buffer --*/
  dcs_dac.buffer = malloc(DCS_BUFFER_SIZE * sizeof(INT16));
  memset(dcs_dac.buffer, 0, DCS_BUFFER_SIZE * sizeof(INT16));

#ifdef DCS_LOWPASS
#ifdef SALLEN_KEY
  fi = 0;
  if (core_gameData->gen & (GEN_WPC95 /*| GEN_WPC95DCS*/)) // WHO Dunnit still has the 16-9472 (according to schematics on ipdb at least)
  {
  //WPC-95 Schematics 16-10011 sheet 4 of 4:
  // This omits one high-pass filter between the DAC and the low-pass filter
  // series (C=4.7u, R=47K, corner frequency 7.2 Hz).  This is just there to
  // decouple the filter from the DAC output's DC offset, which is a feature
  // of the analog design that isn't relevant to the digital version.  It can
  // be omitted without loss of fidelity.
  for (i = 0; i < 3; ++i)
  {
    filter_rc_lp_setup(6190, 0, 0, 1000e-12, &dcs_dac.f[fi++], DCS_DEFAULT_SAMPLE_RATE);
    filter_sallen_key_lp_setup(6190, 6190, 3900e-12, 680e-12, &dcs_dac.f[fi++], DCS_DEFAULT_SAMPLE_RATE);

    if (i == 1)
    {
      filter_rc_lp_setup(6190, 0, 0, 1000e-12, &dcs_dac.f[fi++], DCS_DEFAULT_SAMPLE_RATE);
      filter_sallen_key_lp_setup(6190, 6190, 4700e-12, 680e-12, &dcs_dac.f[fi++], DCS_DEFAULT_SAMPLE_RATE);
    }
  }
  }
  else
  {
  //WPC Schematics Sound Board 16-9472 sheet 4 of 5:
  // Omits one high-pass stage between the DAC and the first low-pass stage (R=47K, C=4.7u,
  // corner frequency 0.72 Hz).  This is present in the analog circuit to decouple the
  // filters from the DC offset from the DAC; it isn't relevant to the digital version
  // and can be omitted without loss of fidelity.
  for (i = 0; i < 3; ++i)
  {
    filter_rc_lp_setup(6200, 0, 0, 1000e-12, &dcs_dac.f[fi++], DCS_DEFAULT_SAMPLE_RATE);
    filter_sallen_key_lp_setup(6200, 6200, 3900e-12, 680e-12, &dcs_dac.f[fi++], DCS_DEFAULT_SAMPLE_RATE);

    if (i == 1)
    {
      filter_rc_lp_setup(6200, 0, 0, 1000e-12, &dcs_dac.f[fi++], DCS_DEFAULT_SAMPLE_RATE);
      filter_sallen_key_lp_setup(6200, 6200, 6800e-12, 680e-12, &dcs_dac.f[fi++], DCS_DEFAULT_SAMPLE_RATE);
    }
  }
  }
#else
  dcs_dac.filter_f = filter_lp_fir_alloc(0.275, FILTER_ORDER_MAX); // magic, resolves noise on scared stiff for example, while not cutting off too much else -> is this due to DCS compression itself?
  dcs_dac.filter_state = filter_state_alloc();
  filter_state_reset(dcs_dac.filter_f, dcs_dac.filter_state);
#endif
#endif

  return (dcs_dac.buffer == 0);
}

static void dcs_custStop(void) {
  if (dcs_dac.buffer)
    { free(dcs_dac.buffer); dcs_dac.buffer = NULL;
#ifdef DCS_LOWPASS
 #ifndef SALLEN_KEY
      filter_state_free(dcs_dac.filter_state);
      filter_free(dcs_dac.filter_f);
 #endif
#endif
    }
}


static void dcs_dacUpdate(int num, INT16 *buffer, int length)
{
    int ii;
#ifdef DCS_LOWPASS
    float* __restrict const buffer_f = (float*)buffer;
#endif

    /* fill in with samples until we hit the end or run out */
    for (ii = 0; ii < length; ii++)
    {
      double v;
      int iii;
      if (dcs_dac.sOut == dcs_dac.sIn) break;
#ifdef DCS_LOWPASS
 #ifdef SALLEN_KEY
      // run the sample through the staged filter
      v = (double)(1.0/32768.0)*(double)dcs_dac.buffer[dcs_dac.sOut];
      for(iii = 0; iii < 8; iii++) //!! opt.!?
        v = filter2_step_with(&dcs_dac.f[iii], v);
      buffer_f[ii] = (float)v;
 #else
      filter_insert(dcs_dac.filter_f, dcs_dac.filter_state, (float)(1.0/32768.0)*(float)dcs_dac.buffer[dcs_dac.sOut]);
      buffer_f[ii] = filter_compute(dcs_dac.filter_f, dcs_dac.filter_state);
 #endif
#else
      buffer[ii] = dcs_dac.buffer[dcs_dac.sOut];
#endif
      dcs_dac.sOut = (dcs_dac.sOut + 1) & DCS_BUFFER_MASK;
    }
    /* Give core feedback on sound buffer progress, so speed can be throttled to keep sound perfect */
    core_sound_throttle_adj(dcs_dac.sIn, &dcs_dac.sOut, DCS_BUFFER_SIZE, stream_get_sample_rate(dcs_dac.stream));

    /* fill the rest with the last sample (ideally never necessary) */
    for ( ; ii < length; ii++)
    {
#ifdef DCS_LOWPASS
 #ifdef SALLEN_KEY
      // run the sample through the staged filter
      double v = (double)(1.0/32768.0)*(double)dcs_dac.buffer[(dcs_dac.sOut - 1) & DCS_BUFFER_MASK];
      int iii;
      for(iii = 0; iii < 8; iii++) //!! opt.!?
        v = filter2_step_with(&dcs_dac.f[iii], v);
      buffer_f[ii] = (float)v;
 #else
      filter_insert(dcs_dac.filter_f, dcs_dac.filter_state, (float)(1.0/32768.0)*(float)dcs_dac.buffer[(dcs_dac.sOut - 1) & DCS_BUFFER_MASK]);
      buffer_f[ii] = filter_compute(dcs_dac.filter_f, dcs_dac.filter_state);
 #endif
#else
      buffer[ii] = dcs_dac.buffer[(dcs_dac.sOut - 1) & DCS_BUFFER_MASK];
#endif
    }
}

/*-------------------
/ Exported interface
/---------------------*/
static READ_HANDLER(dcs_data_r) {
  dcslocals.replyAvail = FALSE;
  return soundlatch2_r(0) & 0xff;
}

static WRITE_HANDLER(dcs_data_w) {
  DBGLOG(("Latch_w: %02x\n",data));
  soundlatch_w(0, data); cpu_set_irq_line(dcslocals.brdData.cpuNo, ADSP2105_IRQ2, ASSERT_LINE);
}

static WRITE_HANDLER(dcs_ctrl_w) {
  DBGLOG(("ctrl_w: %02x\n",data));

  // Tom: Removed the next line which now prevents some "sound board interface error"
  // if (dcslocals.brdData.subType < 2)
  {
#ifdef WPCDCSSPEEDUP
    // probably a bug in the mame reset handler
    // if a cpu is suspended for some reason a reset will not wake it up
    cpu_triggerint(dcslocals.brdData.cpuNo);
#endif /* WPCDCSSPEEDUP */
    // Reset is triggered on write so just pulse the line
    cpunum_set_reset_line(dcslocals.brdData.cpuNo, PULSE_LINE);
    adsp_boot(0);
  }
}

static READ_HANDLER(dcs_ctrl_r) {
  return dcslocals.replyAvail ? 0x80 : 0x00;
}

/*----------------------------
/ Checksum in DCS
/ GEN_SECURITY: Page 0x0004
/ WPC95:        Page 0x000c
/
/ Pages, StartPage, ChkSum
/
-----------------------------*/

/*-- handle bug in ADSP core */
static OPBASE_HANDLER(opbaseoveride) { return -1; }

static void dcs_init(struct sndbrdData *brdData) {
  memset(&dcslocals, 0, sizeof(dcslocals));
  dcslocals.brdData = *brdData;
  dcslocals.cpuRegion = memory_region(REGION_CPU1+dcslocals.brdData.cpuNo);
  memory_set_opbase_handler(dcslocals.brdData.cpuNo, opbaseoveride);
  /*-- initialize our structure --*/
  dcslocals.ROMbankPtr = dcslocals.brdData.romRegion;
  dcslocals.RAMbankPtr = (UINT16 *)memory_region(DCS_BANKREGION);

  WPC_gWPC95 = brdData->subType;

  adsp_init(dcs_getBootROM, dcs_txData);

  /*-- clear all interrupts --*/
  cpu_set_irq_line(dcslocals.brdData.cpuNo, ADSP2105_IRQ0, CLEAR_LINE );
  cpu_set_irq_line(dcslocals.brdData.cpuNo, ADSP2105_IRQ1, CLEAR_LINE );
  cpu_set_irq_line(dcslocals.brdData.cpuNo, ADSP2105_IRQ2, CLEAR_LINE );

  /*-- speed up startup by disable checksum --*/
#if 0
  if (options.cheat) {
    if (core_gameData->gen & GEN_WPC95)
      *((UINT16 *)(memory_region(WPC_MEMREG_SROM) + 0x6000)) = 0x0000;
    else
      *((UINT16 *)(memory_region(WPC_MEMREG_SROM) + 0x4000)) = 0x0000;
  }
#endif
  /*-- boot ADSP2100 --*/
  adsp_boot(0);
}

/*-----------------
/  local functions
/------------------*/
/*-- autobuffer SPORT transmission  --*/
/*-- copy data to transmit into dac buffer --*/
static void dcs_txData(UINT16 start, UINT16 size, UINT16 memStep, double sRate) {
  const UINT16 * const mem = ((UINT16 *)(dcslocals.cpuRegion + ADSP2100_DATA_OFFSET)) + start;
  int idx;

  // Let the buffer fill naturally, so the throttling mechanism can work.
//  stream_update(dcs_dac.stream, 0);
  if (size == 0) /* No data, stop playing */
  { dcs_dac.status = 0; return; }

  if (dcs_dac.status == 0)
  {
	  // We have a hard assumption that the rate is always DCS_DEFAULT_SAMPLE_RATE,
	  // because we have IIR filters constructed using that rate.  The filters
	  // would need to be reconfigured here if the sample rate were actually
	  // changing.  In practice it never does change, but we'll assert it just
	  // in case someone does something crazy like writing a custom DCS ROM.
	  // If this assert ever fails, here's what you have to do:
	  //  - call stream_set_sample_rate(dcs_dac.stream, sRate) to update the rate
	  //  - reinitialize all of the stream filters with the new rate (by reiterating
	  //    all of the filter setup code in dcs_custStart)
	  assert(stream_get_sample_rate(dcs_dac.stream) == sRate);
  }

  // If we were not playing before, pre-load buffer with some silence to prevent jumpy starts.
  if (dcs_dac.status == 0)
  {
      const int idx_end = (int)(stream_get_sample_rate(dcs_dac.stream) * 20 / 1000 + 1 + 0.5);
      for (idx = 0; idx < idx_end; idx++) {
          dcs_dac.buffer[dcs_dac.sIn] = 0;
          dcs_dac.sIn = (dcs_dac.sIn + 1) & DCS_BUFFER_MASK;
      }

      dcs_dac.status = 1;
  }
  /*-- size is the size of the buffer not the number of samples --*/
  for (idx = 0; idx < size; idx += memStep) {
    dcs_dac.buffer[dcs_dac.sIn] = mem[idx];
    dcs_dac.sIn = (dcs_dac.sIn + 1) & DCS_BUFFER_MASK;
  }
}

#define DCS_IRQSTEPS 4
/*--------------------------------------------------*/
/*-- This should actually be part of the CPU core --*/
/*--------------------------------------------------*/
enum {
  S1_AUTOBUF_REG = 15, S1_RFSDIV_REG, S1_SCLKDIV_REG, S1_CONTROL_REG,
  S0_AUTOBUF_REG, S0_RFSDIV_REG, S0_SCLKDIV_REG, S0_CONTROL_REG,
  S0_MCTXLO_REG, S0_MCTXHI_REG, S0_MCRXLO_REG, S0_MCRXHI_REG,
  TIMER_SCALE_REG, TIMER_COUNT_REG, TIMER_PERIOD_REG, WAITSTATES_REG,
  SYSCONTROL_REG
};

static struct {
 UINT16  ctrlRegs[32];
 void   *irqTimer;
 data8_t *(*getBootROM)(int soft);
 void   (*txData)(UINT16 start, UINT16 size, UINT16 memStep, double sRate);
} adsp; /* = {{0},NULL,dcs_getBootROM,dcs_txData};*/
static void adsp_irqGen(int dummy);

static void adsp_init(data8_t *(*getBootROM)(int soft),
                     void (*txData)(UINT16 start, UINT16 size, UINT16 memStep, double sRate)) {
  /* stupid timer/machine init handling in MAME */
  if (adsp.irqTimer) timer_remove(adsp.irqTimer);
  /*-- reset control registers etc --*/
  memset(&adsp, 0, sizeof(adsp));
  adsp.getBootROM = getBootROM;
  adsp.txData = txData;
  adsp.irqTimer = timer_alloc(adsp_irqGen);
  /*-- initialize the ADSP Tx callback --*/
  adsp2105_set_tx_callback(adsp_txCallback);
}

#if MAMEVER < 6300
static void adsp2105_load_boot_data(data8_t *srcdata, data32_t *dstdata) {
  UINT32 size = 8 * (srcdata[3] + 1), i;
  for (i = 0; i < size; i++) {
    UINT32 opcode = (srcdata[i*4+0] << 16) | (srcdata[i*4+1] << 8) | srcdata[i*4+2];
    ADSP2100_WRPGM(&dstdata[i], opcode);
  }
}
#endif /* MAMEVER */

static void adsp_boot(int soft) {
  adsp2105_load_boot_data(adsp.getBootROM(soft), (UINT32 *)(dcslocals.cpuRegion+ADSP2100_PGM_OFFSET));
  timer_enable(adsp.irqTimer, FALSE);
}

static WRITE16_HANDLER(adsp_control_w) {
  adsp.ctrlRegs[offset] = data;
  switch (offset) {
    case SYSCONTROL_REG:
      if (data & 0x0200) {
        /* boot force */
        DBGLOG(("boot force\n"));
        cpunum_set_reset_line(dcslocals.brdData.cpuNo, PULSE_LINE);
        adsp_boot(1);
        adsp.ctrlRegs[SYSCONTROL_REG] &= ~0x0200;
      }
      /* see if SPORT1 got disabled */
      if ((data & 0x0800) == 0) {
        dcs_txData(0, 0, 0, 0);
        /* nuke the timer */
        timer_enable(adsp.irqTimer, FALSE);
      }
      break;
    case S1_AUTOBUF_REG:
      /* autobuffer off: nuke the timer */
      if ((data & 0x0002) == 0) {
        adsp.txData(0, 0, 0, 0);
        /* nuke the timer */
        timer_enable(adsp.irqTimer, FALSE);
      }
      break;
    case S1_CONTROL_REG:
      if (((data>>4) & 3) == 2)
	DBGLOG(("Oh no!, the data is compresed with u-law encoding\n"));
      if (((data>>4) & 3) == 3)
	DBGLOG(("Oh no!, the data is compresed with A-law encoding\n"));
      break;
  } /* switch */
}

static struct {
  UINT16 start;
  UINT16 size, step;
  double sRate;
  int    iReg;
  int    last;
  int    irqCount;
} adsp_aBufData;

static void adsp_irqGen(int dummy) {
  int next;

  if (adsp_aBufData.irqCount < DCS_IRQSTEPS) {
    adsp_aBufData.irqCount += 1;
#ifdef WPCDCSSPEEDUP
    /* wake up suspended cpu by simulating an interrupt trigger */
    cpu_triggerint(dcslocals.brdData.cpuNo);
#endif /* WPCDCSSPEEDUP */
  }
  else {
    adsp_aBufData.irqCount = 1;
    adsp_aBufData.last = 0;
    cpu_set_irq_line(dcslocals.brdData.cpuNo, ADSP2105_IRQ1, PULSE_LINE);
  }

  next = (adsp_aBufData.size / adsp_aBufData.step * adsp_aBufData.irqCount /
          DCS_IRQSTEPS - 1) * adsp_aBufData.step;

  cpunum_set_reg(dcslocals.brdData.cpuNo, ADSP2100_I0 + adsp_aBufData.iReg,
                 adsp_aBufData.start + next);

  adsp.txData(adsp_aBufData.start + adsp_aBufData.last, (next - adsp_aBufData.last),
              adsp_aBufData.step, adsp_aBufData.sRate);

  adsp_aBufData.last = next;

}

static void adsp_txCallback(int port, INT32 data) {
  if (port != 1)
    { DBGLOG(("tx0 not handled\n")); return; };
  /*-- remove any pending timer --*/
  timer_enable(adsp.irqTimer, FALSE);
  if ((adsp.ctrlRegs[SYSCONTROL_REG] & 0x0800) == 0)
    DBGLOG(("tx1 without SPORT1 enabled\n"));
  else if ((adsp.ctrlRegs[S1_AUTOBUF_REG] & 0x0002) == 0)
    DBGLOG(("SPORT1 without autobuffer"));
  else {
    int ireg, mreg;

    ireg = (adsp.ctrlRegs[S1_AUTOBUF_REG]>>9) & 7;
    mreg = ((adsp.ctrlRegs[S1_AUTOBUF_REG]>>7) & 3) | (ireg & 0x04);

    /* start = In, size = Ln, step = Mn */
    adsp_aBufData.step  = activecpu_get_reg(ADSP2100_M0 + mreg);
    adsp_aBufData.size  = activecpu_get_reg(ADSP2100_L0 + ireg);
    /*-- assume that the first sample comes from the memory position before --*/
    adsp_aBufData.start = activecpu_get_reg(ADSP2100_I0 + ireg) - adsp_aBufData.step;
    adsp_aBufData.sRate = Machine->drv->cpu[dcslocals.brdData.cpuNo].cpu_clock /
                           (2 * (adsp.ctrlRegs[S1_SCLKDIV_REG] + 1)) / 16;
    adsp_aBufData.iReg = ireg;
    adsp_aBufData.irqCount = adsp_aBufData.last = 0;
    adsp_irqGen(0); /* first part, rest is handled via the timer */
    /*-- fire the irq timer --*/
    timer_adjust(adsp.irqTimer, 0, 0, TIME_IN_HZ(adsp_aBufData.sRate) *
                      adsp_aBufData.size / adsp_aBufData.step / DCS_IRQSTEPS);
    DBGLOG(("DCS size=%d,step=%d,rate=%d\n",adsp_aBufData.size,adsp_aBufData.step,adsp_aBufData.sRate));
    return;
  }
  /*-- if we get here, something went wrong. Disable transmission --*/
  adsp.txData(0, 0, 0, 0);
}

#ifdef WPCDCSSPEEDUP
/*
 *   Speedup for DCS games from 1994 and later.
 *   
 *   This is a hand-written C re-implementation of the core audio decoding
 *   loop contained in the ADSP-2100 ROM programs for Williams DCS machines
 *   built from 1994 onward.  The machines in this group share a nearly
 *   identical implementation of the decoding algorithm.  This native C
 *   implementation runs much faster than emulating the opcodes directly in
 *   the general-purpose emulation loop.
 *   
 *   The emulator *can* run the original code, but not quite fast enough.
 *   With current Intel hardware (fourth generation i5/i7) and the current
 *   ADSP-2100 emulator code, the emulated version can't consistently feed
 *   samples to the DAC at a real-time pace.  This causes audible playback
 *   artifacts (e.g., pitch errors, static, and distortion).  The native code
 *   version is about 50-100x faster than the emulated code; that's more than
 *   fast enough to keep up with real time, which eliminates the artifacts
 *   and greatly improves the audio quality.  It also takes a lot of load off
 *   the real CPU.
 *   
 *   This implementation appears to work with all DCS games except the three
 *   released in 1993: Star Trek: The Next Generation, Indiana Jones: The
 *   Pinball Adventure, and Judge Dredd.  Those three use a slightly
 *   different version of the decoding algorithm that's not easy to fold into
 *   a common version, so we broke it out into a separate routine - see
 *   dcs_speedup_1993() below.
 */
UINT32 dcs_speedup(UINT32 pc) {
  UINT16 *ram1source, *ram2source, volume;
  int ii;

  /* DCS and DCS95 uses different buffers */
  if (pc > 0x2000) {
    UINT32 volumeOP = *(UINT32 *)&OP_ROM[ADSP2100_PGM_OFFSET + ((pc+0x2b84-0x2b44)<<2)];

    ram1source = (UINT16 *)(dcslocals.cpuRegion + ADSP2100_DATA_OFFSET + (0x1000<<1));
    ram2source = dcslocals.RAMbankPtr;
    volume = ram1source[((volumeOP>>4)&0x3fff)-0x1000];
    /*DBGLOG(("OP=%6x addr=%4x V=%4x\n",volumeOP,(volumeOP>>4)&0x3fff,volume));*/
  }
  else {
    UINT32 volumeOP = *(UINT32 *)&OP_ROM[ADSP2100_PGM_OFFSET + ((pc+0x2b84-0x2b44)<<2)];

    ram1source = (UINT16 *)(dcslocals.cpuRegion + ADSP2100_DATA_OFFSET + (0x0700<<1));
    ram2source = (UINT16 *)(dcslocals.cpuRegion + ADSP2100_DATA_OFFSET + (0x3800<<1));
    volume = ram2source[((volumeOP>>4)&0x3fff)-0x3800];
    /*DBGLOG(("OP=%6x addr=%4x V=%4x\n",volumeOP,(volumeOP>>4)&0x3fff,volume));*/
  }
  {
    UINT16 *i0, *i2;
			/* 2B44     I0 = $2000 >>> (3800) <<< */
    i0 = &ram2source[0];
			/* 2B45:    I2 = $2080 >>> (3880) <<< */
    i2 = &ram2source[0x0080];
			/* 2B46     M2 = $3FFF */
			/* 2B47     M3 = $3FFD */
			/* 2B48     CNTR = $0040 */
			/* 2B49     DO $2B53 UNTIL CE */
    /* M0 = 0, M1 = 1, M2 = -1 */
    for (ii = 0; ii < 0x0040; ii++) {
      INT16 ax0 , ay0, ax1, ay1, ar;
			/* 2B4A       AX0 = DM(I0,M1) */
      ax0 = *i0++;
			/* 2B4B       AY0 = DM(I2,M0) */
      ay0 = *i2;
			/* 2B4C       AR = AX0 + AY0, AX1 = DM(I0,M2) */
      ax1 = *i0--;
      ar = ax0 + ay0;
			/* 2B4D       AR = AX0 - AY0, DM(I0,M1) = AR */
      *i0++ = ar;
      ar = ax0 - ay0;
			/* 2B4E       DM(I2,M1) = AR */
      *i2++ = ar;
			/* 2B4F       AY1 = DM(I2,M0) */
      ay1 = *i2;
			/* 2B50       AR = AX1 + AY1 */
      ar = ax1 + ay1;
			/* 2B51       DM(I0,M1) = AR */
      *i0++ = ar;
			/* 2B52       AR = AX1 - AY1 */
      ar = ax1 - ay1;
  			/* 2B53       DM(I2,M1) = AR */
      *i2++ = ar;
    }
  }
  {
    int mem63d, mem63e, mem63f;
    int jj,kk;
  			/* 2B54     AR = $0002 */
			/* 2B55     DM($15EB) = AR (063d) */
    mem63d = 2;
			/* 2B56     SI = $0040 */
			/* 2B57     DM($15ED) = SI (063e) */
    mem63e = 0x40;
			/* 2B58     SR = LSHIFT SI BY -1 (LO) */
			/* 2B59     DM($15EF) = SR0 (063f) */
    mem63f = mem63e >> 1;
			/* 2B5A     M0 = $3FFF */
			/* 2B5B     CNTR = $0006 */
			/* 2B5C     DO $2B80 UNTIL CE */

    /* M0 = -1, M1 = 1, M5 = 1 */
    for (ii = 0; ii < 6; ii++) {
      UINT16 *i0, *i1, *i2, *i4, *i5;
      INT16 m2, m3;
			/* 2B5D       I4 = $1080 >>> (0780) <<< */
      i4 = &ram1source[0x0080];
			/* 2B5E       I5 = $1000 >>> (0700) <<< */
      i5 = &ram1source[0x0000];
			/* 2B5F       I0 = $2000 >>> (3800) <<< */
      i0 = &ram2source[0x0000];
			/* 2B60       I1 = $2000 >>> (3800) <<< */
      i1 = &ram2source[0x0000];
			/* 2B61       AY0 = DM($15ED) (063e) */
			/* 2B62       M2 = AY0 */
      m2 = mem63e;
			/* 2B63       MODIFY (I1,M2) */
      i1 += m2;
			/* 2B64       I2 = I1 */
      i2 = i1;
			/* 2B65       AR = AY0 - 1 */
			/* 2B66       M3 = AR */
      m3 = mem63e - 1;
			/* 2B67       CNTR = DM($15EB) (063d) */
			/* 2B68       DO $2B79 UNTIL CE */

      for (jj = 0; jj < mem63d; jj++) {
        INT16 mx0, my0, my1;
			/* 2B6A         MY0 = DM(I4,M5) */
        my0 = *i4++;
			/* 2B6B         MY1 = DM(I5,M5) */
        my1 = *i5++;
			/* 2B6C         MX0 = DM(I1,M1) */
        mx0 = *i1++;
			/* 2B69         CNTR = DM($15EF) (063f) */
			/* 2B6D         DO $2B76 UNTIL CE */
        for (kk = 0; kk < mem63f; kk++) {
          INT16 mx1, ax0, ay0, ay1, ar;
          INT32 tmp, mr;
			/* 2B6E           MR = MX0 * MY0 (SS), MX1 = DM(I1,M1) */
          mx1 = *i1++;
          tmp = (((INT32)mx0 * my0)<<1);
          mr = tmp;
			/* 2B6F           MR = MR - MX1 * MY1 (RND), AY0 = DM(I0,M1) */
          ay0 = *i0++;
          tmp = (((INT32)mx1 * my1)<<1);
          mr = (mr - tmp + 0x8000) & (((tmp & 0xffff) == 0x8000) ? 0xfffeffff : 0xffffffff);
			/* 2B70           MR = MX1 * MY0 (SS), AX0 = MR1 */
          ax0 = mr>>16;
          tmp = (mx1 * my0)<<1;
          mr = tmp;
			/* 2B71           MR = MR + MX0 * MY1 (RND), AY1 = DM(I0,M0) */
          ay1 = *i0--; /* M0 = -1 */
          tmp = (((INT32)mx0 * my1)<<1);
          mr = (mr + tmp + 0x8000) & (((tmp & 0xffff) == 0x8000) ? 0xfffeffff : 0xffffffff);
			/* 2B72           AR = AY0 - AX0, MX0 = DM(I1,M1) */
          mx0 = *i1++;
          ar = ay0 - ax0;
			/* 2B73           AR = AX0 + AY0, DM(I0,M1) = AR */
          *i0++ = ar;
          ar = ax0 + ay0;
			/* 2B74           AR = AY1 - MR1, DM(I2,M1) = AR */
          *i2++ = ar;
          ar = ay1 - (mr>>16);
			/* 2B75           AR = MR1 + AY1, DM(I0,M1) = AR */
          *i0++ = ar;
          ar = (mr>>16) + ay1;
			/* 2B76           DM(I2,M1) = AR */
          *i2++ = ar;
        }
			/* 2B77         MODIFY (I2,M2) */
        i2 += m2;
			/* 2B78         MODIFY (I1,M3) */
        i1 += m3;
			/* 2B79         MODIFY (I0,M2) */
        i0 += m2;
      }
			/* 2B7A       SI = DM($15EB) (063d) */
			/* 2B7B:      SR = LSHIFT SI BY 1 (LO) */
			/* 2B7C:      DM($15EB) = SR0 (063d) */
      mem63d <<= 1;
			/* 2B7D       SI = DM($15EF) (063f) */
			/* 2B7E       DM($15ED) = SI (063e) */
      mem63e = mem63f;
			/* 2B7F       SR = LSHIFT SI BY -1 (LO) */
			/* 2B80       DM($15EF) = SR0 (063f) */
      mem63f >>= 1;
    }
  }
  { /* Volume scaling */
    UINT16 *i0;
    UINT16 my0;
			/* 2B81     M0 = $0000 */
			/* 2B82     I0 = $2000 >>> (3800) <<< */
    i0 = &ram2source[0x0000];
			/* 2B84     MY0 = DM($15FD) (390e) */
    my0 = MIN(volume,0x8000); // be paranoid about the volume, see code below
			/* 2B83     CNTR = $0100 */
			/* 2B85     DO $2B89 UNTIL CE */
    /* M0 = 0, M1 = 1 */
    for (ii = 0; ii < 0x0100; ii++) {
      INT16 mx0;
      INT32 mr;
			/* 2B86       MX0 = DM(I0,M0) */
      mx0 = *i0;
			/* 2B87       MR = MX0 * MY0 (SU) */
      mr = ((INT32)mx0 * my0); // <<1; // see shift below
			/* 2B88       IF MV SAT MR */
      /* This instruction limits MR to 32 bits */
      /* In reality the volume will never be higher than 0x8000 so */
      /* this is not needed */
			/* 2B89       DM(I0,M1) = MR1 */
      *i0++ = mr>>15; // >>16; // see above
    }
  }
  activecpu_set_reg(ADSP2100_PC, pc + 0x2b89 - 0x2b44);
  return 0; /* execute a NOP */
}


/*static UINT16 reverse_bits(UINT16 b)
{
    return ((b >> 13) & 0x0001)
        | ((b >> 11) & 0x0002)
        | ((b >> 9)  & 0x0004)
        | ((b >> 7)  & 0x0008)
        | ((b >> 5)  & 0x0010)
        | ((b >> 3)  & 0x0020)
        | ((b >> 1)  & 0x0040)
        | ((b << 1)  & 0x0080)
        | ((b << 3)  & 0x0100)
        | ((b << 5)  & 0x0200)
        | ((b << 7)  & 0x0400)
        | ((b << 9)  & 0x0800)
        | ((b << 11) & 0x1000)
        | ((b << 13) & 0x2000);
}*/

static const UINT16 reverse_table[0x2008] = {
	0x0, 0x2000, 0x1000, 0x3000, 0x800, 0x2800, 0x1800, 0x3800, 0x400, 0x2400, 0x1400, 0x3400, 0xC00, 0x2C00, 0x1C00, 0x3C00,
	0x200, 0x2200, 0x1200, 0x3200, 0xA00, 0x2A00, 0x1A00, 0x3A00, 0x600, 0x2600, 0x1600, 0x3600, 0xE00, 0x2E00, 0x1E00, 0x3E00,
	0x100, 0x2100, 0x1100, 0x3100, 0x900, 0x2900, 0x1900, 0x3900, 0x500, 0x2500, 0x1500, 0x3500, 0xD00, 0x2D00, 0x1D00, 0x3D00,
	0x300, 0x2300, 0x1300, 0x3300, 0xB00, 0x2B00, 0x1B00, 0x3B00, 0x700, 0x2700, 0x1700, 0x3700, 0xF00, 0x2F00, 0x1F00, 0x3F00,
	0x80, 0x2080, 0x1080, 0x3080, 0x880, 0x2880, 0x1880, 0x3880, 0x480, 0x2480, 0x1480, 0x3480, 0xC80, 0x2C80, 0x1C80, 0x3C80,
	0x280, 0x2280, 0x1280, 0x3280, 0xA80, 0x2A80, 0x1A80, 0x3A80, 0x680, 0x2680, 0x1680, 0x3680, 0xE80, 0x2E80, 0x1E80, 0x3E80,
	0x180, 0x2180, 0x1180, 0x3180, 0x980, 0x2980, 0x1980, 0x3980, 0x580, 0x2580, 0x1580, 0x3580, 0xD80, 0x2D80, 0x1D80, 0x3D80,
	0x380, 0x2380, 0x1380, 0x3380, 0xB80, 0x2B80, 0x1B80, 0x3B80, 0x780, 0x2780, 0x1780, 0x3780, 0xF80, 0x2F80, 0x1F80, 0x3F80,
	0x40, 0x2040, 0x1040, 0x3040, 0x840, 0x2840, 0x1840, 0x3840, 0x440, 0x2440, 0x1440, 0x3440, 0xC40, 0x2C40, 0x1C40, 0x3C40,
	0x240, 0x2240, 0x1240, 0x3240, 0xA40, 0x2A40, 0x1A40, 0x3A40, 0x640, 0x2640, 0x1640, 0x3640, 0xE40, 0x2E40, 0x1E40, 0x3E40,
	0x140, 0x2140, 0x1140, 0x3140, 0x940, 0x2940, 0x1940, 0x3940, 0x540, 0x2540, 0x1540, 0x3540, 0xD40, 0x2D40, 0x1D40, 0x3D40,
	0x340, 0x2340, 0x1340, 0x3340, 0xB40, 0x2B40, 0x1B40, 0x3B40, 0x740, 0x2740, 0x1740, 0x3740, 0xF40, 0x2F40, 0x1F40, 0x3F40,
	0xC0, 0x20C0, 0x10C0, 0x30C0, 0x8C0, 0x28C0, 0x18C0, 0x38C0, 0x4C0, 0x24C0, 0x14C0, 0x34C0, 0xCC0, 0x2CC0, 0x1CC0, 0x3CC0,
	0x2C0, 0x22C0, 0x12C0, 0x32C0, 0xAC0, 0x2AC0, 0x1AC0, 0x3AC0, 0x6C0, 0x26C0, 0x16C0, 0x36C0, 0xEC0, 0x2EC0, 0x1EC0, 0x3EC0,
	0x1C0, 0x21C0, 0x11C0, 0x31C0, 0x9C0, 0x29C0, 0x19C0, 0x39C0, 0x5C0, 0x25C0, 0x15C0, 0x35C0, 0xDC0, 0x2DC0, 0x1DC0, 0x3DC0,
	0x3C0, 0x23C0, 0x13C0, 0x33C0, 0xBC0, 0x2BC0, 0x1BC0, 0x3BC0, 0x7C0, 0x27C0, 0x17C0, 0x37C0, 0xFC0, 0x2FC0, 0x1FC0, 0x3FC0,
	0x20, 0x2020, 0x1020, 0x3020, 0x820, 0x2820, 0x1820, 0x3820, 0x420, 0x2420, 0x1420, 0x3420, 0xC20, 0x2C20, 0x1C20, 0x3C20,
	0x220, 0x2220, 0x1220, 0x3220, 0xA20, 0x2A20, 0x1A20, 0x3A20, 0x620, 0x2620, 0x1620, 0x3620, 0xE20, 0x2E20, 0x1E20, 0x3E20,
	0x120, 0x2120, 0x1120, 0x3120, 0x920, 0x2920, 0x1920, 0x3920, 0x520, 0x2520, 0x1520, 0x3520, 0xD20, 0x2D20, 0x1D20, 0x3D20,
	0x320, 0x2320, 0x1320, 0x3320, 0xB20, 0x2B20, 0x1B20, 0x3B20, 0x720, 0x2720, 0x1720, 0x3720, 0xF20, 0x2F20, 0x1F20, 0x3F20,
	0xA0, 0x20A0, 0x10A0, 0x30A0, 0x8A0, 0x28A0, 0x18A0, 0x38A0, 0x4A0, 0x24A0, 0x14A0, 0x34A0, 0xCA0, 0x2CA0, 0x1CA0, 0x3CA0,
	0x2A0, 0x22A0, 0x12A0, 0x32A0, 0xAA0, 0x2AA0, 0x1AA0, 0x3AA0, 0x6A0, 0x26A0, 0x16A0, 0x36A0, 0xEA0, 0x2EA0, 0x1EA0, 0x3EA0,
	0x1A0, 0x21A0, 0x11A0, 0x31A0, 0x9A0, 0x29A0, 0x19A0, 0x39A0, 0x5A0, 0x25A0, 0x15A0, 0x35A0, 0xDA0, 0x2DA0, 0x1DA0, 0x3DA0,
	0x3A0, 0x23A0, 0x13A0, 0x33A0, 0xBA0, 0x2BA0, 0x1BA0, 0x3BA0, 0x7A0, 0x27A0, 0x17A0, 0x37A0, 0xFA0, 0x2FA0, 0x1FA0, 0x3FA0,
	0x60, 0x2060, 0x1060, 0x3060, 0x860, 0x2860, 0x1860, 0x3860, 0x460, 0x2460, 0x1460, 0x3460, 0xC60, 0x2C60, 0x1C60, 0x3C60,
	0x260, 0x2260, 0x1260, 0x3260, 0xA60, 0x2A60, 0x1A60, 0x3A60, 0x660, 0x2660, 0x1660, 0x3660, 0xE60, 0x2E60, 0x1E60, 0x3E60,
	0x160, 0x2160, 0x1160, 0x3160, 0x960, 0x2960, 0x1960, 0x3960, 0x560, 0x2560, 0x1560, 0x3560, 0xD60, 0x2D60, 0x1D60, 0x3D60,
	0x360, 0x2360, 0x1360, 0x3360, 0xB60, 0x2B60, 0x1B60, 0x3B60, 0x760, 0x2760, 0x1760, 0x3760, 0xF60, 0x2F60, 0x1F60, 0x3F60,
	0xE0, 0x20E0, 0x10E0, 0x30E0, 0x8E0, 0x28E0, 0x18E0, 0x38E0, 0x4E0, 0x24E0, 0x14E0, 0x34E0, 0xCE0, 0x2CE0, 0x1CE0, 0x3CE0,
	0x2E0, 0x22E0, 0x12E0, 0x32E0, 0xAE0, 0x2AE0, 0x1AE0, 0x3AE0, 0x6E0, 0x26E0, 0x16E0, 0x36E0, 0xEE0, 0x2EE0, 0x1EE0, 0x3EE0,
	0x1E0, 0x21E0, 0x11E0, 0x31E0, 0x9E0, 0x29E0, 0x19E0, 0x39E0, 0x5E0, 0x25E0, 0x15E0, 0x35E0, 0xDE0, 0x2DE0, 0x1DE0, 0x3DE0,
	0x3E0, 0x23E0, 0x13E0, 0x33E0, 0xBE0, 0x2BE0, 0x1BE0, 0x3BE0, 0x7E0, 0x27E0, 0x17E0, 0x37E0, 0xFE0, 0x2FE0, 0x1FE0, 0x3FE0,
	0x10, 0x2010, 0x1010, 0x3010, 0x810, 0x2810, 0x1810, 0x3810, 0x410, 0x2410, 0x1410, 0x3410, 0xC10, 0x2C10, 0x1C10, 0x3C10,
	0x210, 0x2210, 0x1210, 0x3210, 0xA10, 0x2A10, 0x1A10, 0x3A10, 0x610, 0x2610, 0x1610, 0x3610, 0xE10, 0x2E10, 0x1E10, 0x3E10,
	0x110, 0x2110, 0x1110, 0x3110, 0x910, 0x2910, 0x1910, 0x3910, 0x510, 0x2510, 0x1510, 0x3510, 0xD10, 0x2D10, 0x1D10, 0x3D10,
	0x310, 0x2310, 0x1310, 0x3310, 0xB10, 0x2B10, 0x1B10, 0x3B10, 0x710, 0x2710, 0x1710, 0x3710, 0xF10, 0x2F10, 0x1F10, 0x3F10,
	0x90, 0x2090, 0x1090, 0x3090, 0x890, 0x2890, 0x1890, 0x3890, 0x490, 0x2490, 0x1490, 0x3490, 0xC90, 0x2C90, 0x1C90, 0x3C90,
	0x290, 0x2290, 0x1290, 0x3290, 0xA90, 0x2A90, 0x1A90, 0x3A90, 0x690, 0x2690, 0x1690, 0x3690, 0xE90, 0x2E90, 0x1E90, 0x3E90,
	0x190, 0x2190, 0x1190, 0x3190, 0x990, 0x2990, 0x1990, 0x3990, 0x590, 0x2590, 0x1590, 0x3590, 0xD90, 0x2D90, 0x1D90, 0x3D90,
	0x390, 0x2390, 0x1390, 0x3390, 0xB90, 0x2B90, 0x1B90, 0x3B90, 0x790, 0x2790, 0x1790, 0x3790, 0xF90, 0x2F90, 0x1F90, 0x3F90,
	0x50, 0x2050, 0x1050, 0x3050, 0x850, 0x2850, 0x1850, 0x3850, 0x450, 0x2450, 0x1450, 0x3450, 0xC50, 0x2C50, 0x1C50, 0x3C50,
	0x250, 0x2250, 0x1250, 0x3250, 0xA50, 0x2A50, 0x1A50, 0x3A50, 0x650, 0x2650, 0x1650, 0x3650, 0xE50, 0x2E50, 0x1E50, 0x3E50,
	0x150, 0x2150, 0x1150, 0x3150, 0x950, 0x2950, 0x1950, 0x3950, 0x550, 0x2550, 0x1550, 0x3550, 0xD50, 0x2D50, 0x1D50, 0x3D50,
	0x350, 0x2350, 0x1350, 0x3350, 0xB50, 0x2B50, 0x1B50, 0x3B50, 0x750, 0x2750, 0x1750, 0x3750, 0xF50, 0x2F50, 0x1F50, 0x3F50,
	0xD0, 0x20D0, 0x10D0, 0x30D0, 0x8D0, 0x28D0, 0x18D0, 0x38D0, 0x4D0, 0x24D0, 0x14D0, 0x34D0, 0xCD0, 0x2CD0, 0x1CD0, 0x3CD0,
	0x2D0, 0x22D0, 0x12D0, 0x32D0, 0xAD0, 0x2AD0, 0x1AD0, 0x3AD0, 0x6D0, 0x26D0, 0x16D0, 0x36D0, 0xED0, 0x2ED0, 0x1ED0, 0x3ED0,
	0x1D0, 0x21D0, 0x11D0, 0x31D0, 0x9D0, 0x29D0, 0x19D0, 0x39D0, 0x5D0, 0x25D0, 0x15D0, 0x35D0, 0xDD0, 0x2DD0, 0x1DD0, 0x3DD0,
	0x3D0, 0x23D0, 0x13D0, 0x33D0, 0xBD0, 0x2BD0, 0x1BD0, 0x3BD0, 0x7D0, 0x27D0, 0x17D0, 0x37D0, 0xFD0, 0x2FD0, 0x1FD0, 0x3FD0,
	0x30, 0x2030, 0x1030, 0x3030, 0x830, 0x2830, 0x1830, 0x3830, 0x430, 0x2430, 0x1430, 0x3430, 0xC30, 0x2C30, 0x1C30, 0x3C30,
	0x230, 0x2230, 0x1230, 0x3230, 0xA30, 0x2A30, 0x1A30, 0x3A30, 0x630, 0x2630, 0x1630, 0x3630, 0xE30, 0x2E30, 0x1E30, 0x3E30,
	0x130, 0x2130, 0x1130, 0x3130, 0x930, 0x2930, 0x1930, 0x3930, 0x530, 0x2530, 0x1530, 0x3530, 0xD30, 0x2D30, 0x1D30, 0x3D30,
	0x330, 0x2330, 0x1330, 0x3330, 0xB30, 0x2B30, 0x1B30, 0x3B30, 0x730, 0x2730, 0x1730, 0x3730, 0xF30, 0x2F30, 0x1F30, 0x3F30,
	0xB0, 0x20B0, 0x10B0, 0x30B0, 0x8B0, 0x28B0, 0x18B0, 0x38B0, 0x4B0, 0x24B0, 0x14B0, 0x34B0, 0xCB0, 0x2CB0, 0x1CB0, 0x3CB0,
	0x2B0, 0x22B0, 0x12B0, 0x32B0, 0xAB0, 0x2AB0, 0x1AB0, 0x3AB0, 0x6B0, 0x26B0, 0x16B0, 0x36B0, 0xEB0, 0x2EB0, 0x1EB0, 0x3EB0,
	0x1B0, 0x21B0, 0x11B0, 0x31B0, 0x9B0, 0x29B0, 0x19B0, 0x39B0, 0x5B0, 0x25B0, 0x15B0, 0x35B0, 0xDB0, 0x2DB0, 0x1DB0, 0x3DB0,
	0x3B0, 0x23B0, 0x13B0, 0x33B0, 0xBB0, 0x2BB0, 0x1BB0, 0x3BB0, 0x7B0, 0x27B0, 0x17B0, 0x37B0, 0xFB0, 0x2FB0, 0x1FB0, 0x3FB0,
	0x70, 0x2070, 0x1070, 0x3070, 0x870, 0x2870, 0x1870, 0x3870, 0x470, 0x2470, 0x1470, 0x3470, 0xC70, 0x2C70, 0x1C70, 0x3C70,
	0x270, 0x2270, 0x1270, 0x3270, 0xA70, 0x2A70, 0x1A70, 0x3A70, 0x670, 0x2670, 0x1670, 0x3670, 0xE70, 0x2E70, 0x1E70, 0x3E70,
	0x170, 0x2170, 0x1170, 0x3170, 0x970, 0x2970, 0x1970, 0x3970, 0x570, 0x2570, 0x1570, 0x3570, 0xD70, 0x2D70, 0x1D70, 0x3D70,
	0x370, 0x2370, 0x1370, 0x3370, 0xB70, 0x2B70, 0x1B70, 0x3B70, 0x770, 0x2770, 0x1770, 0x3770, 0xF70, 0x2F70, 0x1F70, 0x3F70,
	0xF0, 0x20F0, 0x10F0, 0x30F0, 0x8F0, 0x28F0, 0x18F0, 0x38F0, 0x4F0, 0x24F0, 0x14F0, 0x34F0, 0xCF0, 0x2CF0, 0x1CF0, 0x3CF0,
	0x2F0, 0x22F0, 0x12F0, 0x32F0, 0xAF0, 0x2AF0, 0x1AF0, 0x3AF0, 0x6F0, 0x26F0, 0x16F0, 0x36F0, 0xEF0, 0x2EF0, 0x1EF0, 0x3EF0,
	0x1F0, 0x21F0, 0x11F0, 0x31F0, 0x9F0, 0x29F0, 0x19F0, 0x39F0, 0x5F0, 0x25F0, 0x15F0, 0x35F0, 0xDF0, 0x2DF0, 0x1DF0, 0x3DF0,
	0x3F0, 0x23F0, 0x13F0, 0x33F0, 0xBF0, 0x2BF0, 0x1BF0, 0x3BF0, 0x7F0, 0x27F0, 0x17F0, 0x37F0, 0xFF0, 0x2FF0, 0x1FF0, 0x3FF0,
	0x8, 0x2008, 0x1008, 0x3008, 0x808, 0x2808, 0x1808, 0x3808, 0x408, 0x2408, 0x1408, 0x3408, 0xC08, 0x2C08, 0x1C08, 0x3C08,
	0x208, 0x2208, 0x1208, 0x3208, 0xA08, 0x2A08, 0x1A08, 0x3A08, 0x608, 0x2608, 0x1608, 0x3608, 0xE08, 0x2E08, 0x1E08, 0x3E08,
	0x108, 0x2108, 0x1108, 0x3108, 0x908, 0x2908, 0x1908, 0x3908, 0x508, 0x2508, 0x1508, 0x3508, 0xD08, 0x2D08, 0x1D08, 0x3D08,
	0x308, 0x2308, 0x1308, 0x3308, 0xB08, 0x2B08, 0x1B08, 0x3B08, 0x708, 0x2708, 0x1708, 0x3708, 0xF08, 0x2F08, 0x1F08, 0x3F08,
	0x88, 0x2088, 0x1088, 0x3088, 0x888, 0x2888, 0x1888, 0x3888, 0x488, 0x2488, 0x1488, 0x3488, 0xC88, 0x2C88, 0x1C88, 0x3C88,
	0x288, 0x2288, 0x1288, 0x3288, 0xA88, 0x2A88, 0x1A88, 0x3A88, 0x688, 0x2688, 0x1688, 0x3688, 0xE88, 0x2E88, 0x1E88, 0x3E88,
	0x188, 0x2188, 0x1188, 0x3188, 0x988, 0x2988, 0x1988, 0x3988, 0x588, 0x2588, 0x1588, 0x3588, 0xD88, 0x2D88, 0x1D88, 0x3D88,
	0x388, 0x2388, 0x1388, 0x3388, 0xB88, 0x2B88, 0x1B88, 0x3B88, 0x788, 0x2788, 0x1788, 0x3788, 0xF88, 0x2F88, 0x1F88, 0x3F88,
	0x48, 0x2048, 0x1048, 0x3048, 0x848, 0x2848, 0x1848, 0x3848, 0x448, 0x2448, 0x1448, 0x3448, 0xC48, 0x2C48, 0x1C48, 0x3C48,
	0x248, 0x2248, 0x1248, 0x3248, 0xA48, 0x2A48, 0x1A48, 0x3A48, 0x648, 0x2648, 0x1648, 0x3648, 0xE48, 0x2E48, 0x1E48, 0x3E48,
	0x148, 0x2148, 0x1148, 0x3148, 0x948, 0x2948, 0x1948, 0x3948, 0x548, 0x2548, 0x1548, 0x3548, 0xD48, 0x2D48, 0x1D48, 0x3D48,
	0x348, 0x2348, 0x1348, 0x3348, 0xB48, 0x2B48, 0x1B48, 0x3B48, 0x748, 0x2748, 0x1748, 0x3748, 0xF48, 0x2F48, 0x1F48, 0x3F48,
	0xC8, 0x20C8, 0x10C8, 0x30C8, 0x8C8, 0x28C8, 0x18C8, 0x38C8, 0x4C8, 0x24C8, 0x14C8, 0x34C8, 0xCC8, 0x2CC8, 0x1CC8, 0x3CC8,
	0x2C8, 0x22C8, 0x12C8, 0x32C8, 0xAC8, 0x2AC8, 0x1AC8, 0x3AC8, 0x6C8, 0x26C8, 0x16C8, 0x36C8, 0xEC8, 0x2EC8, 0x1EC8, 0x3EC8,
	0x1C8, 0x21C8, 0x11C8, 0x31C8, 0x9C8, 0x29C8, 0x19C8, 0x39C8, 0x5C8, 0x25C8, 0x15C8, 0x35C8, 0xDC8, 0x2DC8, 0x1DC8, 0x3DC8,
	0x3C8, 0x23C8, 0x13C8, 0x33C8, 0xBC8, 0x2BC8, 0x1BC8, 0x3BC8, 0x7C8, 0x27C8, 0x17C8, 0x37C8, 0xFC8, 0x2FC8, 0x1FC8, 0x3FC8,
	0x28, 0x2028, 0x1028, 0x3028, 0x828, 0x2828, 0x1828, 0x3828, 0x428, 0x2428, 0x1428, 0x3428, 0xC28, 0x2C28, 0x1C28, 0x3C28,
	0x228, 0x2228, 0x1228, 0x3228, 0xA28, 0x2A28, 0x1A28, 0x3A28, 0x628, 0x2628, 0x1628, 0x3628, 0xE28, 0x2E28, 0x1E28, 0x3E28,
	0x128, 0x2128, 0x1128, 0x3128, 0x928, 0x2928, 0x1928, 0x3928, 0x528, 0x2528, 0x1528, 0x3528, 0xD28, 0x2D28, 0x1D28, 0x3D28,
	0x328, 0x2328, 0x1328, 0x3328, 0xB28, 0x2B28, 0x1B28, 0x3B28, 0x728, 0x2728, 0x1728, 0x3728, 0xF28, 0x2F28, 0x1F28, 0x3F28,
	0xA8, 0x20A8, 0x10A8, 0x30A8, 0x8A8, 0x28A8, 0x18A8, 0x38A8, 0x4A8, 0x24A8, 0x14A8, 0x34A8, 0xCA8, 0x2CA8, 0x1CA8, 0x3CA8,
	0x2A8, 0x22A8, 0x12A8, 0x32A8, 0xAA8, 0x2AA8, 0x1AA8, 0x3AA8, 0x6A8, 0x26A8, 0x16A8, 0x36A8, 0xEA8, 0x2EA8, 0x1EA8, 0x3EA8,
	0x1A8, 0x21A8, 0x11A8, 0x31A8, 0x9A8, 0x29A8, 0x19A8, 0x39A8, 0x5A8, 0x25A8, 0x15A8, 0x35A8, 0xDA8, 0x2DA8, 0x1DA8, 0x3DA8,
	0x3A8, 0x23A8, 0x13A8, 0x33A8, 0xBA8, 0x2BA8, 0x1BA8, 0x3BA8, 0x7A8, 0x27A8, 0x17A8, 0x37A8, 0xFA8, 0x2FA8, 0x1FA8, 0x3FA8,
	0x68, 0x2068, 0x1068, 0x3068, 0x868, 0x2868, 0x1868, 0x3868, 0x468, 0x2468, 0x1468, 0x3468, 0xC68, 0x2C68, 0x1C68, 0x3C68,
	0x268, 0x2268, 0x1268, 0x3268, 0xA68, 0x2A68, 0x1A68, 0x3A68, 0x668, 0x2668, 0x1668, 0x3668, 0xE68, 0x2E68, 0x1E68, 0x3E68,
	0x168, 0x2168, 0x1168, 0x3168, 0x968, 0x2968, 0x1968, 0x3968, 0x568, 0x2568, 0x1568, 0x3568, 0xD68, 0x2D68, 0x1D68, 0x3D68,
	0x368, 0x2368, 0x1368, 0x3368, 0xB68, 0x2B68, 0x1B68, 0x3B68, 0x768, 0x2768, 0x1768, 0x3768, 0xF68, 0x2F68, 0x1F68, 0x3F68,
	0xE8, 0x20E8, 0x10E8, 0x30E8, 0x8E8, 0x28E8, 0x18E8, 0x38E8, 0x4E8, 0x24E8, 0x14E8, 0x34E8, 0xCE8, 0x2CE8, 0x1CE8, 0x3CE8,
	0x2E8, 0x22E8, 0x12E8, 0x32E8, 0xAE8, 0x2AE8, 0x1AE8, 0x3AE8, 0x6E8, 0x26E8, 0x16E8, 0x36E8, 0xEE8, 0x2EE8, 0x1EE8, 0x3EE8,
	0x1E8, 0x21E8, 0x11E8, 0x31E8, 0x9E8, 0x29E8, 0x19E8, 0x39E8, 0x5E8, 0x25E8, 0x15E8, 0x35E8, 0xDE8, 0x2DE8, 0x1DE8, 0x3DE8,
	0x3E8, 0x23E8, 0x13E8, 0x33E8, 0xBE8, 0x2BE8, 0x1BE8, 0x3BE8, 0x7E8, 0x27E8, 0x17E8, 0x37E8, 0xFE8, 0x2FE8, 0x1FE8, 0x3FE8,
	0x18, 0x2018, 0x1018, 0x3018, 0x818, 0x2818, 0x1818, 0x3818, 0x418, 0x2418, 0x1418, 0x3418, 0xC18, 0x2C18, 0x1C18, 0x3C18,
	0x218, 0x2218, 0x1218, 0x3218, 0xA18, 0x2A18, 0x1A18, 0x3A18, 0x618, 0x2618, 0x1618, 0x3618, 0xE18, 0x2E18, 0x1E18, 0x3E18,
	0x118, 0x2118, 0x1118, 0x3118, 0x918, 0x2918, 0x1918, 0x3918, 0x518, 0x2518, 0x1518, 0x3518, 0xD18, 0x2D18, 0x1D18, 0x3D18,
	0x318, 0x2318, 0x1318, 0x3318, 0xB18, 0x2B18, 0x1B18, 0x3B18, 0x718, 0x2718, 0x1718, 0x3718, 0xF18, 0x2F18, 0x1F18, 0x3F18,
	0x98, 0x2098, 0x1098, 0x3098, 0x898, 0x2898, 0x1898, 0x3898, 0x498, 0x2498, 0x1498, 0x3498, 0xC98, 0x2C98, 0x1C98, 0x3C98,
	0x298, 0x2298, 0x1298, 0x3298, 0xA98, 0x2A98, 0x1A98, 0x3A98, 0x698, 0x2698, 0x1698, 0x3698, 0xE98, 0x2E98, 0x1E98, 0x3E98,
	0x198, 0x2198, 0x1198, 0x3198, 0x998, 0x2998, 0x1998, 0x3998, 0x598, 0x2598, 0x1598, 0x3598, 0xD98, 0x2D98, 0x1D98, 0x3D98,
	0x398, 0x2398, 0x1398, 0x3398, 0xB98, 0x2B98, 0x1B98, 0x3B98, 0x798, 0x2798, 0x1798, 0x3798, 0xF98, 0x2F98, 0x1F98, 0x3F98,
	0x58, 0x2058, 0x1058, 0x3058, 0x858, 0x2858, 0x1858, 0x3858, 0x458, 0x2458, 0x1458, 0x3458, 0xC58, 0x2C58, 0x1C58, 0x3C58,
	0x258, 0x2258, 0x1258, 0x3258, 0xA58, 0x2A58, 0x1A58, 0x3A58, 0x658, 0x2658, 0x1658, 0x3658, 0xE58, 0x2E58, 0x1E58, 0x3E58,
	0x158, 0x2158, 0x1158, 0x3158, 0x958, 0x2958, 0x1958, 0x3958, 0x558, 0x2558, 0x1558, 0x3558, 0xD58, 0x2D58, 0x1D58, 0x3D58,
	0x358, 0x2358, 0x1358, 0x3358, 0xB58, 0x2B58, 0x1B58, 0x3B58, 0x758, 0x2758, 0x1758, 0x3758, 0xF58, 0x2F58, 0x1F58, 0x3F58,
	0xD8, 0x20D8, 0x10D8, 0x30D8, 0x8D8, 0x28D8, 0x18D8, 0x38D8, 0x4D8, 0x24D8, 0x14D8, 0x34D8, 0xCD8, 0x2CD8, 0x1CD8, 0x3CD8,
	0x2D8, 0x22D8, 0x12D8, 0x32D8, 0xAD8, 0x2AD8, 0x1AD8, 0x3AD8, 0x6D8, 0x26D8, 0x16D8, 0x36D8, 0xED8, 0x2ED8, 0x1ED8, 0x3ED8,
	0x1D8, 0x21D8, 0x11D8, 0x31D8, 0x9D8, 0x29D8, 0x19D8, 0x39D8, 0x5D8, 0x25D8, 0x15D8, 0x35D8, 0xDD8, 0x2DD8, 0x1DD8, 0x3DD8,
	0x3D8, 0x23D8, 0x13D8, 0x33D8, 0xBD8, 0x2BD8, 0x1BD8, 0x3BD8, 0x7D8, 0x27D8, 0x17D8, 0x37D8, 0xFD8, 0x2FD8, 0x1FD8, 0x3FD8,
	0x38, 0x2038, 0x1038, 0x3038, 0x838, 0x2838, 0x1838, 0x3838, 0x438, 0x2438, 0x1438, 0x3438, 0xC38, 0x2C38, 0x1C38, 0x3C38,
	0x238, 0x2238, 0x1238, 0x3238, 0xA38, 0x2A38, 0x1A38, 0x3A38, 0x638, 0x2638, 0x1638, 0x3638, 0xE38, 0x2E38, 0x1E38, 0x3E38,
	0x138, 0x2138, 0x1138, 0x3138, 0x938, 0x2938, 0x1938, 0x3938, 0x538, 0x2538, 0x1538, 0x3538, 0xD38, 0x2D38, 0x1D38, 0x3D38,
	0x338, 0x2338, 0x1338, 0x3338, 0xB38, 0x2B38, 0x1B38, 0x3B38, 0x738, 0x2738, 0x1738, 0x3738, 0xF38, 0x2F38, 0x1F38, 0x3F38,
	0xB8, 0x20B8, 0x10B8, 0x30B8, 0x8B8, 0x28B8, 0x18B8, 0x38B8, 0x4B8, 0x24B8, 0x14B8, 0x34B8, 0xCB8, 0x2CB8, 0x1CB8, 0x3CB8,
	0x2B8, 0x22B8, 0x12B8, 0x32B8, 0xAB8, 0x2AB8, 0x1AB8, 0x3AB8, 0x6B8, 0x26B8, 0x16B8, 0x36B8, 0xEB8, 0x2EB8, 0x1EB8, 0x3EB8,
	0x1B8, 0x21B8, 0x11B8, 0x31B8, 0x9B8, 0x29B8, 0x19B8, 0x39B8, 0x5B8, 0x25B8, 0x15B8, 0x35B8, 0xDB8, 0x2DB8, 0x1DB8, 0x3DB8,
	0x3B8, 0x23B8, 0x13B8, 0x33B8, 0xBB8, 0x2BB8, 0x1BB8, 0x3BB8, 0x7B8, 0x27B8, 0x17B8, 0x37B8, 0xFB8, 0x2FB8, 0x1FB8, 0x3FB8,
	0x78, 0x2078, 0x1078, 0x3078, 0x878, 0x2878, 0x1878, 0x3878, 0x478, 0x2478, 0x1478, 0x3478, 0xC78, 0x2C78, 0x1C78, 0x3C78,
	0x278, 0x2278, 0x1278, 0x3278, 0xA78, 0x2A78, 0x1A78, 0x3A78, 0x678, 0x2678, 0x1678, 0x3678, 0xE78, 0x2E78, 0x1E78, 0x3E78,
	0x178, 0x2178, 0x1178, 0x3178, 0x978, 0x2978, 0x1978, 0x3978, 0x578, 0x2578, 0x1578, 0x3578, 0xD78, 0x2D78, 0x1D78, 0x3D78,
	0x378, 0x2378, 0x1378, 0x3378, 0xB78, 0x2B78, 0x1B78, 0x3B78, 0x778, 0x2778, 0x1778, 0x3778, 0xF78, 0x2F78, 0x1F78, 0x3F78,
	0xF8, 0x20F8, 0x10F8, 0x30F8, 0x8F8, 0x28F8, 0x18F8, 0x38F8, 0x4F8, 0x24F8, 0x14F8, 0x34F8, 0xCF8, 0x2CF8, 0x1CF8, 0x3CF8,
	0x2F8, 0x22F8, 0x12F8, 0x32F8, 0xAF8, 0x2AF8, 0x1AF8, 0x3AF8, 0x6F8, 0x26F8, 0x16F8, 0x36F8, 0xEF8, 0x2EF8, 0x1EF8, 0x3EF8,
	0x1F8, 0x21F8, 0x11F8, 0x31F8, 0x9F8, 0x29F8, 0x19F8, 0x39F8, 0x5F8, 0x25F8, 0x15F8, 0x35F8, 0xDF8, 0x2DF8, 0x1DF8, 0x3DF8,
	0x3F8, 0x23F8, 0x13F8, 0x33F8, 0xBF8, 0x2BF8, 0x1BF8, 0x3BF8, 0x7F8, 0x27F8, 0x17F8, 0x37F8, 0xFF8, 0x2FF8, 0x1FF8, 0x3FF8,
	0x4, 0x2004, 0x1004, 0x3004, 0x804, 0x2804, 0x1804, 0x3804, 0x404, 0x2404, 0x1404, 0x3404, 0xC04, 0x2C04, 0x1C04, 0x3C04,
	0x204, 0x2204, 0x1204, 0x3204, 0xA04, 0x2A04, 0x1A04, 0x3A04, 0x604, 0x2604, 0x1604, 0x3604, 0xE04, 0x2E04, 0x1E04, 0x3E04,
	0x104, 0x2104, 0x1104, 0x3104, 0x904, 0x2904, 0x1904, 0x3904, 0x504, 0x2504, 0x1504, 0x3504, 0xD04, 0x2D04, 0x1D04, 0x3D04,
	0x304, 0x2304, 0x1304, 0x3304, 0xB04, 0x2B04, 0x1B04, 0x3B04, 0x704, 0x2704, 0x1704, 0x3704, 0xF04, 0x2F04, 0x1F04, 0x3F04,
	0x84, 0x2084, 0x1084, 0x3084, 0x884, 0x2884, 0x1884, 0x3884, 0x484, 0x2484, 0x1484, 0x3484, 0xC84, 0x2C84, 0x1C84, 0x3C84,
	0x284, 0x2284, 0x1284, 0x3284, 0xA84, 0x2A84, 0x1A84, 0x3A84, 0x684, 0x2684, 0x1684, 0x3684, 0xE84, 0x2E84, 0x1E84, 0x3E84,
	0x184, 0x2184, 0x1184, 0x3184, 0x984, 0x2984, 0x1984, 0x3984, 0x584, 0x2584, 0x1584, 0x3584, 0xD84, 0x2D84, 0x1D84, 0x3D84,
	0x384, 0x2384, 0x1384, 0x3384, 0xB84, 0x2B84, 0x1B84, 0x3B84, 0x784, 0x2784, 0x1784, 0x3784, 0xF84, 0x2F84, 0x1F84, 0x3F84,
	0x44, 0x2044, 0x1044, 0x3044, 0x844, 0x2844, 0x1844, 0x3844, 0x444, 0x2444, 0x1444, 0x3444, 0xC44, 0x2C44, 0x1C44, 0x3C44,
	0x244, 0x2244, 0x1244, 0x3244, 0xA44, 0x2A44, 0x1A44, 0x3A44, 0x644, 0x2644, 0x1644, 0x3644, 0xE44, 0x2E44, 0x1E44, 0x3E44,
	0x144, 0x2144, 0x1144, 0x3144, 0x944, 0x2944, 0x1944, 0x3944, 0x544, 0x2544, 0x1544, 0x3544, 0xD44, 0x2D44, 0x1D44, 0x3D44,
	0x344, 0x2344, 0x1344, 0x3344, 0xB44, 0x2B44, 0x1B44, 0x3B44, 0x744, 0x2744, 0x1744, 0x3744, 0xF44, 0x2F44, 0x1F44, 0x3F44,
	0xC4, 0x20C4, 0x10C4, 0x30C4, 0x8C4, 0x28C4, 0x18C4, 0x38C4, 0x4C4, 0x24C4, 0x14C4, 0x34C4, 0xCC4, 0x2CC4, 0x1CC4, 0x3CC4,
	0x2C4, 0x22C4, 0x12C4, 0x32C4, 0xAC4, 0x2AC4, 0x1AC4, 0x3AC4, 0x6C4, 0x26C4, 0x16C4, 0x36C4, 0xEC4, 0x2EC4, 0x1EC4, 0x3EC4,
	0x1C4, 0x21C4, 0x11C4, 0x31C4, 0x9C4, 0x29C4, 0x19C4, 0x39C4, 0x5C4, 0x25C4, 0x15C4, 0x35C4, 0xDC4, 0x2DC4, 0x1DC4, 0x3DC4,
	0x3C4, 0x23C4, 0x13C4, 0x33C4, 0xBC4, 0x2BC4, 0x1BC4, 0x3BC4, 0x7C4, 0x27C4, 0x17C4, 0x37C4, 0xFC4, 0x2FC4, 0x1FC4, 0x3FC4,
	0x24, 0x2024, 0x1024, 0x3024, 0x824, 0x2824, 0x1824, 0x3824, 0x424, 0x2424, 0x1424, 0x3424, 0xC24, 0x2C24, 0x1C24, 0x3C24,
	0x224, 0x2224, 0x1224, 0x3224, 0xA24, 0x2A24, 0x1A24, 0x3A24, 0x624, 0x2624, 0x1624, 0x3624, 0xE24, 0x2E24, 0x1E24, 0x3E24,
	0x124, 0x2124, 0x1124, 0x3124, 0x924, 0x2924, 0x1924, 0x3924, 0x524, 0x2524, 0x1524, 0x3524, 0xD24, 0x2D24, 0x1D24, 0x3D24,
	0x324, 0x2324, 0x1324, 0x3324, 0xB24, 0x2B24, 0x1B24, 0x3B24, 0x724, 0x2724, 0x1724, 0x3724, 0xF24, 0x2F24, 0x1F24, 0x3F24,
	0xA4, 0x20A4, 0x10A4, 0x30A4, 0x8A4, 0x28A4, 0x18A4, 0x38A4, 0x4A4, 0x24A4, 0x14A4, 0x34A4, 0xCA4, 0x2CA4, 0x1CA4, 0x3CA4,
	0x2A4, 0x22A4, 0x12A4, 0x32A4, 0xAA4, 0x2AA4, 0x1AA4, 0x3AA4, 0x6A4, 0x26A4, 0x16A4, 0x36A4, 0xEA4, 0x2EA4, 0x1EA4, 0x3EA4,
	0x1A4, 0x21A4, 0x11A4, 0x31A4, 0x9A4, 0x29A4, 0x19A4, 0x39A4, 0x5A4, 0x25A4, 0x15A4, 0x35A4, 0xDA4, 0x2DA4, 0x1DA4, 0x3DA4,
	0x3A4, 0x23A4, 0x13A4, 0x33A4, 0xBA4, 0x2BA4, 0x1BA4, 0x3BA4, 0x7A4, 0x27A4, 0x17A4, 0x37A4, 0xFA4, 0x2FA4, 0x1FA4, 0x3FA4,
	0x64, 0x2064, 0x1064, 0x3064, 0x864, 0x2864, 0x1864, 0x3864, 0x464, 0x2464, 0x1464, 0x3464, 0xC64, 0x2C64, 0x1C64, 0x3C64,
	0x264, 0x2264, 0x1264, 0x3264, 0xA64, 0x2A64, 0x1A64, 0x3A64, 0x664, 0x2664, 0x1664, 0x3664, 0xE64, 0x2E64, 0x1E64, 0x3E64,
	0x164, 0x2164, 0x1164, 0x3164, 0x964, 0x2964, 0x1964, 0x3964, 0x564, 0x2564, 0x1564, 0x3564, 0xD64, 0x2D64, 0x1D64, 0x3D64,
	0x364, 0x2364, 0x1364, 0x3364, 0xB64, 0x2B64, 0x1B64, 0x3B64, 0x764, 0x2764, 0x1764, 0x3764, 0xF64, 0x2F64, 0x1F64, 0x3F64,
	0xE4, 0x20E4, 0x10E4, 0x30E4, 0x8E4, 0x28E4, 0x18E4, 0x38E4, 0x4E4, 0x24E4, 0x14E4, 0x34E4, 0xCE4, 0x2CE4, 0x1CE4, 0x3CE4,
	0x2E4, 0x22E4, 0x12E4, 0x32E4, 0xAE4, 0x2AE4, 0x1AE4, 0x3AE4, 0x6E4, 0x26E4, 0x16E4, 0x36E4, 0xEE4, 0x2EE4, 0x1EE4, 0x3EE4,
	0x1E4, 0x21E4, 0x11E4, 0x31E4, 0x9E4, 0x29E4, 0x19E4, 0x39E4, 0x5E4, 0x25E4, 0x15E4, 0x35E4, 0xDE4, 0x2DE4, 0x1DE4, 0x3DE4,
	0x3E4, 0x23E4, 0x13E4, 0x33E4, 0xBE4, 0x2BE4, 0x1BE4, 0x3BE4, 0x7E4, 0x27E4, 0x17E4, 0x37E4, 0xFE4, 0x2FE4, 0x1FE4, 0x3FE4,
	0x14, 0x2014, 0x1014, 0x3014, 0x814, 0x2814, 0x1814, 0x3814, 0x414, 0x2414, 0x1414, 0x3414, 0xC14, 0x2C14, 0x1C14, 0x3C14,
	0x214, 0x2214, 0x1214, 0x3214, 0xA14, 0x2A14, 0x1A14, 0x3A14, 0x614, 0x2614, 0x1614, 0x3614, 0xE14, 0x2E14, 0x1E14, 0x3E14,
	0x114, 0x2114, 0x1114, 0x3114, 0x914, 0x2914, 0x1914, 0x3914, 0x514, 0x2514, 0x1514, 0x3514, 0xD14, 0x2D14, 0x1D14, 0x3D14,
	0x314, 0x2314, 0x1314, 0x3314, 0xB14, 0x2B14, 0x1B14, 0x3B14, 0x714, 0x2714, 0x1714, 0x3714, 0xF14, 0x2F14, 0x1F14, 0x3F14,
	0x94, 0x2094, 0x1094, 0x3094, 0x894, 0x2894, 0x1894, 0x3894, 0x494, 0x2494, 0x1494, 0x3494, 0xC94, 0x2C94, 0x1C94, 0x3C94,
	0x294, 0x2294, 0x1294, 0x3294, 0xA94, 0x2A94, 0x1A94, 0x3A94, 0x694, 0x2694, 0x1694, 0x3694, 0xE94, 0x2E94, 0x1E94, 0x3E94,
	0x194, 0x2194, 0x1194, 0x3194, 0x994, 0x2994, 0x1994, 0x3994, 0x594, 0x2594, 0x1594, 0x3594, 0xD94, 0x2D94, 0x1D94, 0x3D94,
	0x394, 0x2394, 0x1394, 0x3394, 0xB94, 0x2B94, 0x1B94, 0x3B94, 0x794, 0x2794, 0x1794, 0x3794, 0xF94, 0x2F94, 0x1F94, 0x3F94,
	0x54, 0x2054, 0x1054, 0x3054, 0x854, 0x2854, 0x1854, 0x3854, 0x454, 0x2454, 0x1454, 0x3454, 0xC54, 0x2C54, 0x1C54, 0x3C54,
	0x254, 0x2254, 0x1254, 0x3254, 0xA54, 0x2A54, 0x1A54, 0x3A54, 0x654, 0x2654, 0x1654, 0x3654, 0xE54, 0x2E54, 0x1E54, 0x3E54,
	0x154, 0x2154, 0x1154, 0x3154, 0x954, 0x2954, 0x1954, 0x3954, 0x554, 0x2554, 0x1554, 0x3554, 0xD54, 0x2D54, 0x1D54, 0x3D54,
	0x354, 0x2354, 0x1354, 0x3354, 0xB54, 0x2B54, 0x1B54, 0x3B54, 0x754, 0x2754, 0x1754, 0x3754, 0xF54, 0x2F54, 0x1F54, 0x3F54,
	0xD4, 0x20D4, 0x10D4, 0x30D4, 0x8D4, 0x28D4, 0x18D4, 0x38D4, 0x4D4, 0x24D4, 0x14D4, 0x34D4, 0xCD4, 0x2CD4, 0x1CD4, 0x3CD4,
	0x2D4, 0x22D4, 0x12D4, 0x32D4, 0xAD4, 0x2AD4, 0x1AD4, 0x3AD4, 0x6D4, 0x26D4, 0x16D4, 0x36D4, 0xED4, 0x2ED4, 0x1ED4, 0x3ED4,
	0x1D4, 0x21D4, 0x11D4, 0x31D4, 0x9D4, 0x29D4, 0x19D4, 0x39D4, 0x5D4, 0x25D4, 0x15D4, 0x35D4, 0xDD4, 0x2DD4, 0x1DD4, 0x3DD4,
	0x3D4, 0x23D4, 0x13D4, 0x33D4, 0xBD4, 0x2BD4, 0x1BD4, 0x3BD4, 0x7D4, 0x27D4, 0x17D4, 0x37D4, 0xFD4, 0x2FD4, 0x1FD4, 0x3FD4,
	0x34, 0x2034, 0x1034, 0x3034, 0x834, 0x2834, 0x1834, 0x3834, 0x434, 0x2434, 0x1434, 0x3434, 0xC34, 0x2C34, 0x1C34, 0x3C34,
	0x234, 0x2234, 0x1234, 0x3234, 0xA34, 0x2A34, 0x1A34, 0x3A34, 0x634, 0x2634, 0x1634, 0x3634, 0xE34, 0x2E34, 0x1E34, 0x3E34,
	0x134, 0x2134, 0x1134, 0x3134, 0x934, 0x2934, 0x1934, 0x3934, 0x534, 0x2534, 0x1534, 0x3534, 0xD34, 0x2D34, 0x1D34, 0x3D34,
	0x334, 0x2334, 0x1334, 0x3334, 0xB34, 0x2B34, 0x1B34, 0x3B34, 0x734, 0x2734, 0x1734, 0x3734, 0xF34, 0x2F34, 0x1F34, 0x3F34,
	0xB4, 0x20B4, 0x10B4, 0x30B4, 0x8B4, 0x28B4, 0x18B4, 0x38B4, 0x4B4, 0x24B4, 0x14B4, 0x34B4, 0xCB4, 0x2CB4, 0x1CB4, 0x3CB4,
	0x2B4, 0x22B4, 0x12B4, 0x32B4, 0xAB4, 0x2AB4, 0x1AB4, 0x3AB4, 0x6B4, 0x26B4, 0x16B4, 0x36B4, 0xEB4, 0x2EB4, 0x1EB4, 0x3EB4,
	0x1B4, 0x21B4, 0x11B4, 0x31B4, 0x9B4, 0x29B4, 0x19B4, 0x39B4, 0x5B4, 0x25B4, 0x15B4, 0x35B4, 0xDB4, 0x2DB4, 0x1DB4, 0x3DB4,
	0x3B4, 0x23B4, 0x13B4, 0x33B4, 0xBB4, 0x2BB4, 0x1BB4, 0x3BB4, 0x7B4, 0x27B4, 0x17B4, 0x37B4, 0xFB4, 0x2FB4, 0x1FB4, 0x3FB4,
	0x74, 0x2074, 0x1074, 0x3074, 0x874, 0x2874, 0x1874, 0x3874, 0x474, 0x2474, 0x1474, 0x3474, 0xC74, 0x2C74, 0x1C74, 0x3C74,
	0x274, 0x2274, 0x1274, 0x3274, 0xA74, 0x2A74, 0x1A74, 0x3A74, 0x674, 0x2674, 0x1674, 0x3674, 0xE74, 0x2E74, 0x1E74, 0x3E74,
	0x174, 0x2174, 0x1174, 0x3174, 0x974, 0x2974, 0x1974, 0x3974, 0x574, 0x2574, 0x1574, 0x3574, 0xD74, 0x2D74, 0x1D74, 0x3D74,
	0x374, 0x2374, 0x1374, 0x3374, 0xB74, 0x2B74, 0x1B74, 0x3B74, 0x774, 0x2774, 0x1774, 0x3774, 0xF74, 0x2F74, 0x1F74, 0x3F74,
	0xF4, 0x20F4, 0x10F4, 0x30F4, 0x8F4, 0x28F4, 0x18F4, 0x38F4, 0x4F4, 0x24F4, 0x14F4, 0x34F4, 0xCF4, 0x2CF4, 0x1CF4, 0x3CF4,
	0x2F4, 0x22F4, 0x12F4, 0x32F4, 0xAF4, 0x2AF4, 0x1AF4, 0x3AF4, 0x6F4, 0x26F4, 0x16F4, 0x36F4, 0xEF4, 0x2EF4, 0x1EF4, 0x3EF4,
	0x1F4, 0x21F4, 0x11F4, 0x31F4, 0x9F4, 0x29F4, 0x19F4, 0x39F4, 0x5F4, 0x25F4, 0x15F4, 0x35F4, 0xDF4, 0x2DF4, 0x1DF4, 0x3DF4,
	0x3F4, 0x23F4, 0x13F4, 0x33F4, 0xBF4, 0x2BF4, 0x1BF4, 0x3BF4, 0x7F4, 0x27F4, 0x17F4, 0x37F4, 0xFF4, 0x2FF4, 0x1FF4, 0x3FF4,
	0xC, 0x200C, 0x100C, 0x300C, 0x80C, 0x280C, 0x180C, 0x380C, 0x40C, 0x240C, 0x140C, 0x340C, 0xC0C, 0x2C0C, 0x1C0C, 0x3C0C,
	0x20C, 0x220C, 0x120C, 0x320C, 0xA0C, 0x2A0C, 0x1A0C, 0x3A0C, 0x60C, 0x260C, 0x160C, 0x360C, 0xE0C, 0x2E0C, 0x1E0C, 0x3E0C,
	0x10C, 0x210C, 0x110C, 0x310C, 0x90C, 0x290C, 0x190C, 0x390C, 0x50C, 0x250C, 0x150C, 0x350C, 0xD0C, 0x2D0C, 0x1D0C, 0x3D0C,
	0x30C, 0x230C, 0x130C, 0x330C, 0xB0C, 0x2B0C, 0x1B0C, 0x3B0C, 0x70C, 0x270C, 0x170C, 0x370C, 0xF0C, 0x2F0C, 0x1F0C, 0x3F0C,
	0x8C, 0x208C, 0x108C, 0x308C, 0x88C, 0x288C, 0x188C, 0x388C, 0x48C, 0x248C, 0x148C, 0x348C, 0xC8C, 0x2C8C, 0x1C8C, 0x3C8C,
	0x28C, 0x228C, 0x128C, 0x328C, 0xA8C, 0x2A8C, 0x1A8C, 0x3A8C, 0x68C, 0x268C, 0x168C, 0x368C, 0xE8C, 0x2E8C, 0x1E8C, 0x3E8C,
	0x18C, 0x218C, 0x118C, 0x318C, 0x98C, 0x298C, 0x198C, 0x398C, 0x58C, 0x258C, 0x158C, 0x358C, 0xD8C, 0x2D8C, 0x1D8C, 0x3D8C,
	0x38C, 0x238C, 0x138C, 0x338C, 0xB8C, 0x2B8C, 0x1B8C, 0x3B8C, 0x78C, 0x278C, 0x178C, 0x378C, 0xF8C, 0x2F8C, 0x1F8C, 0x3F8C,
	0x4C, 0x204C, 0x104C, 0x304C, 0x84C, 0x284C, 0x184C, 0x384C, 0x44C, 0x244C, 0x144C, 0x344C, 0xC4C, 0x2C4C, 0x1C4C, 0x3C4C,
	0x24C, 0x224C, 0x124C, 0x324C, 0xA4C, 0x2A4C, 0x1A4C, 0x3A4C, 0x64C, 0x264C, 0x164C, 0x364C, 0xE4C, 0x2E4C, 0x1E4C, 0x3E4C,
	0x14C, 0x214C, 0x114C, 0x314C, 0x94C, 0x294C, 0x194C, 0x394C, 0x54C, 0x254C, 0x154C, 0x354C, 0xD4C, 0x2D4C, 0x1D4C, 0x3D4C,
	0x34C, 0x234C, 0x134C, 0x334C, 0xB4C, 0x2B4C, 0x1B4C, 0x3B4C, 0x74C, 0x274C, 0x174C, 0x374C, 0xF4C, 0x2F4C, 0x1F4C, 0x3F4C,
	0xCC, 0x20CC, 0x10CC, 0x30CC, 0x8CC, 0x28CC, 0x18CC, 0x38CC, 0x4CC, 0x24CC, 0x14CC, 0x34CC, 0xCCC, 0x2CCC, 0x1CCC, 0x3CCC,
	0x2CC, 0x22CC, 0x12CC, 0x32CC, 0xACC, 0x2ACC, 0x1ACC, 0x3ACC, 0x6CC, 0x26CC, 0x16CC, 0x36CC, 0xECC, 0x2ECC, 0x1ECC, 0x3ECC,
	0x1CC, 0x21CC, 0x11CC, 0x31CC, 0x9CC, 0x29CC, 0x19CC, 0x39CC, 0x5CC, 0x25CC, 0x15CC, 0x35CC, 0xDCC, 0x2DCC, 0x1DCC, 0x3DCC,
	0x3CC, 0x23CC, 0x13CC, 0x33CC, 0xBCC, 0x2BCC, 0x1BCC, 0x3BCC, 0x7CC, 0x27CC, 0x17CC, 0x37CC, 0xFCC, 0x2FCC, 0x1FCC, 0x3FCC,
	0x2C, 0x202C, 0x102C, 0x302C, 0x82C, 0x282C, 0x182C, 0x382C, 0x42C, 0x242C, 0x142C, 0x342C, 0xC2C, 0x2C2C, 0x1C2C, 0x3C2C,
	0x22C, 0x222C, 0x122C, 0x322C, 0xA2C, 0x2A2C, 0x1A2C, 0x3A2C, 0x62C, 0x262C, 0x162C, 0x362C, 0xE2C, 0x2E2C, 0x1E2C, 0x3E2C,
	0x12C, 0x212C, 0x112C, 0x312C, 0x92C, 0x292C, 0x192C, 0x392C, 0x52C, 0x252C, 0x152C, 0x352C, 0xD2C, 0x2D2C, 0x1D2C, 0x3D2C,
	0x32C, 0x232C, 0x132C, 0x332C, 0xB2C, 0x2B2C, 0x1B2C, 0x3B2C, 0x72C, 0x272C, 0x172C, 0x372C, 0xF2C, 0x2F2C, 0x1F2C, 0x3F2C,
	0xAC, 0x20AC, 0x10AC, 0x30AC, 0x8AC, 0x28AC, 0x18AC, 0x38AC, 0x4AC, 0x24AC, 0x14AC, 0x34AC, 0xCAC, 0x2CAC, 0x1CAC, 0x3CAC,
	0x2AC, 0x22AC, 0x12AC, 0x32AC, 0xAAC, 0x2AAC, 0x1AAC, 0x3AAC, 0x6AC, 0x26AC, 0x16AC, 0x36AC, 0xEAC, 0x2EAC, 0x1EAC, 0x3EAC,
	0x1AC, 0x21AC, 0x11AC, 0x31AC, 0x9AC, 0x29AC, 0x19AC, 0x39AC, 0x5AC, 0x25AC, 0x15AC, 0x35AC, 0xDAC, 0x2DAC, 0x1DAC, 0x3DAC,
	0x3AC, 0x23AC, 0x13AC, 0x33AC, 0xBAC, 0x2BAC, 0x1BAC, 0x3BAC, 0x7AC, 0x27AC, 0x17AC, 0x37AC, 0xFAC, 0x2FAC, 0x1FAC, 0x3FAC,
	0x6C, 0x206C, 0x106C, 0x306C, 0x86C, 0x286C, 0x186C, 0x386C, 0x46C, 0x246C, 0x146C, 0x346C, 0xC6C, 0x2C6C, 0x1C6C, 0x3C6C,
	0x26C, 0x226C, 0x126C, 0x326C, 0xA6C, 0x2A6C, 0x1A6C, 0x3A6C, 0x66C, 0x266C, 0x166C, 0x366C, 0xE6C, 0x2E6C, 0x1E6C, 0x3E6C,
	0x16C, 0x216C, 0x116C, 0x316C, 0x96C, 0x296C, 0x196C, 0x396C, 0x56C, 0x256C, 0x156C, 0x356C, 0xD6C, 0x2D6C, 0x1D6C, 0x3D6C,
	0x36C, 0x236C, 0x136C, 0x336C, 0xB6C, 0x2B6C, 0x1B6C, 0x3B6C, 0x76C, 0x276C, 0x176C, 0x376C, 0xF6C, 0x2F6C, 0x1F6C, 0x3F6C,
	0xEC, 0x20EC, 0x10EC, 0x30EC, 0x8EC, 0x28EC, 0x18EC, 0x38EC, 0x4EC, 0x24EC, 0x14EC, 0x34EC, 0xCEC, 0x2CEC, 0x1CEC, 0x3CEC,
	0x2EC, 0x22EC, 0x12EC, 0x32EC, 0xAEC, 0x2AEC, 0x1AEC, 0x3AEC, 0x6EC, 0x26EC, 0x16EC, 0x36EC, 0xEEC, 0x2EEC, 0x1EEC, 0x3EEC,
	0x1EC, 0x21EC, 0x11EC, 0x31EC, 0x9EC, 0x29EC, 0x19EC, 0x39EC, 0x5EC, 0x25EC, 0x15EC, 0x35EC, 0xDEC, 0x2DEC, 0x1DEC, 0x3DEC,
	0x3EC, 0x23EC, 0x13EC, 0x33EC, 0xBEC, 0x2BEC, 0x1BEC, 0x3BEC, 0x7EC, 0x27EC, 0x17EC, 0x37EC, 0xFEC, 0x2FEC, 0x1FEC, 0x3FEC,
	0x1C, 0x201C, 0x101C, 0x301C, 0x81C, 0x281C, 0x181C, 0x381C, 0x41C, 0x241C, 0x141C, 0x341C, 0xC1C, 0x2C1C, 0x1C1C, 0x3C1C,
	0x21C, 0x221C, 0x121C, 0x321C, 0xA1C, 0x2A1C, 0x1A1C, 0x3A1C, 0x61C, 0x261C, 0x161C, 0x361C, 0xE1C, 0x2E1C, 0x1E1C, 0x3E1C,
	0x11C, 0x211C, 0x111C, 0x311C, 0x91C, 0x291C, 0x191C, 0x391C, 0x51C, 0x251C, 0x151C, 0x351C, 0xD1C, 0x2D1C, 0x1D1C, 0x3D1C,
	0x31C, 0x231C, 0x131C, 0x331C, 0xB1C, 0x2B1C, 0x1B1C, 0x3B1C, 0x71C, 0x271C, 0x171C, 0x371C, 0xF1C, 0x2F1C, 0x1F1C, 0x3F1C,
	0x9C, 0x209C, 0x109C, 0x309C, 0x89C, 0x289C, 0x189C, 0x389C, 0x49C, 0x249C, 0x149C, 0x349C, 0xC9C, 0x2C9C, 0x1C9C, 0x3C9C,
	0x29C, 0x229C, 0x129C, 0x329C, 0xA9C, 0x2A9C, 0x1A9C, 0x3A9C, 0x69C, 0x269C, 0x169C, 0x369C, 0xE9C, 0x2E9C, 0x1E9C, 0x3E9C,
	0x19C, 0x219C, 0x119C, 0x319C, 0x99C, 0x299C, 0x199C, 0x399C, 0x59C, 0x259C, 0x159C, 0x359C, 0xD9C, 0x2D9C, 0x1D9C, 0x3D9C,
	0x39C, 0x239C, 0x139C, 0x339C, 0xB9C, 0x2B9C, 0x1B9C, 0x3B9C, 0x79C, 0x279C, 0x179C, 0x379C, 0xF9C, 0x2F9C, 0x1F9C, 0x3F9C,
	0x5C, 0x205C, 0x105C, 0x305C, 0x85C, 0x285C, 0x185C, 0x385C, 0x45C, 0x245C, 0x145C, 0x345C, 0xC5C, 0x2C5C, 0x1C5C, 0x3C5C,
	0x25C, 0x225C, 0x125C, 0x325C, 0xA5C, 0x2A5C, 0x1A5C, 0x3A5C, 0x65C, 0x265C, 0x165C, 0x365C, 0xE5C, 0x2E5C, 0x1E5C, 0x3E5C,
	0x15C, 0x215C, 0x115C, 0x315C, 0x95C, 0x295C, 0x195C, 0x395C, 0x55C, 0x255C, 0x155C, 0x355C, 0xD5C, 0x2D5C, 0x1D5C, 0x3D5C,
	0x35C, 0x235C, 0x135C, 0x335C, 0xB5C, 0x2B5C, 0x1B5C, 0x3B5C, 0x75C, 0x275C, 0x175C, 0x375C, 0xF5C, 0x2F5C, 0x1F5C, 0x3F5C,
	0xDC, 0x20DC, 0x10DC, 0x30DC, 0x8DC, 0x28DC, 0x18DC, 0x38DC, 0x4DC, 0x24DC, 0x14DC, 0x34DC, 0xCDC, 0x2CDC, 0x1CDC, 0x3CDC,
	0x2DC, 0x22DC, 0x12DC, 0x32DC, 0xADC, 0x2ADC, 0x1ADC, 0x3ADC, 0x6DC, 0x26DC, 0x16DC, 0x36DC, 0xEDC, 0x2EDC, 0x1EDC, 0x3EDC,
	0x1DC, 0x21DC, 0x11DC, 0x31DC, 0x9DC, 0x29DC, 0x19DC, 0x39DC, 0x5DC, 0x25DC, 0x15DC, 0x35DC, 0xDDC, 0x2DDC, 0x1DDC, 0x3DDC,
	0x3DC, 0x23DC, 0x13DC, 0x33DC, 0xBDC, 0x2BDC, 0x1BDC, 0x3BDC, 0x7DC, 0x27DC, 0x17DC, 0x37DC, 0xFDC, 0x2FDC, 0x1FDC, 0x3FDC,
	0x3C, 0x203C, 0x103C, 0x303C, 0x83C, 0x283C, 0x183C, 0x383C, 0x43C, 0x243C, 0x143C, 0x343C, 0xC3C, 0x2C3C, 0x1C3C, 0x3C3C,
	0x23C, 0x223C, 0x123C, 0x323C, 0xA3C, 0x2A3C, 0x1A3C, 0x3A3C, 0x63C, 0x263C, 0x163C, 0x363C, 0xE3C, 0x2E3C, 0x1E3C, 0x3E3C,
	0x13C, 0x213C, 0x113C, 0x313C, 0x93C, 0x293C, 0x193C, 0x393C, 0x53C, 0x253C, 0x153C, 0x353C, 0xD3C, 0x2D3C, 0x1D3C, 0x3D3C,
	0x33C, 0x233C, 0x133C, 0x333C, 0xB3C, 0x2B3C, 0x1B3C, 0x3B3C, 0x73C, 0x273C, 0x173C, 0x373C, 0xF3C, 0x2F3C, 0x1F3C, 0x3F3C,
	0xBC, 0x20BC, 0x10BC, 0x30BC, 0x8BC, 0x28BC, 0x18BC, 0x38BC, 0x4BC, 0x24BC, 0x14BC, 0x34BC, 0xCBC, 0x2CBC, 0x1CBC, 0x3CBC,
	0x2BC, 0x22BC, 0x12BC, 0x32BC, 0xABC, 0x2ABC, 0x1ABC, 0x3ABC, 0x6BC, 0x26BC, 0x16BC, 0x36BC, 0xEBC, 0x2EBC, 0x1EBC, 0x3EBC,
	0x1BC, 0x21BC, 0x11BC, 0x31BC, 0x9BC, 0x29BC, 0x19BC, 0x39BC, 0x5BC, 0x25BC, 0x15BC, 0x35BC, 0xDBC, 0x2DBC, 0x1DBC, 0x3DBC,
	0x3BC, 0x23BC, 0x13BC, 0x33BC, 0xBBC, 0x2BBC, 0x1BBC, 0x3BBC, 0x7BC, 0x27BC, 0x17BC, 0x37BC, 0xFBC, 0x2FBC, 0x1FBC, 0x3FBC,
	0x7C, 0x207C, 0x107C, 0x307C, 0x87C, 0x287C, 0x187C, 0x387C, 0x47C, 0x247C, 0x147C, 0x347C, 0xC7C, 0x2C7C, 0x1C7C, 0x3C7C,
	0x27C, 0x227C, 0x127C, 0x327C, 0xA7C, 0x2A7C, 0x1A7C, 0x3A7C, 0x67C, 0x267C, 0x167C, 0x367C, 0xE7C, 0x2E7C, 0x1E7C, 0x3E7C,
	0x17C, 0x217C, 0x117C, 0x317C, 0x97C, 0x297C, 0x197C, 0x397C, 0x57C, 0x257C, 0x157C, 0x357C, 0xD7C, 0x2D7C, 0x1D7C, 0x3D7C,
	0x37C, 0x237C, 0x137C, 0x337C, 0xB7C, 0x2B7C, 0x1B7C, 0x3B7C, 0x77C, 0x277C, 0x177C, 0x377C, 0xF7C, 0x2F7C, 0x1F7C, 0x3F7C,
	0xFC, 0x20FC, 0x10FC, 0x30FC, 0x8FC, 0x28FC, 0x18FC, 0x38FC, 0x4FC, 0x24FC, 0x14FC, 0x34FC, 0xCFC, 0x2CFC, 0x1CFC, 0x3CFC,
	0x2FC, 0x22FC, 0x12FC, 0x32FC, 0xAFC, 0x2AFC, 0x1AFC, 0x3AFC, 0x6FC, 0x26FC, 0x16FC, 0x36FC, 0xEFC, 0x2EFC, 0x1EFC, 0x3EFC,
	0x1FC, 0x21FC, 0x11FC, 0x31FC, 0x9FC, 0x29FC, 0x19FC, 0x39FC, 0x5FC, 0x25FC, 0x15FC, 0x35FC, 0xDFC, 0x2DFC, 0x1DFC, 0x3DFC,
	0x3FC, 0x23FC, 0x13FC, 0x33FC, 0xBFC, 0x2BFC, 0x1BFC, 0x3BFC, 0x7FC, 0x27FC, 0x17FC, 0x37FC, 0xFFC, 0x2FFC, 0x1FFC, 0x3FFC,
	0x2, 0x2002, 0x1002, 0x3002, 0x802, 0x2802, 0x1802, 0x3802, 0x402, 0x2402, 0x1402, 0x3402, 0xC02, 0x2C02, 0x1C02, 0x3C02,
	0x202, 0x2202, 0x1202, 0x3202, 0xA02, 0x2A02, 0x1A02, 0x3A02, 0x602, 0x2602, 0x1602, 0x3602, 0xE02, 0x2E02, 0x1E02, 0x3E02,
	0x102, 0x2102, 0x1102, 0x3102, 0x902, 0x2902, 0x1902, 0x3902, 0x502, 0x2502, 0x1502, 0x3502, 0xD02, 0x2D02, 0x1D02, 0x3D02,
	0x302, 0x2302, 0x1302, 0x3302, 0xB02, 0x2B02, 0x1B02, 0x3B02, 0x702, 0x2702, 0x1702, 0x3702, 0xF02, 0x2F02, 0x1F02, 0x3F02,
	0x82, 0x2082, 0x1082, 0x3082, 0x882, 0x2882, 0x1882, 0x3882, 0x482, 0x2482, 0x1482, 0x3482, 0xC82, 0x2C82, 0x1C82, 0x3C82,
	0x282, 0x2282, 0x1282, 0x3282, 0xA82, 0x2A82, 0x1A82, 0x3A82, 0x682, 0x2682, 0x1682, 0x3682, 0xE82, 0x2E82, 0x1E82, 0x3E82,
	0x182, 0x2182, 0x1182, 0x3182, 0x982, 0x2982, 0x1982, 0x3982, 0x582, 0x2582, 0x1582, 0x3582, 0xD82, 0x2D82, 0x1D82, 0x3D82,
	0x382, 0x2382, 0x1382, 0x3382, 0xB82, 0x2B82, 0x1B82, 0x3B82, 0x782, 0x2782, 0x1782, 0x3782, 0xF82, 0x2F82, 0x1F82, 0x3F82,
	0x42, 0x2042, 0x1042, 0x3042, 0x842, 0x2842, 0x1842, 0x3842, 0x442, 0x2442, 0x1442, 0x3442, 0xC42, 0x2C42, 0x1C42, 0x3C42,
	0x242, 0x2242, 0x1242, 0x3242, 0xA42, 0x2A42, 0x1A42, 0x3A42, 0x642, 0x2642, 0x1642, 0x3642, 0xE42, 0x2E42, 0x1E42, 0x3E42,
	0x142, 0x2142, 0x1142, 0x3142, 0x942, 0x2942, 0x1942, 0x3942, 0x542, 0x2542, 0x1542, 0x3542, 0xD42, 0x2D42, 0x1D42, 0x3D42,
	0x342, 0x2342, 0x1342, 0x3342, 0xB42, 0x2B42, 0x1B42, 0x3B42, 0x742, 0x2742, 0x1742, 0x3742, 0xF42, 0x2F42, 0x1F42, 0x3F42,
	0xC2, 0x20C2, 0x10C2, 0x30C2, 0x8C2, 0x28C2, 0x18C2, 0x38C2, 0x4C2, 0x24C2, 0x14C2, 0x34C2, 0xCC2, 0x2CC2, 0x1CC2, 0x3CC2,
	0x2C2, 0x22C2, 0x12C2, 0x32C2, 0xAC2, 0x2AC2, 0x1AC2, 0x3AC2, 0x6C2, 0x26C2, 0x16C2, 0x36C2, 0xEC2, 0x2EC2, 0x1EC2, 0x3EC2,
	0x1C2, 0x21C2, 0x11C2, 0x31C2, 0x9C2, 0x29C2, 0x19C2, 0x39C2, 0x5C2, 0x25C2, 0x15C2, 0x35C2, 0xDC2, 0x2DC2, 0x1DC2, 0x3DC2,
	0x3C2, 0x23C2, 0x13C2, 0x33C2, 0xBC2, 0x2BC2, 0x1BC2, 0x3BC2, 0x7C2, 0x27C2, 0x17C2, 0x37C2, 0xFC2, 0x2FC2, 0x1FC2, 0x3FC2,
	0x22, 0x2022, 0x1022, 0x3022, 0x822, 0x2822, 0x1822, 0x3822, 0x422, 0x2422, 0x1422, 0x3422, 0xC22, 0x2C22, 0x1C22, 0x3C22,
	0x222, 0x2222, 0x1222, 0x3222, 0xA22, 0x2A22, 0x1A22, 0x3A22, 0x622, 0x2622, 0x1622, 0x3622, 0xE22, 0x2E22, 0x1E22, 0x3E22,
	0x122, 0x2122, 0x1122, 0x3122, 0x922, 0x2922, 0x1922, 0x3922, 0x522, 0x2522, 0x1522, 0x3522, 0xD22, 0x2D22, 0x1D22, 0x3D22,
	0x322, 0x2322, 0x1322, 0x3322, 0xB22, 0x2B22, 0x1B22, 0x3B22, 0x722, 0x2722, 0x1722, 0x3722, 0xF22, 0x2F22, 0x1F22, 0x3F22,
	0xA2, 0x20A2, 0x10A2, 0x30A2, 0x8A2, 0x28A2, 0x18A2, 0x38A2, 0x4A2, 0x24A2, 0x14A2, 0x34A2, 0xCA2, 0x2CA2, 0x1CA2, 0x3CA2,
	0x2A2, 0x22A2, 0x12A2, 0x32A2, 0xAA2, 0x2AA2, 0x1AA2, 0x3AA2, 0x6A2, 0x26A2, 0x16A2, 0x36A2, 0xEA2, 0x2EA2, 0x1EA2, 0x3EA2,
	0x1A2, 0x21A2, 0x11A2, 0x31A2, 0x9A2, 0x29A2, 0x19A2, 0x39A2, 0x5A2, 0x25A2, 0x15A2, 0x35A2, 0xDA2, 0x2DA2, 0x1DA2, 0x3DA2,
	0x3A2, 0x23A2, 0x13A2, 0x33A2, 0xBA2, 0x2BA2, 0x1BA2, 0x3BA2, 0x7A2, 0x27A2, 0x17A2, 0x37A2, 0xFA2, 0x2FA2, 0x1FA2, 0x3FA2,
	0x62, 0x2062, 0x1062, 0x3062, 0x862, 0x2862, 0x1862, 0x3862, 0x462, 0x2462, 0x1462, 0x3462, 0xC62, 0x2C62, 0x1C62, 0x3C62,
	0x262, 0x2262, 0x1262, 0x3262, 0xA62, 0x2A62, 0x1A62, 0x3A62, 0x662, 0x2662, 0x1662, 0x3662, 0xE62, 0x2E62, 0x1E62, 0x3E62,
	0x162, 0x2162, 0x1162, 0x3162, 0x962, 0x2962, 0x1962, 0x3962, 0x562, 0x2562, 0x1562, 0x3562, 0xD62, 0x2D62, 0x1D62, 0x3D62,
	0x362, 0x2362, 0x1362, 0x3362, 0xB62, 0x2B62, 0x1B62, 0x3B62, 0x762, 0x2762, 0x1762, 0x3762, 0xF62, 0x2F62, 0x1F62, 0x3F62,
	0xE2, 0x20E2, 0x10E2, 0x30E2, 0x8E2, 0x28E2, 0x18E2, 0x38E2, 0x4E2, 0x24E2, 0x14E2, 0x34E2, 0xCE2, 0x2CE2, 0x1CE2, 0x3CE2,
	0x2E2, 0x22E2, 0x12E2, 0x32E2, 0xAE2, 0x2AE2, 0x1AE2, 0x3AE2, 0x6E2, 0x26E2, 0x16E2, 0x36E2, 0xEE2, 0x2EE2, 0x1EE2, 0x3EE2,
	0x1E2, 0x21E2, 0x11E2, 0x31E2, 0x9E2, 0x29E2, 0x19E2, 0x39E2, 0x5E2, 0x25E2, 0x15E2, 0x35E2, 0xDE2, 0x2DE2, 0x1DE2, 0x3DE2,
	0x3E2, 0x23E2, 0x13E2, 0x33E2, 0xBE2, 0x2BE2, 0x1BE2, 0x3BE2, 0x7E2, 0x27E2, 0x17E2, 0x37E2, 0xFE2, 0x2FE2, 0x1FE2, 0x3FE2,
	0x12, 0x2012, 0x1012, 0x3012, 0x812, 0x2812, 0x1812, 0x3812, 0x412, 0x2412, 0x1412, 0x3412, 0xC12, 0x2C12, 0x1C12, 0x3C12,
	0x212, 0x2212, 0x1212, 0x3212, 0xA12, 0x2A12, 0x1A12, 0x3A12, 0x612, 0x2612, 0x1612, 0x3612, 0xE12, 0x2E12, 0x1E12, 0x3E12,
	0x112, 0x2112, 0x1112, 0x3112, 0x912, 0x2912, 0x1912, 0x3912, 0x512, 0x2512, 0x1512, 0x3512, 0xD12, 0x2D12, 0x1D12, 0x3D12,
	0x312, 0x2312, 0x1312, 0x3312, 0xB12, 0x2B12, 0x1B12, 0x3B12, 0x712, 0x2712, 0x1712, 0x3712, 0xF12, 0x2F12, 0x1F12, 0x3F12,
	0x92, 0x2092, 0x1092, 0x3092, 0x892, 0x2892, 0x1892, 0x3892, 0x492, 0x2492, 0x1492, 0x3492, 0xC92, 0x2C92, 0x1C92, 0x3C92,
	0x292, 0x2292, 0x1292, 0x3292, 0xA92, 0x2A92, 0x1A92, 0x3A92, 0x692, 0x2692, 0x1692, 0x3692, 0xE92, 0x2E92, 0x1E92, 0x3E92,
	0x192, 0x2192, 0x1192, 0x3192, 0x992, 0x2992, 0x1992, 0x3992, 0x592, 0x2592, 0x1592, 0x3592, 0xD92, 0x2D92, 0x1D92, 0x3D92,
	0x392, 0x2392, 0x1392, 0x3392, 0xB92, 0x2B92, 0x1B92, 0x3B92, 0x792, 0x2792, 0x1792, 0x3792, 0xF92, 0x2F92, 0x1F92, 0x3F92,
	0x52, 0x2052, 0x1052, 0x3052, 0x852, 0x2852, 0x1852, 0x3852, 0x452, 0x2452, 0x1452, 0x3452, 0xC52, 0x2C52, 0x1C52, 0x3C52,
	0x252, 0x2252, 0x1252, 0x3252, 0xA52, 0x2A52, 0x1A52, 0x3A52, 0x652, 0x2652, 0x1652, 0x3652, 0xE52, 0x2E52, 0x1E52, 0x3E52,
	0x152, 0x2152, 0x1152, 0x3152, 0x952, 0x2952, 0x1952, 0x3952, 0x552, 0x2552, 0x1552, 0x3552, 0xD52, 0x2D52, 0x1D52, 0x3D52,
	0x352, 0x2352, 0x1352, 0x3352, 0xB52, 0x2B52, 0x1B52, 0x3B52, 0x752, 0x2752, 0x1752, 0x3752, 0xF52, 0x2F52, 0x1F52, 0x3F52,
	0xD2, 0x20D2, 0x10D2, 0x30D2, 0x8D2, 0x28D2, 0x18D2, 0x38D2, 0x4D2, 0x24D2, 0x14D2, 0x34D2, 0xCD2, 0x2CD2, 0x1CD2, 0x3CD2,
	0x2D2, 0x22D2, 0x12D2, 0x32D2, 0xAD2, 0x2AD2, 0x1AD2, 0x3AD2, 0x6D2, 0x26D2, 0x16D2, 0x36D2, 0xED2, 0x2ED2, 0x1ED2, 0x3ED2,
	0x1D2, 0x21D2, 0x11D2, 0x31D2, 0x9D2, 0x29D2, 0x19D2, 0x39D2, 0x5D2, 0x25D2, 0x15D2, 0x35D2, 0xDD2, 0x2DD2, 0x1DD2, 0x3DD2,
	0x3D2, 0x23D2, 0x13D2, 0x33D2, 0xBD2, 0x2BD2, 0x1BD2, 0x3BD2, 0x7D2, 0x27D2, 0x17D2, 0x37D2, 0xFD2, 0x2FD2, 0x1FD2, 0x3FD2,
	0x32, 0x2032, 0x1032, 0x3032, 0x832, 0x2832, 0x1832, 0x3832, 0x432, 0x2432, 0x1432, 0x3432, 0xC32, 0x2C32, 0x1C32, 0x3C32,
	0x232, 0x2232, 0x1232, 0x3232, 0xA32, 0x2A32, 0x1A32, 0x3A32, 0x632, 0x2632, 0x1632, 0x3632, 0xE32, 0x2E32, 0x1E32, 0x3E32,
	0x132, 0x2132, 0x1132, 0x3132, 0x932, 0x2932, 0x1932, 0x3932, 0x532, 0x2532, 0x1532, 0x3532, 0xD32, 0x2D32, 0x1D32, 0x3D32,
	0x332, 0x2332, 0x1332, 0x3332, 0xB32, 0x2B32, 0x1B32, 0x3B32, 0x732, 0x2732, 0x1732, 0x3732, 0xF32, 0x2F32, 0x1F32, 0x3F32,
	0xB2, 0x20B2, 0x10B2, 0x30B2, 0x8B2, 0x28B2, 0x18B2, 0x38B2, 0x4B2, 0x24B2, 0x14B2, 0x34B2, 0xCB2, 0x2CB2, 0x1CB2, 0x3CB2,
	0x2B2, 0x22B2, 0x12B2, 0x32B2, 0xAB2, 0x2AB2, 0x1AB2, 0x3AB2, 0x6B2, 0x26B2, 0x16B2, 0x36B2, 0xEB2, 0x2EB2, 0x1EB2, 0x3EB2,
	0x1B2, 0x21B2, 0x11B2, 0x31B2, 0x9B2, 0x29B2, 0x19B2, 0x39B2, 0x5B2, 0x25B2, 0x15B2, 0x35B2, 0xDB2, 0x2DB2, 0x1DB2, 0x3DB2,
	0x3B2, 0x23B2, 0x13B2, 0x33B2, 0xBB2, 0x2BB2, 0x1BB2, 0x3BB2, 0x7B2, 0x27B2, 0x17B2, 0x37B2, 0xFB2, 0x2FB2, 0x1FB2, 0x3FB2,
	0x72, 0x2072, 0x1072, 0x3072, 0x872, 0x2872, 0x1872, 0x3872, 0x472, 0x2472, 0x1472, 0x3472, 0xC72, 0x2C72, 0x1C72, 0x3C72,
	0x272, 0x2272, 0x1272, 0x3272, 0xA72, 0x2A72, 0x1A72, 0x3A72, 0x672, 0x2672, 0x1672, 0x3672, 0xE72, 0x2E72, 0x1E72, 0x3E72,
	0x172, 0x2172, 0x1172, 0x3172, 0x972, 0x2972, 0x1972, 0x3972, 0x572, 0x2572, 0x1572, 0x3572, 0xD72, 0x2D72, 0x1D72, 0x3D72,
	0x372, 0x2372, 0x1372, 0x3372, 0xB72, 0x2B72, 0x1B72, 0x3B72, 0x772, 0x2772, 0x1772, 0x3772, 0xF72, 0x2F72, 0x1F72, 0x3F72,
	0xF2, 0x20F2, 0x10F2, 0x30F2, 0x8F2, 0x28F2, 0x18F2, 0x38F2, 0x4F2, 0x24F2, 0x14F2, 0x34F2, 0xCF2, 0x2CF2, 0x1CF2, 0x3CF2,
	0x2F2, 0x22F2, 0x12F2, 0x32F2, 0xAF2, 0x2AF2, 0x1AF2, 0x3AF2, 0x6F2, 0x26F2, 0x16F2, 0x36F2, 0xEF2, 0x2EF2, 0x1EF2, 0x3EF2,
	0x1F2, 0x21F2, 0x11F2, 0x31F2, 0x9F2, 0x29F2, 0x19F2, 0x39F2, 0x5F2, 0x25F2, 0x15F2, 0x35F2, 0xDF2, 0x2DF2, 0x1DF2, 0x3DF2,
	0x3F2, 0x23F2, 0x13F2, 0x33F2, 0xBF2, 0x2BF2, 0x1BF2, 0x3BF2, 0x7F2, 0x27F2, 0x17F2, 0x37F2, 0xFF2, 0x2FF2, 0x1FF2, 0x3FF2,
	0xA, 0x200A, 0x100A, 0x300A, 0x80A, 0x280A, 0x180A, 0x380A, 0x40A, 0x240A, 0x140A, 0x340A, 0xC0A, 0x2C0A, 0x1C0A, 0x3C0A,
	0x20A, 0x220A, 0x120A, 0x320A, 0xA0A, 0x2A0A, 0x1A0A, 0x3A0A, 0x60A, 0x260A, 0x160A, 0x360A, 0xE0A, 0x2E0A, 0x1E0A, 0x3E0A,
	0x10A, 0x210A, 0x110A, 0x310A, 0x90A, 0x290A, 0x190A, 0x390A, 0x50A, 0x250A, 0x150A, 0x350A, 0xD0A, 0x2D0A, 0x1D0A, 0x3D0A,
	0x30A, 0x230A, 0x130A, 0x330A, 0xB0A, 0x2B0A, 0x1B0A, 0x3B0A, 0x70A, 0x270A, 0x170A, 0x370A, 0xF0A, 0x2F0A, 0x1F0A, 0x3F0A,
	0x8A, 0x208A, 0x108A, 0x308A, 0x88A, 0x288A, 0x188A, 0x388A, 0x48A, 0x248A, 0x148A, 0x348A, 0xC8A, 0x2C8A, 0x1C8A, 0x3C8A,
	0x28A, 0x228A, 0x128A, 0x328A, 0xA8A, 0x2A8A, 0x1A8A, 0x3A8A, 0x68A, 0x268A, 0x168A, 0x368A, 0xE8A, 0x2E8A, 0x1E8A, 0x3E8A,
	0x18A, 0x218A, 0x118A, 0x318A, 0x98A, 0x298A, 0x198A, 0x398A, 0x58A, 0x258A, 0x158A, 0x358A, 0xD8A, 0x2D8A, 0x1D8A, 0x3D8A,
	0x38A, 0x238A, 0x138A, 0x338A, 0xB8A, 0x2B8A, 0x1B8A, 0x3B8A, 0x78A, 0x278A, 0x178A, 0x378A, 0xF8A, 0x2F8A, 0x1F8A, 0x3F8A,
	0x4A, 0x204A, 0x104A, 0x304A, 0x84A, 0x284A, 0x184A, 0x384A, 0x44A, 0x244A, 0x144A, 0x344A, 0xC4A, 0x2C4A, 0x1C4A, 0x3C4A,
	0x24A, 0x224A, 0x124A, 0x324A, 0xA4A, 0x2A4A, 0x1A4A, 0x3A4A, 0x64A, 0x264A, 0x164A, 0x364A, 0xE4A, 0x2E4A, 0x1E4A, 0x3E4A,
	0x14A, 0x214A, 0x114A, 0x314A, 0x94A, 0x294A, 0x194A, 0x394A, 0x54A, 0x254A, 0x154A, 0x354A, 0xD4A, 0x2D4A, 0x1D4A, 0x3D4A,
	0x34A, 0x234A, 0x134A, 0x334A, 0xB4A, 0x2B4A, 0x1B4A, 0x3B4A, 0x74A, 0x274A, 0x174A, 0x374A, 0xF4A, 0x2F4A, 0x1F4A, 0x3F4A,
	0xCA, 0x20CA, 0x10CA, 0x30CA, 0x8CA, 0x28CA, 0x18CA, 0x38CA, 0x4CA, 0x24CA, 0x14CA, 0x34CA, 0xCCA, 0x2CCA, 0x1CCA, 0x3CCA,
	0x2CA, 0x22CA, 0x12CA, 0x32CA, 0xACA, 0x2ACA, 0x1ACA, 0x3ACA, 0x6CA, 0x26CA, 0x16CA, 0x36CA, 0xECA, 0x2ECA, 0x1ECA, 0x3ECA,
	0x1CA, 0x21CA, 0x11CA, 0x31CA, 0x9CA, 0x29CA, 0x19CA, 0x39CA, 0x5CA, 0x25CA, 0x15CA, 0x35CA, 0xDCA, 0x2DCA, 0x1DCA, 0x3DCA,
	0x3CA, 0x23CA, 0x13CA, 0x33CA, 0xBCA, 0x2BCA, 0x1BCA, 0x3BCA, 0x7CA, 0x27CA, 0x17CA, 0x37CA, 0xFCA, 0x2FCA, 0x1FCA, 0x3FCA,
	0x2A, 0x202A, 0x102A, 0x302A, 0x82A, 0x282A, 0x182A, 0x382A, 0x42A, 0x242A, 0x142A, 0x342A, 0xC2A, 0x2C2A, 0x1C2A, 0x3C2A,
	0x22A, 0x222A, 0x122A, 0x322A, 0xA2A, 0x2A2A, 0x1A2A, 0x3A2A, 0x62A, 0x262A, 0x162A, 0x362A, 0xE2A, 0x2E2A, 0x1E2A, 0x3E2A,
	0x12A, 0x212A, 0x112A, 0x312A, 0x92A, 0x292A, 0x192A, 0x392A, 0x52A, 0x252A, 0x152A, 0x352A, 0xD2A, 0x2D2A, 0x1D2A, 0x3D2A,
	0x32A, 0x232A, 0x132A, 0x332A, 0xB2A, 0x2B2A, 0x1B2A, 0x3B2A, 0x72A, 0x272A, 0x172A, 0x372A, 0xF2A, 0x2F2A, 0x1F2A, 0x3F2A,
	0xAA, 0x20AA, 0x10AA, 0x30AA, 0x8AA, 0x28AA, 0x18AA, 0x38AA, 0x4AA, 0x24AA, 0x14AA, 0x34AA, 0xCAA, 0x2CAA, 0x1CAA, 0x3CAA,
	0x2AA, 0x22AA, 0x12AA, 0x32AA, 0xAAA, 0x2AAA, 0x1AAA, 0x3AAA, 0x6AA, 0x26AA, 0x16AA, 0x36AA, 0xEAA, 0x2EAA, 0x1EAA, 0x3EAA,
	0x1AA, 0x21AA, 0x11AA, 0x31AA, 0x9AA, 0x29AA, 0x19AA, 0x39AA, 0x5AA, 0x25AA, 0x15AA, 0x35AA, 0xDAA, 0x2DAA, 0x1DAA, 0x3DAA,
	0x3AA, 0x23AA, 0x13AA, 0x33AA, 0xBAA, 0x2BAA, 0x1BAA, 0x3BAA, 0x7AA, 0x27AA, 0x17AA, 0x37AA, 0xFAA, 0x2FAA, 0x1FAA, 0x3FAA,
	0x6A, 0x206A, 0x106A, 0x306A, 0x86A, 0x286A, 0x186A, 0x386A, 0x46A, 0x246A, 0x146A, 0x346A, 0xC6A, 0x2C6A, 0x1C6A, 0x3C6A,
	0x26A, 0x226A, 0x126A, 0x326A, 0xA6A, 0x2A6A, 0x1A6A, 0x3A6A, 0x66A, 0x266A, 0x166A, 0x366A, 0xE6A, 0x2E6A, 0x1E6A, 0x3E6A,
	0x16A, 0x216A, 0x116A, 0x316A, 0x96A, 0x296A, 0x196A, 0x396A, 0x56A, 0x256A, 0x156A, 0x356A, 0xD6A, 0x2D6A, 0x1D6A, 0x3D6A,
	0x36A, 0x236A, 0x136A, 0x336A, 0xB6A, 0x2B6A, 0x1B6A, 0x3B6A, 0x76A, 0x276A, 0x176A, 0x376A, 0xF6A, 0x2F6A, 0x1F6A, 0x3F6A,
	0xEA, 0x20EA, 0x10EA, 0x30EA, 0x8EA, 0x28EA, 0x18EA, 0x38EA, 0x4EA, 0x24EA, 0x14EA, 0x34EA, 0xCEA, 0x2CEA, 0x1CEA, 0x3CEA,
	0x2EA, 0x22EA, 0x12EA, 0x32EA, 0xAEA, 0x2AEA, 0x1AEA, 0x3AEA, 0x6EA, 0x26EA, 0x16EA, 0x36EA, 0xEEA, 0x2EEA, 0x1EEA, 0x3EEA,
	0x1EA, 0x21EA, 0x11EA, 0x31EA, 0x9EA, 0x29EA, 0x19EA, 0x39EA, 0x5EA, 0x25EA, 0x15EA, 0x35EA, 0xDEA, 0x2DEA, 0x1DEA, 0x3DEA,
	0x3EA, 0x23EA, 0x13EA, 0x33EA, 0xBEA, 0x2BEA, 0x1BEA, 0x3BEA, 0x7EA, 0x27EA, 0x17EA, 0x37EA, 0xFEA, 0x2FEA, 0x1FEA, 0x3FEA,
	0x1A, 0x201A, 0x101A, 0x301A, 0x81A, 0x281A, 0x181A, 0x381A, 0x41A, 0x241A, 0x141A, 0x341A, 0xC1A, 0x2C1A, 0x1C1A, 0x3C1A,
	0x21A, 0x221A, 0x121A, 0x321A, 0xA1A, 0x2A1A, 0x1A1A, 0x3A1A, 0x61A, 0x261A, 0x161A, 0x361A, 0xE1A, 0x2E1A, 0x1E1A, 0x3E1A,
	0x11A, 0x211A, 0x111A, 0x311A, 0x91A, 0x291A, 0x191A, 0x391A, 0x51A, 0x251A, 0x151A, 0x351A, 0xD1A, 0x2D1A, 0x1D1A, 0x3D1A,
	0x31A, 0x231A, 0x131A, 0x331A, 0xB1A, 0x2B1A, 0x1B1A, 0x3B1A, 0x71A, 0x271A, 0x171A, 0x371A, 0xF1A, 0x2F1A, 0x1F1A, 0x3F1A,
	0x9A, 0x209A, 0x109A, 0x309A, 0x89A, 0x289A, 0x189A, 0x389A, 0x49A, 0x249A, 0x149A, 0x349A, 0xC9A, 0x2C9A, 0x1C9A, 0x3C9A,
	0x29A, 0x229A, 0x129A, 0x329A, 0xA9A, 0x2A9A, 0x1A9A, 0x3A9A, 0x69A, 0x269A, 0x169A, 0x369A, 0xE9A, 0x2E9A, 0x1E9A, 0x3E9A,
	0x19A, 0x219A, 0x119A, 0x319A, 0x99A, 0x299A, 0x199A, 0x399A, 0x59A, 0x259A, 0x159A, 0x359A, 0xD9A, 0x2D9A, 0x1D9A, 0x3D9A,
	0x39A, 0x239A, 0x139A, 0x339A, 0xB9A, 0x2B9A, 0x1B9A, 0x3B9A, 0x79A, 0x279A, 0x179A, 0x379A, 0xF9A, 0x2F9A, 0x1F9A, 0x3F9A,
	0x5A, 0x205A, 0x105A, 0x305A, 0x85A, 0x285A, 0x185A, 0x385A, 0x45A, 0x245A, 0x145A, 0x345A, 0xC5A, 0x2C5A, 0x1C5A, 0x3C5A,
	0x25A, 0x225A, 0x125A, 0x325A, 0xA5A, 0x2A5A, 0x1A5A, 0x3A5A, 0x65A, 0x265A, 0x165A, 0x365A, 0xE5A, 0x2E5A, 0x1E5A, 0x3E5A,
	0x15A, 0x215A, 0x115A, 0x315A, 0x95A, 0x295A, 0x195A, 0x395A, 0x55A, 0x255A, 0x155A, 0x355A, 0xD5A, 0x2D5A, 0x1D5A, 0x3D5A,
	0x35A, 0x235A, 0x135A, 0x335A, 0xB5A, 0x2B5A, 0x1B5A, 0x3B5A, 0x75A, 0x275A, 0x175A, 0x375A, 0xF5A, 0x2F5A, 0x1F5A, 0x3F5A,
	0xDA, 0x20DA, 0x10DA, 0x30DA, 0x8DA, 0x28DA, 0x18DA, 0x38DA, 0x4DA, 0x24DA, 0x14DA, 0x34DA, 0xCDA, 0x2CDA, 0x1CDA, 0x3CDA,
	0x2DA, 0x22DA, 0x12DA, 0x32DA, 0xADA, 0x2ADA, 0x1ADA, 0x3ADA, 0x6DA, 0x26DA, 0x16DA, 0x36DA, 0xEDA, 0x2EDA, 0x1EDA, 0x3EDA,
	0x1DA, 0x21DA, 0x11DA, 0x31DA, 0x9DA, 0x29DA, 0x19DA, 0x39DA, 0x5DA, 0x25DA, 0x15DA, 0x35DA, 0xDDA, 0x2DDA, 0x1DDA, 0x3DDA,
	0x3DA, 0x23DA, 0x13DA, 0x33DA, 0xBDA, 0x2BDA, 0x1BDA, 0x3BDA, 0x7DA, 0x27DA, 0x17DA, 0x37DA, 0xFDA, 0x2FDA, 0x1FDA, 0x3FDA,
	0x3A, 0x203A, 0x103A, 0x303A, 0x83A, 0x283A, 0x183A, 0x383A, 0x43A, 0x243A, 0x143A, 0x343A, 0xC3A, 0x2C3A, 0x1C3A, 0x3C3A,
	0x23A, 0x223A, 0x123A, 0x323A, 0xA3A, 0x2A3A, 0x1A3A, 0x3A3A, 0x63A, 0x263A, 0x163A, 0x363A, 0xE3A, 0x2E3A, 0x1E3A, 0x3E3A,
	0x13A, 0x213A, 0x113A, 0x313A, 0x93A, 0x293A, 0x193A, 0x393A, 0x53A, 0x253A, 0x153A, 0x353A, 0xD3A, 0x2D3A, 0x1D3A, 0x3D3A,
	0x33A, 0x233A, 0x133A, 0x333A, 0xB3A, 0x2B3A, 0x1B3A, 0x3B3A, 0x73A, 0x273A, 0x173A, 0x373A, 0xF3A, 0x2F3A, 0x1F3A, 0x3F3A,
	0xBA, 0x20BA, 0x10BA, 0x30BA, 0x8BA, 0x28BA, 0x18BA, 0x38BA, 0x4BA, 0x24BA, 0x14BA, 0x34BA, 0xCBA, 0x2CBA, 0x1CBA, 0x3CBA,
	0x2BA, 0x22BA, 0x12BA, 0x32BA, 0xABA, 0x2ABA, 0x1ABA, 0x3ABA, 0x6BA, 0x26BA, 0x16BA, 0x36BA, 0xEBA, 0x2EBA, 0x1EBA, 0x3EBA,
	0x1BA, 0x21BA, 0x11BA, 0x31BA, 0x9BA, 0x29BA, 0x19BA, 0x39BA, 0x5BA, 0x25BA, 0x15BA, 0x35BA, 0xDBA, 0x2DBA, 0x1DBA, 0x3DBA,
	0x3BA, 0x23BA, 0x13BA, 0x33BA, 0xBBA, 0x2BBA, 0x1BBA, 0x3BBA, 0x7BA, 0x27BA, 0x17BA, 0x37BA, 0xFBA, 0x2FBA, 0x1FBA, 0x3FBA,
	0x7A, 0x207A, 0x107A, 0x307A, 0x87A, 0x287A, 0x187A, 0x387A, 0x47A, 0x247A, 0x147A, 0x347A, 0xC7A, 0x2C7A, 0x1C7A, 0x3C7A,
	0x27A, 0x227A, 0x127A, 0x327A, 0xA7A, 0x2A7A, 0x1A7A, 0x3A7A, 0x67A, 0x267A, 0x167A, 0x367A, 0xE7A, 0x2E7A, 0x1E7A, 0x3E7A,
	0x17A, 0x217A, 0x117A, 0x317A, 0x97A, 0x297A, 0x197A, 0x397A, 0x57A, 0x257A, 0x157A, 0x357A, 0xD7A, 0x2D7A, 0x1D7A, 0x3D7A,
	0x37A, 0x237A, 0x137A, 0x337A, 0xB7A, 0x2B7A, 0x1B7A, 0x3B7A, 0x77A, 0x277A, 0x177A, 0x377A, 0xF7A, 0x2F7A, 0x1F7A, 0x3F7A,
	0xFA, 0x20FA, 0x10FA, 0x30FA, 0x8FA, 0x28FA, 0x18FA, 0x38FA, 0x4FA, 0x24FA, 0x14FA, 0x34FA, 0xCFA, 0x2CFA, 0x1CFA, 0x3CFA,
	0x2FA, 0x22FA, 0x12FA, 0x32FA, 0xAFA, 0x2AFA, 0x1AFA, 0x3AFA, 0x6FA, 0x26FA, 0x16FA, 0x36FA, 0xEFA, 0x2EFA, 0x1EFA, 0x3EFA,
	0x1FA, 0x21FA, 0x11FA, 0x31FA, 0x9FA, 0x29FA, 0x19FA, 0x39FA, 0x5FA, 0x25FA, 0x15FA, 0x35FA, 0xDFA, 0x2DFA, 0x1DFA, 0x3DFA,
	0x3FA, 0x23FA, 0x13FA, 0x33FA, 0xBFA, 0x2BFA, 0x1BFA, 0x3BFA, 0x7FA, 0x27FA, 0x17FA, 0x37FA, 0xFFA, 0x2FFA, 0x1FFA, 0x3FFA,
	0x6, 0x2006, 0x1006, 0x3006, 0x806, 0x2806, 0x1806, 0x3806, 0x406, 0x2406, 0x1406, 0x3406, 0xC06, 0x2C06, 0x1C06, 0x3C06,
	0x206, 0x2206, 0x1206, 0x3206, 0xA06, 0x2A06, 0x1A06, 0x3A06, 0x606, 0x2606, 0x1606, 0x3606, 0xE06, 0x2E06, 0x1E06, 0x3E06,
	0x106, 0x2106, 0x1106, 0x3106, 0x906, 0x2906, 0x1906, 0x3906, 0x506, 0x2506, 0x1506, 0x3506, 0xD06, 0x2D06, 0x1D06, 0x3D06,
	0x306, 0x2306, 0x1306, 0x3306, 0xB06, 0x2B06, 0x1B06, 0x3B06, 0x706, 0x2706, 0x1706, 0x3706, 0xF06, 0x2F06, 0x1F06, 0x3F06,
	0x86, 0x2086, 0x1086, 0x3086, 0x886, 0x2886, 0x1886, 0x3886, 0x486, 0x2486, 0x1486, 0x3486, 0xC86, 0x2C86, 0x1C86, 0x3C86,
	0x286, 0x2286, 0x1286, 0x3286, 0xA86, 0x2A86, 0x1A86, 0x3A86, 0x686, 0x2686, 0x1686, 0x3686, 0xE86, 0x2E86, 0x1E86, 0x3E86,
	0x186, 0x2186, 0x1186, 0x3186, 0x986, 0x2986, 0x1986, 0x3986, 0x586, 0x2586, 0x1586, 0x3586, 0xD86, 0x2D86, 0x1D86, 0x3D86,
	0x386, 0x2386, 0x1386, 0x3386, 0xB86, 0x2B86, 0x1B86, 0x3B86, 0x786, 0x2786, 0x1786, 0x3786, 0xF86, 0x2F86, 0x1F86, 0x3F86,
	0x46, 0x2046, 0x1046, 0x3046, 0x846, 0x2846, 0x1846, 0x3846, 0x446, 0x2446, 0x1446, 0x3446, 0xC46, 0x2C46, 0x1C46, 0x3C46,
	0x246, 0x2246, 0x1246, 0x3246, 0xA46, 0x2A46, 0x1A46, 0x3A46, 0x646, 0x2646, 0x1646, 0x3646, 0xE46, 0x2E46, 0x1E46, 0x3E46,
	0x146, 0x2146, 0x1146, 0x3146, 0x946, 0x2946, 0x1946, 0x3946, 0x546, 0x2546, 0x1546, 0x3546, 0xD46, 0x2D46, 0x1D46, 0x3D46,
	0x346, 0x2346, 0x1346, 0x3346, 0xB46, 0x2B46, 0x1B46, 0x3B46, 0x746, 0x2746, 0x1746, 0x3746, 0xF46, 0x2F46, 0x1F46, 0x3F46,
	0xC6, 0x20C6, 0x10C6, 0x30C6, 0x8C6, 0x28C6, 0x18C6, 0x38C6, 0x4C6, 0x24C6, 0x14C6, 0x34C6, 0xCC6, 0x2CC6, 0x1CC6, 0x3CC6,
	0x2C6, 0x22C6, 0x12C6, 0x32C6, 0xAC6, 0x2AC6, 0x1AC6, 0x3AC6, 0x6C6, 0x26C6, 0x16C6, 0x36C6, 0xEC6, 0x2EC6, 0x1EC6, 0x3EC6,
	0x1C6, 0x21C6, 0x11C6, 0x31C6, 0x9C6, 0x29C6, 0x19C6, 0x39C6, 0x5C6, 0x25C6, 0x15C6, 0x35C6, 0xDC6, 0x2DC6, 0x1DC6, 0x3DC6,
	0x3C6, 0x23C6, 0x13C6, 0x33C6, 0xBC6, 0x2BC6, 0x1BC6, 0x3BC6, 0x7C6, 0x27C6, 0x17C6, 0x37C6, 0xFC6, 0x2FC6, 0x1FC6, 0x3FC6,
	0x26, 0x2026, 0x1026, 0x3026, 0x826, 0x2826, 0x1826, 0x3826, 0x426, 0x2426, 0x1426, 0x3426, 0xC26, 0x2C26, 0x1C26, 0x3C26,
	0x226, 0x2226, 0x1226, 0x3226, 0xA26, 0x2A26, 0x1A26, 0x3A26, 0x626, 0x2626, 0x1626, 0x3626, 0xE26, 0x2E26, 0x1E26, 0x3E26,
	0x126, 0x2126, 0x1126, 0x3126, 0x926, 0x2926, 0x1926, 0x3926, 0x526, 0x2526, 0x1526, 0x3526, 0xD26, 0x2D26, 0x1D26, 0x3D26,
	0x326, 0x2326, 0x1326, 0x3326, 0xB26, 0x2B26, 0x1B26, 0x3B26, 0x726, 0x2726, 0x1726, 0x3726, 0xF26, 0x2F26, 0x1F26, 0x3F26,
	0xA6, 0x20A6, 0x10A6, 0x30A6, 0x8A6, 0x28A6, 0x18A6, 0x38A6, 0x4A6, 0x24A6, 0x14A6, 0x34A6, 0xCA6, 0x2CA6, 0x1CA6, 0x3CA6,
	0x2A6, 0x22A6, 0x12A6, 0x32A6, 0xAA6, 0x2AA6, 0x1AA6, 0x3AA6, 0x6A6, 0x26A6, 0x16A6, 0x36A6, 0xEA6, 0x2EA6, 0x1EA6, 0x3EA6,
	0x1A6, 0x21A6, 0x11A6, 0x31A6, 0x9A6, 0x29A6, 0x19A6, 0x39A6, 0x5A6, 0x25A6, 0x15A6, 0x35A6, 0xDA6, 0x2DA6, 0x1DA6, 0x3DA6,
	0x3A6, 0x23A6, 0x13A6, 0x33A6, 0xBA6, 0x2BA6, 0x1BA6, 0x3BA6, 0x7A6, 0x27A6, 0x17A6, 0x37A6, 0xFA6, 0x2FA6, 0x1FA6, 0x3FA6,
	0x66, 0x2066, 0x1066, 0x3066, 0x866, 0x2866, 0x1866, 0x3866, 0x466, 0x2466, 0x1466, 0x3466, 0xC66, 0x2C66, 0x1C66, 0x3C66,
	0x266, 0x2266, 0x1266, 0x3266, 0xA66, 0x2A66, 0x1A66, 0x3A66, 0x666, 0x2666, 0x1666, 0x3666, 0xE66, 0x2E66, 0x1E66, 0x3E66,
	0x166, 0x2166, 0x1166, 0x3166, 0x966, 0x2966, 0x1966, 0x3966, 0x566, 0x2566, 0x1566, 0x3566, 0xD66, 0x2D66, 0x1D66, 0x3D66,
	0x366, 0x2366, 0x1366, 0x3366, 0xB66, 0x2B66, 0x1B66, 0x3B66, 0x766, 0x2766, 0x1766, 0x3766, 0xF66, 0x2F66, 0x1F66, 0x3F66,
	0xE6, 0x20E6, 0x10E6, 0x30E6, 0x8E6, 0x28E6, 0x18E6, 0x38E6, 0x4E6, 0x24E6, 0x14E6, 0x34E6, 0xCE6, 0x2CE6, 0x1CE6, 0x3CE6,
	0x2E6, 0x22E6, 0x12E6, 0x32E6, 0xAE6, 0x2AE6, 0x1AE6, 0x3AE6, 0x6E6, 0x26E6, 0x16E6, 0x36E6, 0xEE6, 0x2EE6, 0x1EE6, 0x3EE6,
	0x1E6, 0x21E6, 0x11E6, 0x31E6, 0x9E6, 0x29E6, 0x19E6, 0x39E6, 0x5E6, 0x25E6, 0x15E6, 0x35E6, 0xDE6, 0x2DE6, 0x1DE6, 0x3DE6,
	0x3E6, 0x23E6, 0x13E6, 0x33E6, 0xBE6, 0x2BE6, 0x1BE6, 0x3BE6, 0x7E6, 0x27E6, 0x17E6, 0x37E6, 0xFE6, 0x2FE6, 0x1FE6, 0x3FE6,
	0x16, 0x2016, 0x1016, 0x3016, 0x816, 0x2816, 0x1816, 0x3816, 0x416, 0x2416, 0x1416, 0x3416, 0xC16, 0x2C16, 0x1C16, 0x3C16,
	0x216, 0x2216, 0x1216, 0x3216, 0xA16, 0x2A16, 0x1A16, 0x3A16, 0x616, 0x2616, 0x1616, 0x3616, 0xE16, 0x2E16, 0x1E16, 0x3E16,
	0x116, 0x2116, 0x1116, 0x3116, 0x916, 0x2916, 0x1916, 0x3916, 0x516, 0x2516, 0x1516, 0x3516, 0xD16, 0x2D16, 0x1D16, 0x3D16,
	0x316, 0x2316, 0x1316, 0x3316, 0xB16, 0x2B16, 0x1B16, 0x3B16, 0x716, 0x2716, 0x1716, 0x3716, 0xF16, 0x2F16, 0x1F16, 0x3F16,
	0x96, 0x2096, 0x1096, 0x3096, 0x896, 0x2896, 0x1896, 0x3896, 0x496, 0x2496, 0x1496, 0x3496, 0xC96, 0x2C96, 0x1C96, 0x3C96,
	0x296, 0x2296, 0x1296, 0x3296, 0xA96, 0x2A96, 0x1A96, 0x3A96, 0x696, 0x2696, 0x1696, 0x3696, 0xE96, 0x2E96, 0x1E96, 0x3E96,
	0x196, 0x2196, 0x1196, 0x3196, 0x996, 0x2996, 0x1996, 0x3996, 0x596, 0x2596, 0x1596, 0x3596, 0xD96, 0x2D96, 0x1D96, 0x3D96,
	0x396, 0x2396, 0x1396, 0x3396, 0xB96, 0x2B96, 0x1B96, 0x3B96, 0x796, 0x2796, 0x1796, 0x3796, 0xF96, 0x2F96, 0x1F96, 0x3F96,
	0x56, 0x2056, 0x1056, 0x3056, 0x856, 0x2856, 0x1856, 0x3856, 0x456, 0x2456, 0x1456, 0x3456, 0xC56, 0x2C56, 0x1C56, 0x3C56,
	0x256, 0x2256, 0x1256, 0x3256, 0xA56, 0x2A56, 0x1A56, 0x3A56, 0x656, 0x2656, 0x1656, 0x3656, 0xE56, 0x2E56, 0x1E56, 0x3E56,
	0x156, 0x2156, 0x1156, 0x3156, 0x956, 0x2956, 0x1956, 0x3956, 0x556, 0x2556, 0x1556, 0x3556, 0xD56, 0x2D56, 0x1D56, 0x3D56,
	0x356, 0x2356, 0x1356, 0x3356, 0xB56, 0x2B56, 0x1B56, 0x3B56, 0x756, 0x2756, 0x1756, 0x3756, 0xF56, 0x2F56, 0x1F56, 0x3F56,
	0xD6, 0x20D6, 0x10D6, 0x30D6, 0x8D6, 0x28D6, 0x18D6, 0x38D6, 0x4D6, 0x24D6, 0x14D6, 0x34D6, 0xCD6, 0x2CD6, 0x1CD6, 0x3CD6,
	0x2D6, 0x22D6, 0x12D6, 0x32D6, 0xAD6, 0x2AD6, 0x1AD6, 0x3AD6, 0x6D6, 0x26D6, 0x16D6, 0x36D6, 0xED6, 0x2ED6, 0x1ED6, 0x3ED6,
	0x1D6, 0x21D6, 0x11D6, 0x31D6, 0x9D6, 0x29D6, 0x19D6, 0x39D6, 0x5D6, 0x25D6, 0x15D6, 0x35D6, 0xDD6, 0x2DD6, 0x1DD6, 0x3DD6,
	0x3D6, 0x23D6, 0x13D6, 0x33D6, 0xBD6, 0x2BD6, 0x1BD6, 0x3BD6, 0x7D6, 0x27D6, 0x17D6, 0x37D6, 0xFD6, 0x2FD6, 0x1FD6, 0x3FD6,
	0x36, 0x2036, 0x1036, 0x3036, 0x836, 0x2836, 0x1836, 0x3836, 0x436, 0x2436, 0x1436, 0x3436, 0xC36, 0x2C36, 0x1C36, 0x3C36,
	0x236, 0x2236, 0x1236, 0x3236, 0xA36, 0x2A36, 0x1A36, 0x3A36, 0x636, 0x2636, 0x1636, 0x3636, 0xE36, 0x2E36, 0x1E36, 0x3E36,
	0x136, 0x2136, 0x1136, 0x3136, 0x936, 0x2936, 0x1936, 0x3936, 0x536, 0x2536, 0x1536, 0x3536, 0xD36, 0x2D36, 0x1D36, 0x3D36,
	0x336, 0x2336, 0x1336, 0x3336, 0xB36, 0x2B36, 0x1B36, 0x3B36, 0x736, 0x2736, 0x1736, 0x3736, 0xF36, 0x2F36, 0x1F36, 0x3F36,
	0xB6, 0x20B6, 0x10B6, 0x30B6, 0x8B6, 0x28B6, 0x18B6, 0x38B6, 0x4B6, 0x24B6, 0x14B6, 0x34B6, 0xCB6, 0x2CB6, 0x1CB6, 0x3CB6,
	0x2B6, 0x22B6, 0x12B6, 0x32B6, 0xAB6, 0x2AB6, 0x1AB6, 0x3AB6, 0x6B6, 0x26B6, 0x16B6, 0x36B6, 0xEB6, 0x2EB6, 0x1EB6, 0x3EB6,
	0x1B6, 0x21B6, 0x11B6, 0x31B6, 0x9B6, 0x29B6, 0x19B6, 0x39B6, 0x5B6, 0x25B6, 0x15B6, 0x35B6, 0xDB6, 0x2DB6, 0x1DB6, 0x3DB6,
	0x3B6, 0x23B6, 0x13B6, 0x33B6, 0xBB6, 0x2BB6, 0x1BB6, 0x3BB6, 0x7B6, 0x27B6, 0x17B6, 0x37B6, 0xFB6, 0x2FB6, 0x1FB6, 0x3FB6,
	0x76, 0x2076, 0x1076, 0x3076, 0x876, 0x2876, 0x1876, 0x3876, 0x476, 0x2476, 0x1476, 0x3476, 0xC76, 0x2C76, 0x1C76, 0x3C76,
	0x276, 0x2276, 0x1276, 0x3276, 0xA76, 0x2A76, 0x1A76, 0x3A76, 0x676, 0x2676, 0x1676, 0x3676, 0xE76, 0x2E76, 0x1E76, 0x3E76,
	0x176, 0x2176, 0x1176, 0x3176, 0x976, 0x2976, 0x1976, 0x3976, 0x576, 0x2576, 0x1576, 0x3576, 0xD76, 0x2D76, 0x1D76, 0x3D76,
	0x376, 0x2376, 0x1376, 0x3376, 0xB76, 0x2B76, 0x1B76, 0x3B76, 0x776, 0x2776, 0x1776, 0x3776, 0xF76, 0x2F76, 0x1F76, 0x3F76,
	0xF6, 0x20F6, 0x10F6, 0x30F6, 0x8F6, 0x28F6, 0x18F6, 0x38F6, 0x4F6, 0x24F6, 0x14F6, 0x34F6, 0xCF6, 0x2CF6, 0x1CF6, 0x3CF6,
	0x2F6, 0x22F6, 0x12F6, 0x32F6, 0xAF6, 0x2AF6, 0x1AF6, 0x3AF6, 0x6F6, 0x26F6, 0x16F6, 0x36F6, 0xEF6, 0x2EF6, 0x1EF6, 0x3EF6,
	0x1F6, 0x21F6, 0x11F6, 0x31F6, 0x9F6, 0x29F6, 0x19F6, 0x39F6, 0x5F6, 0x25F6, 0x15F6, 0x35F6, 0xDF6, 0x2DF6, 0x1DF6, 0x3DF6,
	0x3F6, 0x23F6, 0x13F6, 0x33F6, 0xBF6, 0x2BF6, 0x1BF6, 0x3BF6, 0x7F6, 0x27F6, 0x17F6, 0x37F6, 0xFF6, 0x2FF6, 0x1FF6, 0x3FF6,
	0xE, 0x200E, 0x100E, 0x300E, 0x80E, 0x280E, 0x180E, 0x380E, 0x40E, 0x240E, 0x140E, 0x340E, 0xC0E, 0x2C0E, 0x1C0E, 0x3C0E,
	0x20E, 0x220E, 0x120E, 0x320E, 0xA0E, 0x2A0E, 0x1A0E, 0x3A0E, 0x60E, 0x260E, 0x160E, 0x360E, 0xE0E, 0x2E0E, 0x1E0E, 0x3E0E,
	0x10E, 0x210E, 0x110E, 0x310E, 0x90E, 0x290E, 0x190E, 0x390E, 0x50E, 0x250E, 0x150E, 0x350E, 0xD0E, 0x2D0E, 0x1D0E, 0x3D0E,
	0x30E, 0x230E, 0x130E, 0x330E, 0xB0E, 0x2B0E, 0x1B0E, 0x3B0E, 0x70E, 0x270E, 0x170E, 0x370E, 0xF0E, 0x2F0E, 0x1F0E, 0x3F0E,
	0x8E, 0x208E, 0x108E, 0x308E, 0x88E, 0x288E, 0x188E, 0x388E, 0x48E, 0x248E, 0x148E, 0x348E, 0xC8E, 0x2C8E, 0x1C8E, 0x3C8E,
	0x28E, 0x228E, 0x128E, 0x328E, 0xA8E, 0x2A8E, 0x1A8E, 0x3A8E, 0x68E, 0x268E, 0x168E, 0x368E, 0xE8E, 0x2E8E, 0x1E8E, 0x3E8E,
	0x18E, 0x218E, 0x118E, 0x318E, 0x98E, 0x298E, 0x198E, 0x398E, 0x58E, 0x258E, 0x158E, 0x358E, 0xD8E, 0x2D8E, 0x1D8E, 0x3D8E,
	0x38E, 0x238E, 0x138E, 0x338E, 0xB8E, 0x2B8E, 0x1B8E, 0x3B8E, 0x78E, 0x278E, 0x178E, 0x378E, 0xF8E, 0x2F8E, 0x1F8E, 0x3F8E,
	0x4E, 0x204E, 0x104E, 0x304E, 0x84E, 0x284E, 0x184E, 0x384E, 0x44E, 0x244E, 0x144E, 0x344E, 0xC4E, 0x2C4E, 0x1C4E, 0x3C4E,
	0x24E, 0x224E, 0x124E, 0x324E, 0xA4E, 0x2A4E, 0x1A4E, 0x3A4E, 0x64E, 0x264E, 0x164E, 0x364E, 0xE4E, 0x2E4E, 0x1E4E, 0x3E4E,
	0x14E, 0x214E, 0x114E, 0x314E, 0x94E, 0x294E, 0x194E, 0x394E, 0x54E, 0x254E, 0x154E, 0x354E, 0xD4E, 0x2D4E, 0x1D4E, 0x3D4E,
	0x34E, 0x234E, 0x134E, 0x334E, 0xB4E, 0x2B4E, 0x1B4E, 0x3B4E, 0x74E, 0x274E, 0x174E, 0x374E, 0xF4E, 0x2F4E, 0x1F4E, 0x3F4E,
	0xCE, 0x20CE, 0x10CE, 0x30CE, 0x8CE, 0x28CE, 0x18CE, 0x38CE, 0x4CE, 0x24CE, 0x14CE, 0x34CE, 0xCCE, 0x2CCE, 0x1CCE, 0x3CCE,
	0x2CE, 0x22CE, 0x12CE, 0x32CE, 0xACE, 0x2ACE, 0x1ACE, 0x3ACE, 0x6CE, 0x26CE, 0x16CE, 0x36CE, 0xECE, 0x2ECE, 0x1ECE, 0x3ECE,
	0x1CE, 0x21CE, 0x11CE, 0x31CE, 0x9CE, 0x29CE, 0x19CE, 0x39CE, 0x5CE, 0x25CE, 0x15CE, 0x35CE, 0xDCE, 0x2DCE, 0x1DCE, 0x3DCE,
	0x3CE, 0x23CE, 0x13CE, 0x33CE, 0xBCE, 0x2BCE, 0x1BCE, 0x3BCE, 0x7CE, 0x27CE, 0x17CE, 0x37CE, 0xFCE, 0x2FCE, 0x1FCE, 0x3FCE,
	0x2E, 0x202E, 0x102E, 0x302E, 0x82E, 0x282E, 0x182E, 0x382E, 0x42E, 0x242E, 0x142E, 0x342E, 0xC2E, 0x2C2E, 0x1C2E, 0x3C2E,
	0x22E, 0x222E, 0x122E, 0x322E, 0xA2E, 0x2A2E, 0x1A2E, 0x3A2E, 0x62E, 0x262E, 0x162E, 0x362E, 0xE2E, 0x2E2E, 0x1E2E, 0x3E2E,
	0x12E, 0x212E, 0x112E, 0x312E, 0x92E, 0x292E, 0x192E, 0x392E, 0x52E, 0x252E, 0x152E, 0x352E, 0xD2E, 0x2D2E, 0x1D2E, 0x3D2E,
	0x32E, 0x232E, 0x132E, 0x332E, 0xB2E, 0x2B2E, 0x1B2E, 0x3B2E, 0x72E, 0x272E, 0x172E, 0x372E, 0xF2E, 0x2F2E, 0x1F2E, 0x3F2E,
	0xAE, 0x20AE, 0x10AE, 0x30AE, 0x8AE, 0x28AE, 0x18AE, 0x38AE, 0x4AE, 0x24AE, 0x14AE, 0x34AE, 0xCAE, 0x2CAE, 0x1CAE, 0x3CAE,
	0x2AE, 0x22AE, 0x12AE, 0x32AE, 0xAAE, 0x2AAE, 0x1AAE, 0x3AAE, 0x6AE, 0x26AE, 0x16AE, 0x36AE, 0xEAE, 0x2EAE, 0x1EAE, 0x3EAE,
	0x1AE, 0x21AE, 0x11AE, 0x31AE, 0x9AE, 0x29AE, 0x19AE, 0x39AE, 0x5AE, 0x25AE, 0x15AE, 0x35AE, 0xDAE, 0x2DAE, 0x1DAE, 0x3DAE,
	0x3AE, 0x23AE, 0x13AE, 0x33AE, 0xBAE, 0x2BAE, 0x1BAE, 0x3BAE, 0x7AE, 0x27AE, 0x17AE, 0x37AE, 0xFAE, 0x2FAE, 0x1FAE, 0x3FAE,
	0x6E, 0x206E, 0x106E, 0x306E, 0x86E, 0x286E, 0x186E, 0x386E, 0x46E, 0x246E, 0x146E, 0x346E, 0xC6E, 0x2C6E, 0x1C6E, 0x3C6E,
	0x26E, 0x226E, 0x126E, 0x326E, 0xA6E, 0x2A6E, 0x1A6E, 0x3A6E, 0x66E, 0x266E, 0x166E, 0x366E, 0xE6E, 0x2E6E, 0x1E6E, 0x3E6E,
	0x16E, 0x216E, 0x116E, 0x316E, 0x96E, 0x296E, 0x196E, 0x396E, 0x56E, 0x256E, 0x156E, 0x356E, 0xD6E, 0x2D6E, 0x1D6E, 0x3D6E,
	0x36E, 0x236E, 0x136E, 0x336E, 0xB6E, 0x2B6E, 0x1B6E, 0x3B6E, 0x76E, 0x276E, 0x176E, 0x376E, 0xF6E, 0x2F6E, 0x1F6E, 0x3F6E,
	0xEE, 0x20EE, 0x10EE, 0x30EE, 0x8EE, 0x28EE, 0x18EE, 0x38EE, 0x4EE, 0x24EE, 0x14EE, 0x34EE, 0xCEE, 0x2CEE, 0x1CEE, 0x3CEE,
	0x2EE, 0x22EE, 0x12EE, 0x32EE, 0xAEE, 0x2AEE, 0x1AEE, 0x3AEE, 0x6EE, 0x26EE, 0x16EE, 0x36EE, 0xEEE, 0x2EEE, 0x1EEE, 0x3EEE,
	0x1EE, 0x21EE, 0x11EE, 0x31EE, 0x9EE, 0x29EE, 0x19EE, 0x39EE, 0x5EE, 0x25EE, 0x15EE, 0x35EE, 0xDEE, 0x2DEE, 0x1DEE, 0x3DEE,
	0x3EE, 0x23EE, 0x13EE, 0x33EE, 0xBEE, 0x2BEE, 0x1BEE, 0x3BEE, 0x7EE, 0x27EE, 0x17EE, 0x37EE, 0xFEE, 0x2FEE, 0x1FEE, 0x3FEE,
	0x1E, 0x201E, 0x101E, 0x301E, 0x81E, 0x281E, 0x181E, 0x381E, 0x41E, 0x241E, 0x141E, 0x341E, 0xC1E, 0x2C1E, 0x1C1E, 0x3C1E,
	0x21E, 0x221E, 0x121E, 0x321E, 0xA1E, 0x2A1E, 0x1A1E, 0x3A1E, 0x61E, 0x261E, 0x161E, 0x361E, 0xE1E, 0x2E1E, 0x1E1E, 0x3E1E,
	0x11E, 0x211E, 0x111E, 0x311E, 0x91E, 0x291E, 0x191E, 0x391E, 0x51E, 0x251E, 0x151E, 0x351E, 0xD1E, 0x2D1E, 0x1D1E, 0x3D1E,
	0x31E, 0x231E, 0x131E, 0x331E, 0xB1E, 0x2B1E, 0x1B1E, 0x3B1E, 0x71E, 0x271E, 0x171E, 0x371E, 0xF1E, 0x2F1E, 0x1F1E, 0x3F1E,
	0x9E, 0x209E, 0x109E, 0x309E, 0x89E, 0x289E, 0x189E, 0x389E, 0x49E, 0x249E, 0x149E, 0x349E, 0xC9E, 0x2C9E, 0x1C9E, 0x3C9E,
	0x29E, 0x229E, 0x129E, 0x329E, 0xA9E, 0x2A9E, 0x1A9E, 0x3A9E, 0x69E, 0x269E, 0x169E, 0x369E, 0xE9E, 0x2E9E, 0x1E9E, 0x3E9E,
	0x19E, 0x219E, 0x119E, 0x319E, 0x99E, 0x299E, 0x199E, 0x399E, 0x59E, 0x259E, 0x159E, 0x359E, 0xD9E, 0x2D9E, 0x1D9E, 0x3D9E,
	0x39E, 0x239E, 0x139E, 0x339E, 0xB9E, 0x2B9E, 0x1B9E, 0x3B9E, 0x79E, 0x279E, 0x179E, 0x379E, 0xF9E, 0x2F9E, 0x1F9E, 0x3F9E,
	0x5E, 0x205E, 0x105E, 0x305E, 0x85E, 0x285E, 0x185E, 0x385E, 0x45E, 0x245E, 0x145E, 0x345E, 0xC5E, 0x2C5E, 0x1C5E, 0x3C5E,
	0x25E, 0x225E, 0x125E, 0x325E, 0xA5E, 0x2A5E, 0x1A5E, 0x3A5E, 0x65E, 0x265E, 0x165E, 0x365E, 0xE5E, 0x2E5E, 0x1E5E, 0x3E5E,
	0x15E, 0x215E, 0x115E, 0x315E, 0x95E, 0x295E, 0x195E, 0x395E, 0x55E, 0x255E, 0x155E, 0x355E, 0xD5E, 0x2D5E, 0x1D5E, 0x3D5E,
	0x35E, 0x235E, 0x135E, 0x335E, 0xB5E, 0x2B5E, 0x1B5E, 0x3B5E, 0x75E, 0x275E, 0x175E, 0x375E, 0xF5E, 0x2F5E, 0x1F5E, 0x3F5E,
	0xDE, 0x20DE, 0x10DE, 0x30DE, 0x8DE, 0x28DE, 0x18DE, 0x38DE, 0x4DE, 0x24DE, 0x14DE, 0x34DE, 0xCDE, 0x2CDE, 0x1CDE, 0x3CDE,
	0x2DE, 0x22DE, 0x12DE, 0x32DE, 0xADE, 0x2ADE, 0x1ADE, 0x3ADE, 0x6DE, 0x26DE, 0x16DE, 0x36DE, 0xEDE, 0x2EDE, 0x1EDE, 0x3EDE,
	0x1DE, 0x21DE, 0x11DE, 0x31DE, 0x9DE, 0x29DE, 0x19DE, 0x39DE, 0x5DE, 0x25DE, 0x15DE, 0x35DE, 0xDDE, 0x2DDE, 0x1DDE, 0x3DDE,
	0x3DE, 0x23DE, 0x13DE, 0x33DE, 0xBDE, 0x2BDE, 0x1BDE, 0x3BDE, 0x7DE, 0x27DE, 0x17DE, 0x37DE, 0xFDE, 0x2FDE, 0x1FDE, 0x3FDE,
	0x3E, 0x203E, 0x103E, 0x303E, 0x83E, 0x283E, 0x183E, 0x383E, 0x43E, 0x243E, 0x143E, 0x343E, 0xC3E, 0x2C3E, 0x1C3E, 0x3C3E,
	0x23E, 0x223E, 0x123E, 0x323E, 0xA3E, 0x2A3E, 0x1A3E, 0x3A3E, 0x63E, 0x263E, 0x163E, 0x363E, 0xE3E, 0x2E3E, 0x1E3E, 0x3E3E,
	0x13E, 0x213E, 0x113E, 0x313E, 0x93E, 0x293E, 0x193E, 0x393E, 0x53E, 0x253E, 0x153E, 0x353E, 0xD3E, 0x2D3E, 0x1D3E, 0x3D3E,
	0x33E, 0x233E, 0x133E, 0x333E, 0xB3E, 0x2B3E, 0x1B3E, 0x3B3E, 0x73E, 0x273E, 0x173E, 0x373E, 0xF3E, 0x2F3E, 0x1F3E, 0x3F3E,
	0xBE, 0x20BE, 0x10BE, 0x30BE, 0x8BE, 0x28BE, 0x18BE, 0x38BE, 0x4BE, 0x24BE, 0x14BE, 0x34BE, 0xCBE, 0x2CBE, 0x1CBE, 0x3CBE,
	0x2BE, 0x22BE, 0x12BE, 0x32BE, 0xABE, 0x2ABE, 0x1ABE, 0x3ABE, 0x6BE, 0x26BE, 0x16BE, 0x36BE, 0xEBE, 0x2EBE, 0x1EBE, 0x3EBE,
	0x1BE, 0x21BE, 0x11BE, 0x31BE, 0x9BE, 0x29BE, 0x19BE, 0x39BE, 0x5BE, 0x25BE, 0x15BE, 0x35BE, 0xDBE, 0x2DBE, 0x1DBE, 0x3DBE,
	0x3BE, 0x23BE, 0x13BE, 0x33BE, 0xBBE, 0x2BBE, 0x1BBE, 0x3BBE, 0x7BE, 0x27BE, 0x17BE, 0x37BE, 0xFBE, 0x2FBE, 0x1FBE, 0x3FBE,
	0x7E, 0x207E, 0x107E, 0x307E, 0x87E, 0x287E, 0x187E, 0x387E, 0x47E, 0x247E, 0x147E, 0x347E, 0xC7E, 0x2C7E, 0x1C7E, 0x3C7E,
	0x27E, 0x227E, 0x127E, 0x327E, 0xA7E, 0x2A7E, 0x1A7E, 0x3A7E, 0x67E, 0x267E, 0x167E, 0x367E, 0xE7E, 0x2E7E, 0x1E7E, 0x3E7E,
	0x17E, 0x217E, 0x117E, 0x317E, 0x97E, 0x297E, 0x197E, 0x397E, 0x57E, 0x257E, 0x157E, 0x357E, 0xD7E, 0x2D7E, 0x1D7E, 0x3D7E,
	0x37E, 0x237E, 0x137E, 0x337E, 0xB7E, 0x2B7E, 0x1B7E, 0x3B7E, 0x77E, 0x277E, 0x177E, 0x377E, 0xF7E, 0x2F7E, 0x1F7E, 0x3F7E,
	0xFE, 0x20FE, 0x10FE, 0x30FE, 0x8FE, 0x28FE, 0x18FE, 0x38FE, 0x4FE, 0x24FE, 0x14FE, 0x34FE, 0xCFE, 0x2CFE, 0x1CFE, 0x3CFE,
	0x2FE, 0x22FE, 0x12FE, 0x32FE, 0xAFE, 0x2AFE, 0x1AFE, 0x3AFE, 0x6FE, 0x26FE, 0x16FE, 0x36FE, 0xEFE, 0x2EFE, 0x1EFE, 0x3EFE,
	0x1FE, 0x21FE, 0x11FE, 0x31FE, 0x9FE, 0x29FE, 0x19FE, 0x39FE, 0x5FE, 0x25FE, 0x15FE, 0x35FE, 0xDFE, 0x2DFE, 0x1DFE, 0x3DFE,
	0x3FE, 0x23FE, 0x13FE, 0x33FE, 0xBFE, 0x2BFE, 0x1BFE, 0x3BFE, 0x7FE, 0x27FE, 0x17FE, 0x37FE, 0xFFE, 0x2FFE, 0x1FFE, 0x3FFE,
	0x1, 0x2001, 0x1001, 0x3001, 0x801, 0x2801, 0x1801, 0x3801 };

#define reverse_bits(b) reverse_table[b]

/*
 *   Speedup for DCS games from 1993.  This is a special version of the
 *   speedup code just for Star Trek: The Next Generation, Indiana Jones: The
 *   Pinball Adventure, and Judge Dredd.  These games appear to use a
 *   slightly different version of the DCS format from the 1994+ games, with
 *   a slightly different decoding algorithm.  The algorithm is different
 *   enough that it's hard to fold both versions into a common native
 *   implementation, so we broke it out into this separate function.
 *   
 *   Note that the core triple loop in this version is almost identical to
 *   the 1994+ version, but it makes an extra pass through its outermost loop
 *   with different starting parameters.  There's also what appears to be a
 *   radix-2 FFT pass after the main decoding loop; the same algorithm
 *   appears in the 1994+ ROMs, but it occurs just before the main decoding
 *   loop instead of after, and it isn't part of the 1994+ speedup routine.
 *   The 1994+ speedup has a volume scaling pass after the main loop; that
 *   occurs later as a separate subroutine in the 1993 ROMs, and we've left
 *   that in emulation.
 */
UINT32 dcs_speedup_1993(UINT32 pc)
{
    int ii;
    UINT32 volumeOP = *(UINT32 *)&OP_ROM[ADSP2100_PGM_OFFSET + ((pc+0x0135-0x00e8)<<2)];
    UINT16 *ram = (UINT16 *)(dcslocals.cpuRegion + ADSP2100_DATA_OFFSET);
    UINT16 volume = ram[((volumeOP>>4)&0x3fff)];
    /*DBGLOG(("OP=%6x addr=%4x V=%4x\n",volumeOP,(volumeOP>>4)&0x3fff,volume));*/

    {
        UINT16 *i0, *i1, *i2, *i3;

        /* 
         *   NB: Opcode addresses are for the ST:TNG ROMs.  These are for
         *   reference only; the other games that use the same code have it
         *   at different addresses.
         */
        
        /* 00E8     I0 = $3800 */
        i0 = &ram[0x3800];

        /* 00E9     I1 = $38fe */
        i1 = &ram[0x38fe];

        /* 00EA     I2 = $3900 */
        i2 = &ram[0x3900];

        /* 00EB     I3 = $39fe */
        i3 = &ram[0x39fe];

        /* 00EE     AR = *I0++ */
        /* 00F0     *I2++ = AR */
        *i2++ = *i0++;

        /* 00EF     *I0++ = 0 */
        *i0++ = 0;

        /* 00F1     *I2++ = 0 */
        *i2++ = 0;

        /* 00EC     M2 = -1 */
        /* 00ED     M3 = -3 */
        /* 00F2     CNTR = $0040 */
        /* 00F3     DO $00FF UNTIL CE (loop $0040 times) */
        for (ii = 0 ; ii < 0x0040 ; ++ii)
        {
            INT16 ax0, ay0, ax1, ay1, ar;

            /* 00F4      AX0 = DM(I0,M1) */
            ax0 = *i0++;
            
            /* 00F5      AY0 = DM(I1,M1) */
            ay0 = *i1++;

            /* 00F6      AR = AX0 + AY0, AX1 = DM(I0,M2) */
            ar = ax0 + ay0;
            ax1 = *i0--;
            
            /* 00F7      DM(I0,M1) = AR */
            *i0++ = ar;

            /* 00F8      AY1 = DM(I1,M2) */
            ay1 = *i1--;

            /* 00F9      DM(I1,M1) = AR, AR = AX0 - AY0 */
            *i1++ = ar;
            ar = ax0 - ay0;

            /* 00FA      DM(I2,M1) = AR, AR = AY0 - AX0 */
            *i2++ = ar;
            ar = ay0 - ax0;

            /* 00FB      DM(I3,M1) = AR, AR = AX1 + AY1 */
            *i3++ = ar;
            ar = ax1 + ay1;

            /* 00FC      DM(I2,M1) = AR */
            *i2++ = ar;

            /* 00FD      DM(I3,M3) = AR, AR = AX1 - AY1 */
            *i3 = ar; i3 -= 3;
            ar = ax1 - ay1;

            /* 00FE      DM(I0,M1) = AR, AR = AY1 - AX1 */
            *i0++ = ar;
            ar = ay1 - ax1;

            /* 00FF      DM(I1,M3) = AR */
            *i1 = ar;
            i1 -= 3;
        }
	}

	/* 0100     MSTAT = $0000 - MAC result placement = fractional */
	// This sets the multiplication mode to "fractional":  MAC results are
	// shifted left by one.  We take this into account in our C translation
	// for our own calculations below, but also set the emulator register,
	// since it affects calculations in the emulated code after we return.
	activecpu_set_reg(ADSP2100_MSTAT, 0x0000);

    {
        int mem621, mem622, mem623;
        int jj,kk;

        /* 
         *   Note that these three data words ($621, $622, $623) are used in
         *   the ROM code as scratch locations that are only accessed within
         *   this loop, so it's not necessary to save them back to real
         *   memory.  And we don't care about any pre-existing values, as the
         *   first thing we do here is initialize them.  We refer to them
         *   here as "memXXX" locations only for ease of reference back to
         *   the original ROM code.
         */
        
        /* 0101     AR = $0002 */
        /* 0102     WORD PTR [$621] = AR */
        mem621 = 2;

        /* 0103     SI = $0080 */
        /* 0104     WORD PTR [$622] = SI */
        mem622 = 0x80;

        /* 0105     SR = SI >> 1 */
        /* 0106     WORD PTR [$623] = SR */
        mem623 = 0x40;

        /* 0107     M0 = -1 */
        /* 0108     CNTR = 7 */
        /* 0109     DO $12D UNTIL CE (loop 7 times) */
        for (ii = 0 ; ii < 7 ; ++ii)
        {
            UINT16 *i0, *i1, *i2;
            UINT32 *i4, *i5;
            INT16 m2, m3;

            /* 
             *   NB: I4 and I5 are used to access PROGRAM ROM, not data
             *   memory.  These appear to be fixed tables stored in program
             *   ROM.  Note that these are 32-bit opcode locations addressed
             *   as 16-bit memory locations; when we read these, we have to
             *   shift the results right by 8 bits and then truncate to 16
             *   bits to extract the data values.  Don't ask me what the
             *   logic is behind this; that's just the way the ADSP-2100
             *   works when this addressing mode is used.  We could be tricky
             *   here and bump the byte addresses up by one to skip the
             *   right-shift step, but that would cause non-dword aligned
             *   memory reads, which is probably slower than executing the
             *   extra right-shift instruction (as it requires two bus cycles
             *   to physical memory).
             */
            
            /* 010A   I4 = PGM WORD PTR [$1780] */
            i4 = (UINT32 *)&OP_ROM[ADSP2100_PGM_OFFSET + (0x1780<<2)];

            /* 010B   I5 = PGM WORD PTR [$1700] */
            i5 = (UINT32 *)&OP_ROM[ADSP2100_PGM_OFFSET + (0x1700<<2)];

            /* 010C   I0 = $3800 */
            i0 = &ram[0x3800];

            /* 010D   I1 = $3800 */
            i1 = &ram[0x3800];
            
            /* 010E   AY0 = WORD PTR [$622] */
            /* 010F   M2 = AY0 */
            m2 = mem622;

            /* 0110   MODIFY(I1,M2) */
            i1 += m2;

            /* 0111   I2 = I1 */
            i2 = i1;

            /* 0112   AR = AY0 - 1 */
            /* 0113   M3 = AR */
            m3 = mem622 - 1;

            /* 0114   CNTR = WORD PTR [$621] */
            /* 0115   DO $126 UNTIL CE (loop WORD PTR [$621] times) */
            for (jj = 0 ; jj < mem621 ; ++jj)
            {
                INT16 mx0, my0, my1;

                /* 0117   MY0 = DM(I4,M5) (program ROM location -> shift right by 8 for data) */
                my0 = (*i4++) >> 8;

                /* 0118   MY1 = DM(I5,M5) (program ROM location -> shift right by 8 for data) */
                my1 = (*i5++) >> 8;

                /* 0119   MX0 = DM(I1,M1) */
                mx0 = *i1++;

                /* 0116   CNTR = WORD PTR [$623] */
                /* 011A   DO $123 UNTIL CE (loop WORD PTR [$623] times) */
                for (kk = 0 ; kk < mem623 ; ++kk)
                {
                    INT16 mx1, ax0, ay0, ay1, ar;
                    INT32 tmp, mr;
                    
                    /* 011B   MR = (MX0 * MY0) << 1, MX1 = DM(I1,M1) */
                    mx1 = *i1++;
                    mr = ((INT32)mx0 * my0) << 1;

                    /* 011C   MR -= (MX1 * MY1) << 1 (RND), AY0 = DM(I0,M1) */
                    ay0 = *i0++;
                    tmp = ((INT32)mx1 * my1) << 1;
                    mr = (mr - tmp + 0x8000) & (((tmp & 0xffff) == 0x8000) ? 0xfffeffff : 0xffffffff);

                    /* 011D   MR = (MX1 * MY0) << 1 (SS), AX0 = MR1 */
                    ax0 = mr >> 16;
                    mr = ((INT32)mx1 * my0) << 1;
                    
                    /* 011E   MR += (MX0 * MY1) << 1 (RND), AY1 = DM(I0,M0) */
                    ay1 = *i0--;
                    tmp = (((INT32)mx0 * my1)<<1);
                    mr = (mr + tmp + 0x8000) & (((tmp & 0xffff) == 0x8000) ? 0xfffeffff : 0xffffffff);

                    /* 011F   MX0 = DM(I1,M1), AR = AY0 - AX0 */
                    mx0 = *i1++;
                    ar = ay0 - ax0;

                    /* 0120   AR = AX0 + AY0, DM(I0,M1) = AR */
                    *i0++ = ar;
                    ar = ax0 + ay0;
                    
                    /* 0121   AR = AY1 - MR1, DM(I2,M1) = AR */
                    *i2++ = ar;
                    ar = ay1 - (mr >> 16);

                    /* 0122   AR = MR1 + AY1, DM(I0,M1) = AR */
                    *i0++ = ar;
                    ar = (mr >> 16) + ay1;
                    
                    /* 0123   DM(I2,M1) = AR */
                    *i2++ = ar;
                }

                /* 0124   MODIFY (I2,M2) */
                i2 += m2;

                /* 0125   MODIFY (I1,M3) */
                i1 += m3;
                
                /* 0126   MODIFY (I0,M2) */
                i0 += m2;
            }

            /* 0127   SI = WORD PTR [$621] */
            /* 0128   SR = SI << 1 */
            /* 0129   WORD PTR [$621] = SR */
            mem621 <<= 1;

            /* 012A   SI = WORD PTR [$623] */
            /* 012B   WORD PTR [$622] = SI */
            mem622 = mem623;

            /* 012C   SR = SI >> 1 */
            /* 012D   WORD PTR [$623] = SR0 */
            mem623 >>= 1;
        }
	}

	/* 
	 *   This appears to be a Fast Fourier Transform pass over the decoded
	 *   buffer (we infer this from the use of bit-reverse address mode,
	 *   which seems to be useful primarily [or maybe exclusively] to
	 *   implement radix-2 FFT algorithms).  Roughly the same code appears in
	 *   the 1994+ ROMs, but in those ROMs it happens before the main
	 *   decoding loop and isn't part of the C speedup routine.  This is a
	 *   fairly lengthy loop, so we've incorporated it into this version of
	 *   the speedup.
	 */
    {
        UINT16 *i4;
        UINT16 i1;
        INT16 mx0;
        UINT16 my0;

        /* 012E   M0 = 0 */
        /* 0130   M2 = $0020 */
        /* 0132   M6 = 2 */
        /* 0134   MODE CONTROL(REVERSE BIT ADDRESSING DAG1) */
        /* 012F   I1 = $7 */
        i1 = 7;

        /* 0131   I4 = $3801 */
        i4 = &ram[0x3801];

        /* 0135   MY0 = WORD PTR [$3aa] - current volume level */
        my0 = MIN(volume, 0x8000); // be paranoid about the volume, see code below

        /* 0136   MX0 = DM(reverse i1, m2) */
        mx0 = ram[reverse_bits(i1)];
        i1 += 0x20;

        /* 0133   CNTR = $100 */
        /* 0137   DO $13A UNTIL CE (loop 0x100 times) */
        for (ii = 0 ; ii < 0x100 ; ii++)
        {
            /* 0138   MR = (MX0 * MY0) << 1, MX0 = DM(reverse i1,m2) */
            UINT32 mr = ((INT32)mx0 * my0); // << 1; // see shift below
            mx0 = ram[reverse_bits(i1)];
            i1 += 0x20;

            /* 0139  SATURATE MR (effectively NOP, as volume always <= 0x8000) */
            /* 013A  DM(I4,M6) = MR1 */
            *i4 = mr >> 15; // >> 16; // see above
            i4 += 2;
        }
	}
    activecpu_set_reg(ADSP2100_PC, pc + (0x13a - 0x00e8));
    return 0;                                              /* execute a NOP */
}
#endif /* WPCDCSSPEEDUP */
