1 2 3 4 | Next→
//========================================================================================
//  processor.js
//  Copyright (C) 2018 Makoto Kamada
//
//  This program is derived from XEiJ. Please read the XEiJ License.
//  このプログラムは XEiJ の派生物です。XEiJ 使用許諾条件をお読みください。
//  http://stdkmd.com/xeij/
//========================================================================================



//XEiJ使用許諾条件
/*******************************************************************************
--------------------------------------------------------------------------------
XEiJ License (2016-02-26)

  You can use, modify and redistribute the XEiJ (X68000 Emulator in Java) if the
  following conditions are met.

  1. The XEiJ and its derivatives must be distributed free of charge.

  2. The XEiJ and its derivatives must be distributed along with those source
     code that is necessary to recompile them.

  3. You must attach this text to derivatives of the XEiJ.

Copyright

  Source code and data of the XEiJ except for the following parts are
  copyrighted by Makoto Kamada.

  1. Basic software products for X68000 that were distributed free of charge,
     such as IPLROM.DAT, HUMAN.SYS, and so on, are copyrighted by right-holder
     companies.
     http://retropc.net/x68000/software/sharp/

  2. Emulation algorithm of YM2151 is derived from the MAME.
     http://mamedev.org/

  3. Default font data is composed of fonts designed by Keitarou Hiraki and Num
     Kadoma.
     http://hp.vector.co.jp/authors/VA000874/
     http://www.geocities.jp/littlimi/

  4. IPL programs that are written into 2HDE and 2HS floppy disk images in
     formatting are copyrighted by 6no8rou.

Disclaimer

  XEiJ is provided as is. No warranty against disadvantages caused by using
  and/or inability to use this software is given regardless of whether it had
  been able to be foreseen.

--------------------------------------------------------------------------------
XEiJ 使用許諾条件 (2016-02-26)

  XEiJ (X68000 Emulator in Java) は以下の条件で使用し、改変し、再配布することが
  できます。

  1. XEiJ とその派生物は無償で配布されなければなりません。

  2. XEiJ とその派生物はそれらを再コンパイルするために必要なソースコードと共に配
     布されなければなりません。

  3. XEiJ の派生物には本文書を添付しなければなりません。

著作権

  以下の部分を除く XEiJ のソースコードとデータは Makoto Kamada の著作物です。

  1. IPLROM.DAT、HUMAN.SYS などの無償公開された X68000 の基本ソフトウェア製品は
     権利各社の著作物です。
     http://retropc.net/x68000/software/sharp/

  2. YM2151 のエミュレーションアルゴリズムは MAME に由来します。
     http://mamedev.org/

  3. デフォルトのフォントデータは平木敬太郎氏と門真なむ氏によってデザインされた
     フォントで構成されています。
     http://hp.vector.co.jp/authors/VA000874/
     http://www.geocities.jp/littlimi/

  4. 2HDE および 2HS フロッピーディスクイメージをフォーマットするときに書き込ま
     れる IPL プログラムは 6no8rou 氏の著作物です。

免責事項

  XEiJ は現状のまま (AS-IS) 提供されます。このソフトウェアを用いたことあるいは用
  いることができなかったことで不利益が生じたとしても、それが予見可能だったかどう
  かに関わらず補償されません。

--------------------------------------------------------------------------------
*******************************************************************************/





//========================================================================================
//
//  Math
//
//========================================================================================

//------------------------------------------------------------------------
//数学定数
let E = Math.E;
let LN10 = Math.LN10;
let LN2 = Math.LN2;
let LOG10E = Math.LOG10E;
let LOG2E = Math.LOG2E;
let PI = Math.PI;
let SQRT1_2 = Math.SQRT1_2;
let SQRT2 = Math.SQRT2;
let ONE_3 = 1 / 3;
let TWO_3 = 2 / 3;
let FOUR_3 = 4 / 3;
let TWOPI = 2 * PI;
let PI_2 = 0.5 * PI;
let PI_4 = 0.25 * PI;
let DEG_RAD = 180 / PI;
let RAD_DEG = PI / 180;

//------------------------------------------------------------------------
//y = abs (x)
//  絶対値関数 absolute value function アブソリュートバリューファンクション
let abs = Math.abs;

//------------------------------------------------------------------------
//y = acos (x)
//  逆余弦 inverse cosine インバースコサイン
let acos = Math.acos;

//------------------------------------------------------------------------
//y = acosh (x)
//  逆双曲線余弦 inverse hyperbolic cosine インバースハイパボリックコサイン
//
function builtin_acosh (x) {
  return log (x + sqrt (x * x - 1.0));
}
let acosh = Math.acosh || builtin_acosh;  //ECMAScrpit 6

//------------------------------------------------------------------------
//y = acot (x)
//  逆余接 inverse cotangent インバースコタンジェント
function acot (x) {
  return atan (1.0 / x);
}

//------------------------------------------------------------------------
//y = acoth (x)
//  逆双曲線余接 inverse hyperbolic cotangent インバースハイパボリックコタンジェント
function acoth (x) {
  return 0.5 * sgn (x) * log1p (2.0 / (abs (x) - 1.0));
}

//------------------------------------------------------------------------
//y = acsc (x)
//  逆余割 inverse csc インバースコセカント
function acsc (x) {
  return asin (1.0 / x);
}

//------------------------------------------------------------------------
//y = acsch (x)
//  逆双曲線余割 inverse hyperbolic csc インバースハイパボリックコセカント
function acsch (x) {
  return asinh (1.0 / x);
}

//------------------------------------------------------------------------
//y = asec (x)
//  逆正割 inverse secant インバースセカント
function asec (x) {
  return atan2 (sqrt (x * x - 1), sgn (x));
}

//------------------------------------------------------------------------
//y = asech (x)
//  逆双曲線正割 inverse hyperbolic secant インバースハイパボリックセカント
function asech (x) {
  return acosh (1.0 / x);
}

//------------------------------------------------------------------------
//y = asin (x)
//  逆正弦 inverse sine インバースサイン
let asin = Math.asin;

//------------------------------------------------------------------------
//y = asinh (x)
//  逆双曲線正弦 inverse hyperbolic sine インバースハイパボリックサイン
function builtin_asinh (x) {
  return sgn (x) * log (abs (x) + sqrt (x * x + 1.0));
}
let asinh = Math.asinh || builtin_asinh;

//------------------------------------------------------------------------
//y = atan (x)
//  逆正接 inverse tangent インバースタンジェント
let atan = Math.atan;

//------------------------------------------------------------------------
//y = atan2 (y, x)
//  逆正接 inverse tangent インバースタンジェント
let atan2 = Math.atan2;

//------------------------------------------------------------------------
//y = atanh (x)
//  逆双曲線正接 inverse hyperbolic tangent インバースハイパボリックタンジェント
function builtin_atanh (x) {
  return x == 0.0 ? x : 0.5 * log ((1.0 + x) / (1.0 - x));
}
let atanh = Math.atanh || builtin_atanh;

//------------------------------------------------------------------------
//y = cbrt (x)
//  1/3乗(立方根)
function builtin_cbrt (x) {
  return sgn (x) * pow (abs (x), ONE_3);
}
let cbrt = Math.cbrt || builtin_cbrt;

//------------------------------------------------------------------------
//y = ceil (x)
//  天井関数 ceiling function
let ceil = Math.ceil;

//------------------------------------------------------------------------
//n = clz32 (x)
//  count leading zeros
function builtin_clz32 (x) {
  let n = ((x >>> 16) - 1) >> 12 & 16;
  n += ((x >>> (24 - n)) - 1) >> 5 & 8;
  n += ((x >>> (28 - n)) - 1) >> 2 & 4;
  x >>>= 28 - n;
  return n + ((0x55af >>> (x << 1) & 3) - ((x - 1) >> 4));
}
let clz32 = Math.clz32 || builtin_clz32;

//------------------------------------------------------------------------
//s = cmp (x, y)
//  自然順序比較
function cmp (x, y) {
  return y < x ? 1.0 : x < y ? -1.0 : 0.0;
}

//------------------------------------------------------------------------
//s = cmpnum (x, y)
//  数値比較 spaceship operator
function cmpnum (x, y) {
  x = +x;
  y = +y;
  return isNaN (x) || isNaN (y) || x === y ? 0.0 : y < x ? 1.0 : -1.0;
}

//------------------------------------------------------------------------
//z = copysign (x, y)
//  符号複写
function copysign (x, y) {
  x = abs (x);
  return y < 0.0 || y == 0.0 && 1.0 / y < 0.0 ? -x : x;  //1/+0=+Infinity,1/-0=-Infinity。-NaNは作れない
}

//------------------------------------------------------------------------
//y = cos (x)
//  余弦 cosine コサイン
let cos = Math.cos;

//------------------------------------------------------------------------
//y = cosh (x)
//  双曲線余弦 hyperbolic cosine ハイパボリックコサイン
function builtin_cosh (x) {
  x = exp (x);
  return 0.5 * (x + 1.0 / x);
}
let cosh = Math.cosh || builtin_cosh;

//------------------------------------------------------------------------
//y = cot (x)
//  余接 cotangent コタンジェント
function cot (x) {
  return cos (x) / sin (x);
}

//------------------------------------------------------------------------
//y = coth (x)
//  双曲線余接 hyperbolic cotangent ハイパボリックコタンジェント
function coth (x) {
  return cosh (x) / sinh (x);
}

//------------------------------------------------------------------------
//y = csc (x)
//  余割 csc コセカント
function csc (x) {
  return 1.0 / sin (x);
}

//------------------------------------------------------------------------
//y = csch (x)
//  双曲線余割 hyperbolic csc ハイパボリックコセカント
function csch (x) {
  return 1.0 / sinh (x);
}

//------------------------------------------------------------------------
//y = ctz32 (x)
//  count trailing zeros
const CTZ32_HASH = [0, 1, 2, 5, 3, 9, 6, 11, 15, 4, 8, 10, 14, 7, 13, 12];
function builtin_ctz32 (x) {
  x >>>= 0;  //32bit符号なし整数にする
  if (0 < x) {  //1以上かつNaNではないとき
    let n = ((x & 65535) - 1) >> 12 & 16;  //x<<16?0:16
    x >>>= n;
    //  xの下位16bitは0ではない
    //  (1)x&-xで最下位の1<<0..15を取り出す
    //  (2)最小完全ハッシュ関数x*2479>>>12&15で1<<0..15を0..15に変換する
    //  (3)配列参照で0..15を1<<0..15のbit番号に変換する
    //  配列参照のコストによっては見た目ほど速くないかも知れない
    return n + CTZ32_HASH[(x & -x) * 2479 >>> 12 & 15];
  } else {
    return 32;
  }
}
let ctz32 = Math.ctz32 || builtin_ctz32;

//------------------------------------------------------------------------
//y = cub (x)
//  3乗
function cub (x) {
  return x * x * x;
}

//------------------------------------------------------------------------
//x = cubic (a, b, c, d)
//  3次方程式
function cubic (a, b, c, d) {
  return (a != 0.0 ? (a = 1.0 / a,
                      b *= a * ONE_3,
                      c *= a,
                      d *= a,
                      a = b * b - c * ONE_3,
                      c = 0.5 * (b * c - 2.0 * b * b * b - d),
                      d = c * c - a * a * a,
                      (0.0 <= d ? (d = sqrt (d),
                                   cbrt (c - d) + cbrt (c + d)) :
                       2.0 * sqrt (a) * cos (atan2 (sqrt (-d), c) * ONE_3)) - b) :
          b != 0.0 ? (b = 1.0 / b,
                      c *= 0.5 * b,
                      d = c * c - b * d,
                      0.0 <= d ? sqrt (d) - c : NaN) :
          c != 0.0 ? -d / c :
          d != 0.0 ? NaN :
          0.0);
}

//------------------------------------------------------------------------
//b = defined (x)
//  x !== undefined
function defined (x) {
  return x !== undefined;
}

//------------------------------------------------------------------------
//y = deg (x)
//  180/pi倍(ラジアン)
function deg (x) {
  return DEG_RAD * x;
}

//------------------------------------------------------------------------
//y = exp (x)
//  指数関数 exponential
let exp = Math.exp;

//------------------------------------------------------------------------
//y = exp10 (x)
//  底が10の指数関数 exponential with base 10
function exp10 (x) {
  return exp (LN10 * x);
}

//------------------------------------------------------------------------
//y = exp2 (x)
//  底が2の指数関数 exponential with base 2
function exp2 (x) {
  return exp (LN2 * x);
}

//------------------------------------------------------------------------
//y = exp2m1 (x)
//  0に近い数の底が2の指数関数 exponential of number being close to 0 with base 2
function exp2m1 (x) {
  return exp2 (x) - 1.0;
}

//------------------------------------------------------------------------
//y = expm1 (x)
//  0に近い数の指数関数 exponential of number being close to 0
function builtin_expm1 (x) {
  return x == 0 ? x : exp (x) - 1.0;
}
let expm1 = Math.expm1 || builtin_expm1;

//------------------------------------------------------------------------
//y = ext16s (x)
//  符号拡張(16bit符号あり整数)
//  小数点以下を切り捨ててから2^16で割った余りを-2^15..2^15-1の範囲で返す
function ext16s (x) {
  x = trunc (x) + 2 ** 15;  //0x1p+15
  return x - floor (x * 2 ** -16) * 2 ** 16 - 2 ** 15;  //0x1p-16,0x1p+16,0x1p+15
}

//------------------------------------------------------------------------
//y = ext16u (x)
//  ゼロ拡張(16bit符号なし整数)
//  小数点以下を切り捨ててから2^16で割った余りを0..2^16-1の範囲で返す
function ext16u (x) {
  x = trunc (x);
  return x - floor (x * 2 ** -16) * 2 ** 16;  //0x1p-16,0x1p+16
}

//------------------------------------------------------------------------
//y = ext32s (x)
//  符号拡張(32bit符号あり整数)
//  小数点以下を切り捨ててから2^32で割った余りを-2^31..2^31-1の範囲で返す
function ext32s (x) {
  x = trunc (x) + 2 ** 31;  //0x1p+31
  return x - floor (x * 2 ** -32) * 2 ** 32 - 2 ** 31;  //0x1p-32,0x1p+32,0x1p+31
}

//------------------------------------------------------------------------
//y = ext32u (x)
//  ゼロ拡張(32bit符号なし整数)
//  小数点以下を切り捨ててから2^32で割った余りを0..2^32-1の範囲で返す
function ext32u (x) {
  x = trunc (x);
  return x - floor (x * 2 ** -32) * 2 ** 32;  //0x1p-32,0x1p+32
}

//------------------------------------------------------------------------
//y = ext64s (x)
//  符号拡張(64bit符号あり整数)
//  小数点以下を切り捨ててから2^64で割った余りを-2^63..2^63-1の範囲で返す
function ext64s (x) {
  x = trunc (x) + 2 ** 63;  //0x1p+63
  return x - floor (x * 2 ** -64) * 2 ** 64 - 2 ** 63;  //0x1p-64,0x1p+64,0x1p+63
}

//------------------------------------------------------------------------
//y = ext64u (x)
//  ゼロ拡張(64bit符号なし整数)
//  小数点以下を切り捨ててから2^64で割った余りを0..2^64-1の範囲で返す
function ext64u (x) {
  x = trunc (x);
  return x - floor (x * 2 ** -64) * 2 ** 64;  //0x1p-64,0x1p+64
}

//------------------------------------------------------------------------
//y = ext8s (x)
//  符号拡張(8bit符号あり整数)
//  小数点以下を切り捨ててから2^8で割った余りを-2^7..2^7-1の範囲で返す
function ext8s (x) {
  x = trunc (x) + 2 ** 7;  //0x1p+7
  return x - floor (x * 2 ** -8) * 2 ** 8 - 2 ** 7;  //0x1p-8,0x1p+8,0x1p+7
}

//------------------------------------------------------------------------
//y = ext8u (x)
//  ゼロ拡張(8bit符号なし整数)
//  小数点以下を切り捨ててから2^8で割った余りを0..2^8-1の範囲で返す
function ext8u (x) {
  x = trunc (x);
  return x - floor (x * 2 ** -8) * 2 ** 8;  //0x1p-8,0x1p+8
}

//------------------------------------------------------------------------
//z = fdiv (x, y)
//  floor除算の商
function fdiv (x, y) {
  return floor (x / y);
}

//------------------------------------------------------------------------
//y = floor (x)
//  床関数 floor function
let floor = Math.floor;

//------------------------------------------------------------------------
//z = floor2 (x, y)
//  床倍数
function floor2 (x, y) {
  return floor (x / y) * y;
}

//------------------------------------------------------------------------
//y = fracf (x)
//  床小数部 fractional part (floor)
function fracf (x) {
  return x - floor (x);
}

//------------------------------------------------------------------------
//y = fract (x)
//  幹小数部 fractional part (trunc)
function fract (x) {
  return isFinite (x) ? copysign (x - trunc (x), x) : x;
}

//------------------------------------------------------------------------
//z = frem (x, y)
//  floor除算の余り
function frem (x, y) {
  return x - floor (x / y) * y;
}

//------------------------------------------------------------------------
//y = fround (x)
//  最も近いfloat値に丸める
function builtin_fround (x) {
  return new Float32Array ([x]) [0];
}
let fround = Math.fround || builtin_fround;

//------------------------------------------------------------------------
//y = hypot2 (a, b)
//y = hypot3 (a, b, c)
//y = hypot4 (a, b, c, d)
//y = hypotn (n, ...)
//  斜辺 hypotenuse
function builtin_hypot2 (a, b) {
  return sqrt (a * a + b * b);
}
function builtin_hypot3 (a, b, c) {
  return sqrt (a * a + b * b + c * c);
}
function builtin_hypot4 (a, b, c, d) {
  return sqrt (a * a + b * b + c * c + d * d);
}
function builtin_hypotn () {
  let y = 0.0;
  for (let i = 0, n = arguments.length; i < n; i++) {
    let x = arguments[i];
    y += x * x;
  }
  return sqrt (y);
}
let hypot2 = Math.hypot || builtin_hypot2;
let hypot3 = Math.hypot || builtin_hypot3;
let hypot4 = Math.hypot || builtin_hypot4;
let hypotn = Math.hypot || builtin_hypotn;

//------------------------------------------------------------------------
//z = ieeerem (x, y)
//  剰余(round-to-nearest)
function ieeerem (x, y) {
  return !isFinite (x) || isNaN (y) ? NaN : !isFinite (y) ? x : x - roundn (x / y) * y;
}

//------------------------------------------------------------------------
//z = imul (x, y)
//  32bit符号あり整数乗算(下位)
//  64bit浮動小数点数を32bit符号あり整数に変換して掛け合わせ、
//  積の64bit符号あり整数の下位32bitを32bit符号あり整数として取り出して64bit浮動小数点数に変換して返す
//
//  64bit浮動小数点数から32bit符号なし整数を取り出すとき32bit符号あり整数を経由してはならない
//  同じ32bit整数への変換でもdouble→intのキャストは-0x80000000..0x7fffffffで飽和するので、
//  0x80000000..0xffffffffのビットパターンが保存されない
function builtin_imul (x, y) {
  let b = x & 65535, d = y & 65535;
  return ((x >> 16) * d + b * (y >> 16) << 16) + b * d >>> 0 >> 0;
}
let imul = Math.imul || builtin_imul;

//------------------------------------------------------------------------
//z = imulh (x, y)
//  32bit符号あり整数乗算(上位)
//  64bit浮動小数点数を32bit符号あり整数に変換して掛け合わせ、
//  積の64bit符号あり整数の上位32bitを32bit符号あり整数として取り出して64bit浮動小数点数に変換して返す
//
//  64bit浮動小数点数から32bit符号なし整数を取り出すとき32bit符号あり整数を経由してはならない
//  同じ32bit整数への変換でもdouble→intのキャストは-0x80000000..0x7fffffffで飽和するので、
//  0x80000000..0xffffffffのビットパターンが保存されない
function imulh (x, y) {
  let a = x >> 16, b = x & 65535, c = y >> 16, d = y & 65535;
  return a * c + ((a * d + b * c + (b * d >>> 16)) * 2 ** -16 >> 0) >> 0;  //0x1p-16  *0x1p-16>>0の部分は入力が33bitあるので>>16にしてはならない
}

//------------------------------------------------------------------------
//b = isFinite (x)
//  有限か

//------------------------------------------------------------------------
//b = isInfinity (x)
//  ±Infinityか
function isInfinity (x) {
  return !isNaN (x) && !isFinite (x);
}

//------------------------------------------------------------------------
//b =isNaN (x)
//  NaNか

//------------------------------------------------------------------------
//b = isalnum (x)
function isalnum (x) {
  return isdigit (x) || isalpha (x);
}

//------------------------------------------------------------------------
//b = isalpha (x)
function isalpha (x) {
  return isupper (x) || islower (x);
}

//------------------------------------------------------------------------
//b = isascii (x)
function isascii (x) {
  return 0x00 <= x && x <= 0x7f;
}

//------------------------------------------------------------------------
//b = isbdigit (x)
function isbdigit (x) {
  return 0x30 <= x && x <= 0x31;  //'0'..'1'
}

//------------------------------------------------------------------------
//b = isblank (x)
function isblank (x) {
  return x == 0x09 || x == 0x20;  //'\t'||' '
}

//------------------------------------------------------------------------
//b = iscntrl (x)
function iscntrl (x) {
  return isascii (x) && !isprint (x);
}

//------------------------------------------------------------------------
//b = iscsym (x)
function iscsym (x) {
  return isdigit (x) || iscsymf (x);
}

//------------------------------------------------------------------------
//b = iscsymf (x)
function iscsymf (x) {
  return isalpha (x) || x == 0x5f;  //||'_'
}

//------------------------------------------------------------------------
//b = isdigit (x)
function isdigit (x) {
  return 0x30 <= x && x <= 0x39;  //'0'..'9'
}

//------------------------------------------------------------------------
//b = isgraph (x)
function isgraph (x) {
  return 0x21 <= x && x <= 0x7e;  //'!'..'~'
}

//------------------------------------------------------------------------
//b = islower (x)
function islower (x) {
  return 0x61 <= x && x <= 0x7a;  //'a'..'z'
}

//------------------------------------------------------------------------
//b = isodigit (x)
function isodigit (x) {
  return 0x30 <= x && x <= 0x37;  //'0'..'7'
}

//------------------------------------------------------------------------
//b = isprint (x)
function isprint (x) {
  return 0x20 <= x && x <= 0x7e;  //' '..'~'
}

//------------------------------------------------------------------------
//b = ispunct (x)
function ispunct (x) {
  return isgraph (x) && !isalnum (x);
}

//------------------------------------------------------------------------
//b = isspace (x)
function isspace (x) {
  return (0x09 <= x && x <= 0x0d) || x == 0x20;  //'\t'..'\r'||' '
}

//------------------------------------------------------------------------
//b = isupper (x)
function isupper (x) {
  return 0x41 <= x && x <= 0x5a;  //'A'..'Z'
}

//------------------------------------------------------------------------
//b = isxdigit (x)
function isxdigit (x) {
  return isdigit (x) || (0x41 <= x && x <= 0x46) || (0x61 <= x && x <= 0x66);  //||'A'..'F'||'a'..'f'
}

//------------------------------------------------------------------------
//y = log (x)
//  自然対数 natural logarithm
let log = Math.log;

//------------------------------------------------------------------------
//y = log10 (x)
//  常用対数 common logarithm
function builtin_log10 (x) {
  return log (x) * LOG10E;
}
let log10 = Math.log10 || builtin_log10;

//------------------------------------------------------------------------
//y = log1p (x)
//  1に近い数の自然対数 natural logarithm of number being close to 1
function builtin_log1p (x) {
  return x == 0 ? x : log (1.0 + x);
}
let log1p = Math.log1p || builtin_log1p;

//------------------------------------------------------------------------
//y = log2 (x)
//  二進対数 binary logarithm
function builtin_log2 (x) {
  return log (x) * LOG2E;
}
let log2 = Math.log2 || builtin_log2;

//------------------------------------------------------------------------
//y = max2 (a, b)
//y = max3 (a, b, c)
//y = max4 (a, b, c, d)
//y = maxn (n, ...)
//  最大値
let max2 = Math.max;
let max3 = Math.max;
let max4 = Math.max;
let maxn = Math.max;

//------------------------------------------------------------------------
//y = min2 (a, b)
//y = min3 (a, b, c)
//y = min4 (a, b, c, d)
//y = minn (n, ...)
//  最小値
let min2 = Math.min;
let min3 = Math.min;
let min4 = Math.min;
let minn = Math.min;

//------------------------------------------------------------------------
//z = pow (x, y)
//  累乗
let pow = Math.pow;

//------------------------------------------------------------------------
//y = rad (x)
//  pi/180倍(ラジアン)
function rad (x) {
  return RAD_DEG * x;
}

//------------------------------------------------------------------------
//y = rounda (x)
//  丸め(away-from-zero)
function rounda (x) {
  return x == 0 ? x : 0.0 < x ? floor (x + 0.5) : ceil (x - 0.5);
}

//------------------------------------------------------------------------
//y = roundm (x)
//  丸め(toward-minus-infinity)
function roundm (x) {
  return !isFinite (x) ? x : 0.0 <= x && x <= 0.5 ? floor (x) : ceil (x - 0.5);
}

//------------------------------------------------------------------------
//y = roundn (x)
//  丸め(nearest-even)
function roundn (x) {
  let y = floor (x + 0.5), z = ceil (x - 0.5);
  return copysign (y == z ? y : floor (y * 0.5) * 2.0 == y ? y : z, x);
}

//------------------------------------------------------------------------
//y = roundp (x)
//  丸め(toward-plus-infinity)
function roundp (x) {
  return !isFinite (x) ? x : -0.5 <= x && x <= 0.0 ? ceil (x) : floor (x + 0.5);
}

//------------------------------------------------------------------------
//z = roundp2 (x, y)
//  丸め(toward-plus-infinity)
function roundp2 (x, y) {
  return roundp (x / y) * y;
}

//------------------------------------------------------------------------
//y = roundz (x)
//  丸め(toward-zero)
function roundz (x) {
  return !isFinite (x) || x == 0 ? x : (0.0 < x ?
                                        x <= 0.5 ? 0.0 : ceil (x - 0.5) :
                                        -0.5 <= x ? -0.0 : floor (x + 0.5));
}

//------------------------------------------------------------------------
//y = sec (x)
//  正割 secant セカント
function sec (x) {
  return 1.0 / cos (x);
}

//------------------------------------------------------------------------
//y = sech (x)
//  双曲線正割 hyperbolic secant ハイパボリックセカント
function sech (x) {
  return 1.0 / cosh (x);
}

//------------------------------------------------------------------------
//y = sgn (x)
//  符号
function builtin_sgn (x) {
  x = +x;
  return x === 0 || isNaN (x) ? x : 0.0 < x ? 1.0 : -1.0;
}
let sgn = Math.sign || builtin_sgn;

//------------------------------------------------------------------------
//y = sin (x)
//  正弦 sine サイン
let sin = Math.sin;

//------------------------------------------------------------------------
//y = sinh (x)
//  双曲線正弦 hyperbolic sine ハイパボリックサイン
function builtin_sinh (x) {
  return x == 0 ? x : x = exp (x), 0.5 * (x - 1.0 / x);
}
let sinh = Math.sinh || builtin_sinh;

//------------------------------------------------------------------------
//y = sqrt (x)
//  1/2乗(平方根)
let sqrt = Math.sqrt;

//------------------------------------------------------------------------
//y = squ (x)
//  2乗
function squ (x) {
  return x * x;
}

//------------------------------------------------------------------------
//y = tan (x)
//  正接 tangent タンジェント
let tan = Math.tan;

//------------------------------------------------------------------------
//y = tanh (x)
//  双曲線正接 hyperbolic tangent ハイパボリックタンジェント
function builtin_tanh (x) {
  return isNaN (x) || x == 0 ? x : isFinite (x) ? (x = exp (2.0 * x), (x - 1.0) / (x + 1.0)) : 0.0 <= x ? 1.0 : -1.0;
}
let tanh = Math.tanh || builtin_tanh;

//------------------------------------------------------------------------
//b = tolower (x)
function tolower (x) {
  return isupper (x) ? x | 0x20 : x;
}

//------------------------------------------------------------------------
//b = toupper (x)
function toupper (x) {
  return islower (x) ? x & ~0x20 : x;
}

//------------------------------------------------------------------------
//y = trunc (x)
//  切り落とし truncate
function builtin_trunc (x) {
  return isNaN (x) ? NaN : 0.0 <= x ? floor (x) : ceil (x);
}
let trunc = Math.trunc || builtin_trunc;

//------------------------------------------------------------------------
//z = umul (x, y)
//  32bit符号なし整数乗算(下位)
//  64bit浮動小数点数を32bit符号なし整数に変換して掛け合わせ、
//  積の64bit符号なし整数の下位32bitを32bit符号なし整数として取り出して64bit浮動小数点数に変換して返す
//
//  64bit浮動小数点数から32bit符号なし整数を取り出すとき32bit符号あり整数を経由してはならない
//  同じ32bit整数への変換でもdouble→intのキャストは-0x80000000..0x7fffffffで飽和するので、
//  0x80000000..0xffffffffのビットパターンが保存されない
function umul (x, y) {
  let b = x >>> 0 & 65535, d = y >>> 0 & 65535;
  return ((x >>> 16) * d + b * (y >>> 16) << 16) + b * d >>> 0;
}

//------------------------------------------------------------------------
//z = umulh (x, y)
//  32bit符号なし整数乗算(上位)
//  64bit浮動小数点数を32bit符号なし整数に変換して掛け合わせ、
//  積の64bit符号なし整数の上位32bitを32bit符号なし整数として取り出して64bit浮動小数点数に変換して返す
//
//  64bit浮動小数点数から32bit符号なし整数を取り出すとき32bit符号あり整数を経由してはならない
//  同じ32bit整数への変換でもdouble→intのキャストは-0x80000000..0x7fffffffで飽和するので、
//  0x80000000..0xffffffffのビットパターンが保存されない
function umulh (x, y) {
  let a = x >>> 16, b = x >>> 0 & 65535, c = y >>> 16, d = y >>> 0 & 65535;
  return a * c + ((a * d + b * c + (b * d >>> 16)) * 2 ** -16 >>> 0) >>> 0;  //0x1p-16  *0x1p-16>>>0の部分は入力が33bitあるので>>>16にしてはならない
}





//------------------------------------------------------------------------

let opmpcmProcessor;  //プロセッサ

//内部バッファ
const OPM_OSC_FREQ = 4000000;  //int  OPMのオシレータ周波数(Hz)。4000000Hz
const INTERNAL_SAMPLE_RATE = (OPM_OSC_FREQ / 64);  //int  OPMのサンプリング周波数=内部サンプリング周波数(Hz)。62500Hz
const INTERNAL_BUFFER_MSEC = 50;  //int  内部バッファの長さ(ms)。50ms=(1/20)s
const INTERNAL_BUFFER_FRAMES = INTERNAL_SAMPLE_RATE * INTERNAL_BUFFER_MSEC / 1000;  //int  内部バッファのフレーム数。62500/20=3125
let internalBufferLeft;  //Float32Array  内部バッファ左
let internalBufferRight;  //Float32Array  内部バッファ右
let internalBufferTime;  //double  内部バッファに次に充填する時刻

//外部バッファ
//  外部バッファは内部サンプリング周波数で構築された内部バッファを外部サンプリング周波数に合わせて間引き・重複して長さを変更した架空のバッファ
let externalSampleRate;  //int  外部サンプリング周波数。48000Hzまたは44100Hz
let externalBufferFrames;  //int  外部バッファのフレーム数。48000Hzのとき480、44100Hzのとき441
let externalToInternal;  //Int32Array  外部バッファのインデックスを内部バッファのインデックスに変換するテーブル
let externalBufferPointer;  //int  外部バッファから次に読み出す位置



//------------------------------------------------------------------------
//OPM

const OPM_PORT_COUNT = 2;  //OPMポートの数
let opmPortArray;  //OPMポートの配列

const OPM_CHANNEL_COUNT = 8;  //int  1ポートあたりのチャンネル数。8以上の2の累乗。8より大きいときはアドレスの上位バイトを使う
const OPM_SLOT_COUNT = (4 * OPM_CHANNEL_COUNT);  //int  1ポートあたりのスロット数。32以上の2の累乗

const OPM_PHASE_SHIFT = 16;  //int
const OPM_PHASE_MASK = ((1 << OPM_PHASE_SHIFT) - 1);  //int  65535
const OPM_SIN_BITS = 10;  //int
const OPM_SIN_TABLE_SIZE = (1 << OPM_SIN_BITS);  //int  1024
const OPM_SIN_MASK = (OPM_SIN_TABLE_SIZE - 1);  //int  1023

const OPM_TL_BITS = 10;  //int
const OPM_TL_SIZE = (1 << OPM_TL_BITS);  //int  1024

const OPM_TL_BLOCK_SIZE = (256 * 2);  //int  512
const OPM_TL_TABLE_SIZE = (13 * OPM_TL_BLOCK_SIZE);  //int  6656
const OPM_ENV_QUIET = (OPM_TL_TABLE_SIZE >> 3);  //int  832

//タイマ
//  RESET,IRQEN,LOAD,ISTのビットの順序
//  Inside X68000にISTのビットの順序が上位からA|Bと書かれているが、B|Aの誤り
const OPM_RESETB = 0x20;  //int  0b00100000
const OPM_RESETA = 0x10;  //int  0b00010000
const OPM_IRQENB = 0x08;  //int  0b00001000
const OPM_IRQENA = 0x04;  //int  0b00000100
const OPM_LOADB  = 0x02;  //int  0b00000010
const OPM_LOADA  = 0x01;  //int  0b00000001
const OPM_ISTB   = 0x02;  //int  0b00000010
const OPM_ISTA   = 0x01;  //int  0b00000001

//PG
//
//  YM2151は入力クロックとして3.58MHzを与えたときにラの音(キーコード0x4a)の周波数が440Hzになるように設計されている
//    (2062*2^(4-2))*3.58e+6/2^26=439.9991
//  X68000では4MHzが与えられているため、およそ2度高い音が出る
//    (2062*2^(4-2))*4e+6/2^26=491.6191
//  キーコードを2減らすことで本来のラの音に近い音が出る。キーコードを減らすときは欠番の跨ぎ方に注意する
//    (1837*2^(4-2))*4e+6/2^26=437.9749
//  より正確な音を出すにはキーフラクションも調整する
//    log2(4/3.58)*(64*12)=122.9110
//  キーフラクションを123減らすことで本来のラの音に近い音が出る。それでも3.58MHzを与えたときほど正確なラの音は出せない
//    (1845*2^(4-2))*4e+6/2^26=439.8823
//
//  細かい波形はD/AやA/Dを通るときに変化してしまうので観測が難しいが、周波数はある程度の時間観測して振動回数を数えれば分かる
//  X68030の実機で観測し、1オクターブ(16*64=1024音)がすべて整数になる最小の係数を求めたところ、音が重複している箇所も含めてMAMEが持っているテーブルとまったく同じものが得られた
//
//  KFが平均音階の1度を正確に64分割した結果を丸めたものであればテーブルの全体を自動生成できるはずだが、間隔にばらつきがあるため単純に分割しただけでは再現できない
1 2 3 4 | Next→