xeij/MC68060.java (3/3)
1 2 3
      XEiJ.regRn[2] = 65535;  //d2。-1ではない
      XEiJ.regRn[3] = 0;  //d3
      XEiJ.regRn[8] = a;  //a0
      XEiJ.regCCR = 0;  //エラーなし。アンダーフローはエラーとみなされない
      return s < 0.0 ? -0.0 : 0.0;
    }
    if (350 < e) {
      XEiJ.regRn[2] = 0;  //d2
      XEiJ.regRn[3] = 0;  //d3
      XEiJ.regRn[8] = a;  //a0
      XEiJ.regCCR = XEiJ.REG_CCR_V | XEiJ.REG_CCR_C;  //オーバーフロー
      return s * Double.POSITIVE_INFINITY;
    }
    if (true) {
      QFP xx = new QFP (s < 0.0 ? -u : u);  //符号と仮数部
      if (0 < e) {
        xx.mul (QFP.QFP_TEN_P16QR[e & 15]);
        if (16 <= e) {
          xx.mul (QFP.QFP_TEN_P16QR[16 + (e >> 4 & 15)]);
          if (256 <= e) {
            xx.mul (QFP.QFP_TEN_P16QR[33]);
          }
        }
      } else if (e < 0) {
        xx.mul (QFP.QFP_TEN_M16QR[-e & 15]);
        if (e <= -16) {
          xx.mul (QFP.QFP_TEN_M16QR[16 + (-e >> 4 & 15)]);
          if (e <= -256) {
            xx.mul (QFP.QFP_TEN_M16QR[33]);
          }
        }
      }
      x = xx.getd ();
    } else {
      x = s * (double) u;  //符号と仮数部
      if (0 < e) {
        x *= FEFunction.FPK_TEN_P16QR[e & 15];
        if (16 <= e) {
          x *= FEFunction.FPK_TEN_P16QR[16 + (e >> 4 & 15)];
          if (256 <= e) {
            x *= FEFunction.FPK_TEN_P16QR[33];  //FEFunction.FPK_TEN_P16QR[32 + (e >> 8)]
          }
        }
      } else if (e < 0) {
        x /= FEFunction.FPK_TEN_P16QR[-e & 15];
        if (e <= -16) {
          x /= FEFunction.FPK_TEN_P16QR[16 + (-e >> 4 & 15)];
          if (e <= -256) {
            x /= FEFunction.FPK_TEN_P16QR[33];  //FEFunction.FPK_TEN_P16QR[32 + (-e >> 8)]
          }
        }
      }
    }
    if (Double.isInfinite (x)) {
      XEiJ.regRn[8] = a;  //a0
      XEiJ.regCCR = XEiJ.REG_CCR_V | XEiJ.REG_CCR_C;  //オーバーフロー
      return x;
    }
    //  アンダーフローで0になっている場合がある
    if (x == (double) ((int) x)) {  //intで表現できる。+0.0==-0.0==0なので±0.0を含む
      XEiJ.regRn[2] = 65535;  //d2。-1ではない
      XEiJ.regRn[3] = (int) x;  //d3
    } else {  //intで表現できない
      XEiJ.regRn[2] = 0;  //d2
      XEiJ.regRn[3] = 0;  //d3
    }
    XEiJ.regRn[8] = a;  //a0
    XEiJ.regCCR = 0;  //エラーなし
    return x;
  }  //fpkSTODSub()

  //fpkDTOS ()
  //  $FE23  __DTOS
  //  64bit浮動小数点数を文字列に変換する
  //  無限大は"#INF"、非数は"#NAN"になる
  //  指数形式の境目
  //    x<10^-4または10^14<=xのとき指数形式にする
  //    FLOAT2.X/FLOAT4.Xの場合
  //      3f2fffffffffff47  2.4414062499999E-004
  //      3f2fffffffffff48  0.000244140625
  //      42d6bcc41e8fffdf  99999999999999
  //      42d6bcc41e8fffe0  1E+014
  //  <d0d1.d:64bit浮動小数点数
  //  <a0.l:文字列バッファの先頭
  //  >a0.l:末尾の'\0'の位置
  public static void fpkDTOS () throws M68kException {
    fpkDTOSSub ((long) XEiJ.regRn[0] << 32 | 0xffffffffL & XEiJ.regRn[1]);  //64bit浮動小数点数
  }  //fpkDTOS()
  public static void fpkDTOSSub (long l) throws M68kException {
    final int len3 = 14;
    int a = XEiJ.regRn[8];  //文字列バッファの先頭
    //符号と指数部の処理
    //  ±0,±Inf,NaNはここで除外する
    if (l < 0L) {
      mmuWriteByteData (a++, '-', 1);  //負符号
      l &= 0x7fffffffffffffffL;  //符号bitを消しておく
    }
    double x = Double.longBitsToDouble (l);  //絶対値
    int e = (int) (l >>> 52) - 1023;  //指数部。ゲタ0。符号bitは消してあるのでマスクは不要
    l &= 0x000fffffffffffffL;  //仮数部の小数部。正規化数のとき整数部の1が付いていないことに注意
    if (e == -1023) {  //±0,非正規化数
      if (l == 0L) {  //±0
        mmuWriteByteData (a++, '0', 1);  //0
        mmuWriteByteData (a, '\0', 1);
        XEiJ.regRn[8] = a;  //末尾の'\0'の位置
        return;
      }
      e -= Long.numberOfLeadingZeros (l) - 12;  //非正規化数の指数部を補正する
    } else if (e == 1024) {  //±Inf,NaN
      mmuWriteByteData (a++, '#', 1);
      if (l == 0L) {  //±Inf
        mmuWriteByteData (a++, 'I', 1);
        mmuWriteByteData (a++, 'N', 1);
        mmuWriteByteData (a++, 'F', 1);
      } else {  //NaN
        mmuWriteByteData (a++, 'N', 1);
        mmuWriteByteData (a++, 'A', 1);
        mmuWriteByteData (a++, 'N', 1);
      }
      mmuWriteByteData (a, '\0', 1);
      XEiJ.regRn[8] = a;  //末尾の'\0'の位置
      return;
    }
    //10進数で表現したときの指数部を求める
    //  10^e<=x<10^(e+1)となるeを求める
    e = (int) Math.floor ((double) e * 0.30102999566398119521373889472);  //log10(2)
    //10^-eを掛けて1<=x<10にする
    //  非正規化数の最小値から正規化数の最大値まで処理できなければならない
    //  10^-eを計算してからまとめて掛ける方法はxが非正規化数のとき10^-eがオーバーフローしてしまうので不可
    //    doubleは非正規化数の逆数を表現できない
    if (0 < e) {  //10<=x
      x *= FEFunction.FPK_TEN_M16QR[e & 15];
      if (16 <= e) {
        x *= FEFunction.FPK_TEN_M16QR[16 + (e >> 4 & 15)];
        if (256 <= e) {
          x *= FEFunction.FPK_TEN_M16QR[33];  //FEFunction.FPK_TEN_M16QR[32 + (e >> 8)]
        }
      }
    } else if (e < 0) {  //x<1
      x *= FEFunction.FPK_TEN_P16QR[-e & 15];
      if (e <= -16) {
        x *= FEFunction.FPK_TEN_P16QR[16 + (-e >> 4 & 15)];
        if (e <= -256) {
          x *= FEFunction.FPK_TEN_P16QR[33];  //FEFunction.FPK_TEN_P16QR[32 + (-e >> 8)]
        }
      }
    }
    //整数部2桁、小数部16桁の10進数に変換する
    //  1<=x<10なのでw[1]が先頭になるはずだが誤差で前後にずれる可能性がある
    int[] w = new int[18];
    {
      int d = (int) x;
      int t = XEiJ.FMT_BCD4[d];
      w[0] = t >> 4;
      w[1] = t      & 15;
      for (int i = 2; i < 18; i += 4) {
        //xを10000倍して整数部dを引くことで小数部を残すが、このとき情報落ちが発生して誤差が蓄積する
        //Double-Doubleの乗算の要領で10000倍を正確に行い、誤差の蓄積を回避する
        //x = (x - (double) d) * 10000.0;
        double xh = x * 0x8000001p0;
        xh += x - xh;  //xの上半分
        x = (xh - (double) d) * 10000.0 + (x - xh) * 10000.0;
        d = (int) x;
        t = XEiJ.FMT_BCD4[d];
        w[i    ] = t >> 12;
        w[i + 1] = t >>  8 & 15;
        w[i + 2] = t >>  4 & 15;
        w[i + 3] = t       & 15;
      }
    }
    //先頭の位置を確認する
    //  w[h]が先頭(0でない最初の数字)の位置
    int h = w[0] != 0 ? 0 : w[1] != 0 ? 1 : 2;
    //14+1桁目を四捨五入する
    int o = h + 14;  //w[o]は四捨五入する桁の位置。w[]の範囲内
    if (5 <= w[o]) {
      int i = o;
      while (10 <= ++w[--i]) {
        w[i] = 0;
      }
      if (i < h) {  //先頭から繰り上がった。このとき新しい先頭は1でそれ以外はすべて0
        h--;  //先頭を左にずらす
        o--;  //末尾を左にずらす
      }
    }
    //先頭の位置に応じて指数部を更新する
    //  w[h]が整数部、w[h+1..o-1]が小数部。10^eの小数点はw[h]の右側。整数部の桁数はe+1桁
    e -= h - 1;
    //末尾の位置を確認する
    //  w[o-1]が末尾(0でない最後の数字)の位置
    while (w[o - 1] == 0) {  //全体は0ではないので必ず止まる。小数点よりも左側で止まる場合があることに注意
      o--;
    }
    //指数形式にするかどうか選択して文字列に変換する
    if (0 <= e && e < len3) {  //1<=x<10^len3。指数形式にしない
      do {
        mmuWriteByteData (a++, '0' + w[h++], 1);  //整数部。末尾の位置に関係なく1の位まで書く
      } while (0 <= --e);
      if (h < o) {  //小数部がある
        mmuWriteByteData (a++, '.', 1);  //小数部があるときだけ小数点を書く
        do {
          mmuWriteByteData (a++, '0' + w[h++], 1);  //小数部
        } while (h < o);
      }
    } else if (-4 <= e && e < 0) {  //10^-4<=x<1。指数形式にしない
      mmuWriteByteData (a++, '0', 1);  //整数部の0
      mmuWriteByteData (a++, '.', 1);  //小数点
      while (++e < 0) {
        mmuWriteByteData (a++, '0', 1);  //小数部の先頭の0の並び
      }
      do {
        mmuWriteByteData (a++, '0' + w[h++], 1);  //小数部
      } while (h < o);
    } else {  //x<10^-4または10^len3<=x。指数形式にする
      mmuWriteByteData (a++, '0' + w[h++], 1);  //整数部
      if (h < o) {  //小数部がある
        mmuWriteByteData (a++, '.', 1);  //小数部があるときだけ小数点を書く
        do {
          mmuWriteByteData (a++, '0' + w[h++], 1);  //小数部
        } while (h < o);
      }
      mmuWriteByteData (a++, 'E', 1);  //指数部の始まり
      if (0 <= e) {
        mmuWriteByteData (a++, '+', 1);  //指数部の正符号。省略しない
      } else {
        mmuWriteByteData (a++, '-', 1);  //指数部の負符号
        e = -e;
      }
      e = XEiJ.FMT_BCD4[e];
      mmuWriteByteData (a++, '0' + (e >> 8     ), 1);  //指数部の100の位。0でも省略しない
      mmuWriteByteData (a++, '0' + (e >> 4 & 15), 1);  //指数部の10の位
      mmuWriteByteData (a++, '0' + (e      & 15), 1);  //指数部の1の位
    }
    mmuWriteByteData (a, '\0', 1);
    XEiJ.regRn[8] = a;  //末尾の'\0'の位置
  }  //fpkDTOSSub6()

  //fpkECVT ()
  //  $FE24  __ECVT
  //  64bit浮動小数点数を全体の桁数を指定して文字列に変換する
  //  文字列に書くのは仮数部の数字のみ
  //  符号と小数点と指数部は文字列に書かず、小数点の位置と符号をレジスタに入れて返す
  //  桁数は255桁まで指定できるが、有効桁数は14桁まで
  //    有効桁数の次の桁で絶対値を四捨五入する
  //    15桁以上を指定しても14桁に丸められ、15桁目以降はすべて'0'になる
  //  無限大は"#INF"、非数は"#NAN"に変換する
  //    "#INF"と"#NAN"のとき小数点の位置は4になる
  //    "#INF"と"#NAN"で3桁以下のときは途中で打ち切る
  //    メモ
  //      FLOATn.Xは"#INF"と"#NAN"で1桁~3桁のとき文字列が"$","$0","$00"になってしまう
  //      文字数が少なすぎて"#INF"や"#NAN"が入り切らないのは仕方がないが、
  //      無意味な"$00"という文字列になるのは数字ではない文字列を四捨五入しようとするバグが原因
  //      例えば3桁のときは4桁目の'F'または'N'が'5'以上なので繰り上げて上の位をインクリメントする
  //      'N'+1='O'または'A'+1='B'が'9'よりも大きいので'0'を上書きして繰り上げて上の位をインクリメントする
  //      'I'+1='J'または'N'+1='O'も'9'よりも大きいので'0'を上書きして繰り上げて上の位をインクリメントする
  //      '#'+1='$'は'9'以下なので"$00"になる
  //      X-BASICでint i2,i3:print ecvt(val("#INF"),3,i2,i3)とすると再現できる
  //    "#INF"と"#NAN"で5桁以上のときは5桁目以降はすべて'\0'になる
  //    メモ
  //      FLOATn.Xは"#NAN"と"#INF"で15桁以上のとき5桁目から14桁目までは'\0'だが15桁目以降に'0'が書き込まれる
  //      通常は5桁目の'\0'で文字列は終了していると見なされるので実害はないが気持ち悪い
  //  メモ
  //    FLOAT2.X 2.02/2.03は0のとき小数点の位置が0になる
  //    FLOAT4.X 1.02は0のとき小数点の位置が1になる
  //    ここでは1にしている
  //  <d0d1.d:64bit浮動小数点数
  //  <d2.l:全体の桁数
  //  <a0.l:文字列バッファの先頭。末尾に'\0'を書き込むので桁数+1バイト必要
  //  >d0.l:先頭から小数点の位置までのオフセット
  //  >d1.l:符号(0=+,1=-)
  //  a0.lは変化しない
  public static void fpkECVT () throws M68kException {
    fpkECVTSub ((long) XEiJ.regRn[0] << 32 | 0xffffffffL & XEiJ.regRn[1]);  //64bit浮動小数点数
  }  //fpkECVT()
  public static void fpkECVTSub (long l) throws M68kException {
    int len3 = Math.max (0, XEiJ.regRn[2]);  //全体の桁数
    int a = XEiJ.regRn[8];  //文字列バッファの先頭
    int b = a + len3;  //文字列バッファの末尾+1。'\0'を書き込む位置
    //符号と指数部の処理
    //  ±0,±Inf,NaNはここで除外する
    if (0L <= l) {
      XEiJ.regRn[1] = 0;  //正符号
    } else {
      XEiJ.regRn[1] = 1;  //負符号
      l &= 0x7fffffffffffffffL;  //符号bitを消しておく
    }
    double x = Double.longBitsToDouble (l);  //絶対値
    int e = (int) (l >>> 52) - 1023;  //指数部。ゲタ0。符号bitは消してあるのでマスクは不要
    l &= 0x000fffffffffffffL;  //仮数部の小数部。正規化数のとき整数部の1が付いていないことに注意
    if (e == -1023) {  //±0,非正規化数
      if (l == 0L) {  //±0
        //指定された全体の桁数だけ'0'を並べる
        while (a < b) {
          mmuWriteByteData (a++, '0', 1);
        }
        mmuWriteByteData (a, '\0', 1);
        XEiJ.regRn[0] = 1;  //小数点の位置
        return;
      }
      e -= Long.numberOfLeadingZeros (l) - 12;  //非正規化数の指数部を補正する
    } else if (e == 1024) {  //±Inf,NaN
      for (int s = l != 0L ? '#' | 'N' << 8 | 'A' << 16 | 'N' << 24 : '#' | 'I' << 8 | 'N' << 16 | 'F' << 24; a < b && s != 0; s >>>= 8) {
        mmuWriteByteData (a++, s, 1);
      }
      while (a < b) {
        mmuWriteByteData (a++, '\0', 1);  //残りは'\0'
      }
      mmuWriteByteData (a, '\0', 1);
      XEiJ.regRn[0] = 4;  //小数点の位置
      return;
    }
    //10進数で表現したときの指数部を求める
    //  10^e<=x<10^(e+1)となるeを求める
    e = (int) Math.floor ((double) e * 0.30102999566398119521373889472);  //log10(2)
    //10^-eを掛けて1<=x<10にする
    //  非正規化数の最小値から正規化数の最大値まで処理できなければならない
    //  10^-eを計算してからまとめて掛ける方法はxが非正規化数のとき10^-eがオーバーフローしてしまうので不可
    //    doubleは非正規化数の逆数を表現できない
    if (0 < e) {  //10<=x
      x *= FEFunction.FPK_TEN_M16QR[e & 15];
      if (16 <= e) {
        x *= FEFunction.FPK_TEN_M16QR[16 + (e >> 4 & 15)];
        if (256 <= e) {
          x *= FEFunction.FPK_TEN_M16QR[33];  //FEFunction.FPK_TEN_M16QR[32 + (e >> 8)]
        }
      }
    } else if (e < 0) {  //x<1
      x *= FEFunction.FPK_TEN_P16QR[-e & 15];
      if (e <= -16) {
        x *= FEFunction.FPK_TEN_P16QR[16 + (-e >> 4 & 15)];
        if (e <= -256) {
          x *= FEFunction.FPK_TEN_P16QR[33];  //FEFunction.FPK_TEN_P16QR[32 + (-e >> 8)]
        }
      }
    }
    //整数部2桁、小数部16桁の10進数に変換する
    //  1<=x<10なのでw[1]が先頭になるはずだが誤差で前後にずれる可能性がある
    int[] w = new int[18];
    {
      int d = (int) x;
      int t = XEiJ.FMT_BCD4[d];
      w[0] = t >> 4;
      w[1] = t      & 15;
      for (int i = 2; i < 18; i += 4) {
        //xを10000倍して整数部dを引くことで小数部を残すが、このとき情報落ちが発生して誤差が蓄積する
        //Double-Doubleの乗算の要領で10000倍を正確に行い、誤差の蓄積を回避する
        //x = (x - (double) d) * 10000.0;
        double xh = x * 0x8000001p0;
        xh += x - xh;  //xの上半分
        x = (xh - (double) d) * 10000.0 + (x - xh) * 10000.0;
        d = (int) x;
        t = XEiJ.FMT_BCD4[d];
        w[i    ] = t >> 12;
        w[i + 1] = t >>  8 & 15;
        w[i + 2] = t >>  4 & 15;
        w[i + 3] = t       & 15;
      }
    }
    //先頭の位置を確認する
    //  w[h]が先頭(0でない最初の数字)の位置
    int h = w[0] != 0 ? 0 : w[1] != 0 ? 1 : 2;
    //14+1桁目を四捨五入する
    int o = h + 14;  //w[o]は四捨五入する桁の位置。w[]の範囲内
    if (5 <= w[o]) {
      int i = o;
      while (10 <= ++w[--i]) {
        w[i] = 0;
      }
      if (i < h) {  //先頭から繰り上がった。このとき新しい先頭は1でそれ以外はすべて0
        h--;  //先頭を左にずらす
        o--;  //末尾を左にずらす
      }
    }
    //先頭の位置に応じて指数部を更新する
    //  w[h]が整数部、w[h+1..o-1]が小数部。10^eの小数点はw[h]の右側。整数部の桁数はe+1桁
    e -= h - 1;
    //先頭からlen3+1桁目が先頭から14+1桁目よりも左側にあるときその桁で改めて四捨五入する
    //  あらかじめ14+1桁目で四捨五入しておかないと、
    //  1.5の5を四捨五入しなければならないときに誤差で1.499…になったまま4を四捨五入しようとして失敗することがある
    int s = h + len3;  //w[s]は先頭からlen3+1桁目の位置。w.length<=sの場合があることに注意
    if (s < o) {
      o = s;  //w[o]は四捨五入する桁の位置。o<0の場合があることに注意
      if (0 <= o && 5 <= w[o]) {
        int i = o;
        while (10 <= ++w[--i]) {
          w[i] = 0;
        }
        if (i < h) {  //先頭から繰り上がった。このとき新しい先頭は1でそれ以外はすべて0
          h--;  //先頭を左にずらす
          o--;  //末尾を左にずらす
          e++;  //指数部を1増やす
        }
      }
    }
    //文字列に変換する
    while (a < b && h < o) {
      mmuWriteByteData (a++, '0' + w[h++], 1);  //有効数字
    }
    while (a < b) {
      mmuWriteByteData (a++, '0', 1);  //残りは'0'
    }
    mmuWriteByteData (a, '\0', 1);
    XEiJ.regRn[0] = e + 1;  //小数点の位置
  }  //fpkECVTSub6()

  //fpkFCVT ()
  //  $FE25  __FCVT
  //  64bit浮動小数点数を小数点以下の桁数を指定して文字列に変換する
  //  メモ
  //    小数点の位置がpのとき[p]の左側に小数点がある
  //    全体の桁数が制限されないので指数部が大きいとき整数部が収まるサイズのバッファが必要
  //    0または1以上のとき
  //      整数部と小数点以下の指定された桁数までを小数部の0を省略せずに出力する
  //      整数部と小数点以下の指定された桁数が合わせて14桁を超えるときは15桁目が四捨五入されて15桁目以降は0になる
  //      小数点の位置は整数部の桁数に等しい
  //      print fcvt(0#,4,i2,i3),i2,i3
  //      0000     0       0
  //      print fcvt(2e+12/3#,4,i2,i3),i2,i3
  //      6666666666666700         12      0
  //                 ↑
  //    1未満のとき
  //      小数点以下の桁数の範囲内を先頭の0を省略して出力する
  //      小数点以下の桁数の範囲内がすべて0のときは""になる
  //      小数点の位置は指数部+1に等しい
  //      print fcvt(0.01,3,i2,i3),i2,i3                0.010
  //      10      -1       0                              <~~
  //      print fcvt(0.001,3,i2,i3),i2,i3               0.001
  //      1       -2       0                              <<~
  //      print fcvt(0.0001,3,i2,i3),i2,i3              0.0001
  //              -3       0                              <<<
  //      print fcvt(0.00001,3,i2,i3),i2,i3             0.00001
  //              -4       0                              <<<<
  //    #INFと#NAN
  //      小数点以下の桁数の指定に関係なく4文字出力して小数点の位置4を返す
  //      print fcvt(val("#INF"),2,i2,i3),i2,i3
  //      #INF     4       0
  //      print fcvt(val("#INF"),6,i2,i3),i2,i3
  //      #INF     4       0
  //  バグ
  //    FLOAT4.X 1.02は結果が整数部が大きいとき255文字で打ち切られる
  //    FLOAT4.X 1.02はFCVT(±0)の整数部が0桁ではなく1桁になる
  //  <d0d1.d:64bit浮動小数点数
  //  <d2.l:小数点以下の桁数
  //  <a0.l:文字列バッファの先頭
  //  >d0.l:先頭から小数点の位置までのオフセット
  //  >d1.l:符号(0=+,1=-)
  public static void fpkFCVT () throws M68kException {
    fpkFCVTSub ((long) XEiJ.regRn[0] << 32 | 0xffffffffL & XEiJ.regRn[1]);  //64bit浮動小数点数
  }  //fpkFCVT()
  public static void fpkFCVTSub (long l) throws M68kException {
    int len2 = Math.max (0, XEiJ.regRn[2]);  //小数部の桁数
    int a = XEiJ.regRn[8];  //文字列バッファの先頭
    //符号と指数部の処理
    //  ±0,±Inf,NaNはここで除外する
    if (0L <= l) {
      XEiJ.regRn[1] = 0;  //正符号
    } else {
      XEiJ.regRn[1] = 1;  //負符号
      l &= 0x7fffffffffffffffL;  //符号bitを消しておく
    }
    double x = Double.longBitsToDouble (l);  //絶対値
    int e = (int) (l >>> 52) - 1023;  //指数部。ゲタ0。符号bitは消してあるのでマスクは不要
    l &= 0x000fffffffffffffL;  //仮数部の小数部。正規化数のとき整数部の1が付いていないことに注意
    if (e == -1023) {  //±0,非正規化数
      if (l == 0L) {  //±0
        //指定された小数点以下の桁数だけ'0'を並べる
        while (len2-- > 0) {
          mmuWriteByteData (a++, '0', 1);
        }
        mmuWriteByteData (a, '\0', 1);
        XEiJ.regRn[0] = 0;  //小数点の位置
        return;
      }
      e -= Long.numberOfLeadingZeros (l) - 12;  //非正規化数の指数部を補正する
    } else if (e == 1024) {  //±Inf,NaN
      mmuWriteByteData (a++, '#', 1);
      if (l == 0L) {  //±Inf
        mmuWriteByteData (a++, 'I', 1);
        mmuWriteByteData (a++, 'N', 1);
        mmuWriteByteData (a++, 'F', 1);
      } else {  //NaN
        mmuWriteByteData (a++, 'N', 1);
        mmuWriteByteData (a++, 'A', 1);
        mmuWriteByteData (a++, 'N', 1);
      }
      mmuWriteByteData (a, '\0', 1);
      XEiJ.regRn[0] = 4;  //小数点の位置
      return;
    }
    //10進数で表現したときの指数部を求める
    //  10^e<=x<10^(e+1)となるeを求める
    e = (int) Math.floor ((double) e * 0.30102999566398119521373889472);  //log10(2)
    //10^-eを掛けて1<=x<10にする
    //  非正規化数の最小値から正規化数の最大値まで処理できなければならない
    //  10^-eを計算してからまとめて掛ける方法はxが非正規化数のとき10^-eがオーバーフローしてしまうので不可
    //    doubleは非正規化数の逆数を表現できない
    if (0 < e) {  //10<=x
      x *= FEFunction.FPK_TEN_M16QR[e & 15];
      if (16 <= e) {
        x *= FEFunction.FPK_TEN_M16QR[16 + (e >> 4 & 15)];
        if (256 <= e) {
          x *= FEFunction.FPK_TEN_M16QR[33];  //FEFunction.FPK_TEN_M16QR[32 + (e >> 8)]
        }
      }
    } else if (e < 0) {  //x<1
      x *= FEFunction.FPK_TEN_P16QR[-e & 15];
      if (e <= -16) {
        x *= FEFunction.FPK_TEN_P16QR[16 + (-e >> 4 & 15)];
        if (e <= -256) {
          x *= FEFunction.FPK_TEN_P16QR[33];  //FEFunction.FPK_TEN_P16QR[32 + (-e >> 8)]
        }
      }
    }
    //整数部2桁、小数部16桁の10進数に変換する
    //  1<=x<10なのでw[1]が先頭になるはずだが誤差で前後にずれる可能性がある
    int[] w = new int[18];
    {
      int d = (int) x;
      int t = XEiJ.FMT_BCD4[d];
      w[0] = t >> 4;
      w[1] = t      & 15;
      for (int i = 2; i < 18; i += 4) {
        //xを10000倍して整数部dを引くことで小数部を残すが、このとき情報落ちが発生して誤差が蓄積する
        //Double-Doubleの乗算の要領で10000倍を正確に行い、誤差の蓄積を回避する
        //x = (x - (double) d) * 10000.0;
        double xh = x * 0x8000001p0;
        xh += x - xh;  //xの上半分
        x = (xh - (double) d) * 10000.0 + (x - xh) * 10000.0;
        d = (int) x;
        t = XEiJ.FMT_BCD4[d];
        w[i    ] = t >> 12;
        w[i + 1] = t >>  8 & 15;
        w[i + 2] = t >>  4 & 15;
        w[i + 3] = t       & 15;
      }
    }
    //先頭の位置を確認する
    //  w[h]が先頭(0でない最初の数字)の位置
    int h = w[0] != 0 ? 0 : w[1] != 0 ? 1 : 2;
    //14+1桁目を四捨五入する
    int o = h + 14;  //w[o]は四捨五入する桁の位置。w[]の範囲内
    if (5 <= w[o]) {
      int i = o;
      while (10 <= ++w[--i]) {
        w[i] = 0;
      }
      if (i < h) {  //先頭から繰り上がった。このとき新しい先頭は1でそれ以外はすべて0
        h--;  //先頭を左にずらす
        o--;  //末尾を左にずらす
      }
    }
    //先頭の位置に応じて指数部を更新する
    //  w[h]が整数部、w[h+1..o-1]が小数部。10^eの小数点はw[h]の右側。整数部の桁数はe+1桁
    e -= h - 1;
    //小数点以下len2+1桁目が先頭から14+1桁目よりも左側にあるときその桁で改めて四捨五入する
    //  あらかじめ14+1桁目で四捨五入しておかないと、
    //  1.5の5を四捨五入しなければならないときに誤差で1.499…になったまま4を四捨五入しようとして失敗することがある
    int s = h + e + 1 + len2;  //w[s]は小数点以下len2+1桁目の位置。w.length<=sの場合があることに注意
    if (s < o) {
      o = s;  //w[o]は四捨五入する桁の位置。o<0の場合があることに注意
      if (0 <= o && 5 <= w[o]) {
        int i = o;
        while (10 <= ++w[--i]) {
          w[i] = 0;
        }
        if (i < h) {  //先頭から繰り上がった。このとき新しい先頭は1でそれ以外はすべて0
          h--;  //先頭を左にずらす
          o--;  //末尾を左にずらす
          e++;  //指数部を1増やす
        }
      }
    }
    //文字列に変換する
    while (h < o) {
      mmuWriteByteData (a++, '0' + w[h++], 1);  //有効数字
    }
    while (h++ < s) {
      mmuWriteByteData (a++, '0', 1);  //残りは'0'
    }
    mmuWriteByteData (a, '\0', 1);
    XEiJ.regRn[0] = e + 1;  //小数点の位置
  }  //fpkFCVTSub6()

  //fpkGCVT ()
  //  $FE26  __GCVT
  //  64bit浮動小数点数を全体の桁数を指定して文字列に変換する
  //  指定された桁数で表現できないときは指数表現になる
  //  メモ
  //    print gcvt(1e-1,10)
  //    0.1
  //    print gcvt(1e-8,10)
  //    0.00000001
  //    print gcvt(1.5e-8,10)
  //    1.5E-008
  //    print gcvt(1e-9,10)
  //    1.E-009                 小数点はあるが小数部がない
  //    print gcvt(2e-1/3#,10)
  //    6.666666667E-002
  //    print gcvt(2e+0/3#,10)
  //    0.6666666667
  //    print gcvt(2e+1/3#,10)
  //    6.666666667
  //    print gcvt(2e+9/3#,10)
  //    666666666.7
  //    print gcvt(2e+10/3#,10)
  //    6666666667
  //    print gcvt(2e+11/3#,10)
  //    6.666666667E+010
  //    print gcvt(0#,4)
  //    0.
  //    print gcvt(val("#INF"),4)
  //    #INF
  //    print gcvt(val("#INF"),3)
  //    $.E+003
  //    print gcvt(val("#INF"),2)
  //    $.E+003
  //    print gcvt(val("#INF"),1)
  //    $.E+003
  //    FLOAT2.XのGCVTは小数部がなくても桁数の範囲内であれば小数点を書く
  //    桁数ちょうどのときは小数点も指数部も付かないので、整数でないことを明確にするために小数点を書いているとも言い難い
  //    ここでは#NANと#INF以外は小数部がなくても小数点を書くことにする
  //  バグ
  //    FLOAT2.X 2.02/2.03は#NANと#INFにも小数点を付ける
  //    FLOAT2.X 2.02/2.03は#NANと#INFのとき桁数が足りないと指数形式にしようとして文字列が壊れる
  //    FLOAT4.X 1.02は#NANと#INFにも小数点を付ける
  //    FLOAT4.X 1.02は桁数の少ない整数には小数点を付けて桁数ちょうどの整数には小数点も指数部も付けない
  //  <d0d1.d:64bit浮動小数点数
  //  <d2.b:全体の桁数
  //  <a0.l:文字列バッファの先頭
  //  >a0.l:末尾の'\0'の位置
  public static void fpkGCVT () throws M68kException {
    fpkGCVTSub ((long) XEiJ.regRn[0] << 32 | 0xffffffffL & XEiJ.regRn[1]);  //64bit浮動小数点数
  }  //fpkGCVT()
  public static void fpkGCVTSub (long l) throws M68kException {
    int len3 = Math.max (0, XEiJ.regRn[2]);  //全体の桁数
    int a = XEiJ.regRn[8];  //文字列バッファの先頭
    //符号と指数部の処理
    //  ±0,±Inf,NaNはここで除外する
    if (l < 0L) {
      mmuWriteByteData (a++, '-', 1);  //負符号
      l &= 0x7fffffffffffffffL;  //符号bitを消しておく
    }
    double x = Double.longBitsToDouble (l);  //絶対値
    int e = (int) (l >>> 52) - 1023;  //指数部。ゲタ0。符号bitは消してあるのでマスクは不要
    l &= 0x000fffffffffffffL;  //仮数部の小数部。正規化数のとき整数部の1が付いていないことに注意
    if (e == -1023) {  //±0,非正規化数
      if (l == 0L) {  //±0
        mmuWriteByteData (a++, '0', 1);  //0
        mmuWriteByteData (a++, '.', 1);  //小数点
        mmuWriteByteData (a, '\0', 1);
        XEiJ.regRn[8] = a;  //末尾の'\0'の位置
        return;
      }
      e -= Long.numberOfLeadingZeros (l) - 12;  //非正規化数の指数部を補正する
    } else if (e == 1024) {  //±Inf,NaN
      mmuWriteByteData (a++, '#', 1);
      if (l == 0L) {  //±Inf
        mmuWriteByteData (a++, 'I', 1);
        mmuWriteByteData (a++, 'N', 1);
        mmuWriteByteData (a++, 'F', 1);
      } else {  //NaN
        mmuWriteByteData (a++, 'N', 1);
        mmuWriteByteData (a++, 'A', 1);
        mmuWriteByteData (a++, 'N', 1);
      }
      mmuWriteByteData (a, '\0', 1);
      XEiJ.regRn[8] = a;  //末尾の'\0'の位置
      return;
    }
    //10進数で表現したときの指数部を求める
    //  10^e<=x<10^(e+1)となるeを求める
    e = (int) Math.floor ((double) e * 0.30102999566398119521373889472);  //log10(2)
    //10^-eを掛けて1<=x<10にする
    //  非正規化数の最小値から正規化数の最大値まで処理できなければならない
    //  10^-eを計算してからまとめて掛ける方法はxが非正規化数のとき10^-eがオーバーフローしてしまうので不可
    //    doubleは非正規化数の逆数を表現できない
    if (0 < e) {  //10<=x
      x *= FEFunction.FPK_TEN_M16QR[e & 15];
      if (16 <= e) {
        x *= FEFunction.FPK_TEN_M16QR[16 + (e >> 4 & 15)];
        if (256 <= e) {
          x *= FEFunction.FPK_TEN_M16QR[33];  //FEFunction.FPK_TEN_M16QR[32 + (e >> 8)]
        }
      }
    } else if (e < 0) {  //x<1
      x *= FEFunction.FPK_TEN_P16QR[-e & 15];
      if (e <= -16) {
        x *= FEFunction.FPK_TEN_P16QR[16 + (-e >> 4 & 15)];
        if (e <= -256) {
          x *= FEFunction.FPK_TEN_P16QR[33];  //FEFunction.FPK_TEN_P16QR[32 + (-e >> 8)]
        }
      }
    }
    //整数部2桁、小数部16桁の10進数に変換する
    //  1<=x<10なのでw[1]が先頭になるはずだが誤差で前後にずれる可能性がある
    int[] w = new int[18];
    {
      int d = (int) x;
      int t = XEiJ.FMT_BCD4[d];
      w[0] = t >> 4;
      w[1] = t      & 15;
      for (int i = 2; i < 18; i += 4) {
        //xを10000倍して整数部dを引くことで小数部を残すが、このとき情報落ちが発生して誤差が蓄積する
        //Double-Doubleの乗算の要領で10000倍を正確に行い、誤差の蓄積を回避する
        //x = (x - (double) d) * 10000.0;
        double xh = x * 0x8000001p0;
        xh += x - xh;  //xの上半分
        x = (xh - (double) d) * 10000.0 + (x - xh) * 10000.0;
        d = (int) x;
        t = XEiJ.FMT_BCD4[d];
        w[i    ] = t >> 12;
        w[i + 1] = t >>  8 & 15;
        w[i + 2] = t >>  4 & 15;
        w[i + 3] = t       & 15;
      }
    }
    //先頭の位置を確認する
    //  w[h]が先頭(0でない最初の数字)の位置
    int h = w[0] != 0 ? 0 : w[1] != 0 ? 1 : 2;
    //14+1桁目を四捨五入する
    int o = h + 14;  //w[o]は四捨五入する桁の位置。w[]の範囲内
    if (5 <= w[o]) {
      int i = o;
      while (10 <= ++w[--i]) {
        w[i] = 0;
      }
      if (i < h) {  //先頭から繰り上がった。このとき新しい先頭は1でそれ以外はすべて0
        h--;  //先頭を左にずらす
        o--;  //末尾を左にずらす
      }
    }
    //先頭の位置に応じて指数部を更新する
    //  w[h]が整数部、w[h+1..o-1]が小数部。10^eの小数点はw[h]の右側。整数部の桁数はe+1桁
    e -= h - 1;
    //先頭からlen3+1桁目が先頭から14+1桁目よりも左側にあるときその桁で改めて四捨五入する
    //  あらかじめ14+1桁目で四捨五入しておかないと、
    //  1.5の5を四捨五入しなければならないときに誤差で1.499…になったまま4を四捨五入しようとして失敗することがある
    int s = h + len3;  //w[s]は先頭からlen3+1桁目の位置。w.length<=sの場合があることに注意
    if (s < o) {
      o = s;  //w[o]は四捨五入する桁の位置。o<0の場合があることに注意
      if (0 <= o && 5 <= w[o]) {
        int i = o;
        while (10 <= ++w[--i]) {
          w[i] = 0;
        }
        if (i < h) {  //先頭から繰り上がった。このとき新しい先頭は1でそれ以外はすべて0
          h--;  //先頭を左にずらす
          o--;  //末尾を左にずらす
          e++;  //指数部を1増やす
        }
      }
    }
    //末尾の位置を確認する
    //  w[o-1]が末尾(0でない最後の数字)の位置
    while (w[o - 1] == 0) {  //全体は0ではないので必ず止まる。小数点よりも左側で止まる場合があることに注意
      o--;
    }
    //指数形式にするかどうか選択して文字列に変換する
    if (0 <= e && e < len3) {  //1<=x<10^len3。指数形式にしない
      do {
        mmuWriteByteData (a++, '0' + w[h++], 1);  //整数部。末尾の位置に関係なく1の位まで書く
      } while (0 <= --e);
      mmuWriteByteData (a++, '.', 1);  //小数部がなくても小数点を書く
      while (h < o) {
        mmuWriteByteData (a++, '0' + w[h++], 1);  //小数部
      }
    } else if (-4 <= e && e < 0) {  //10^-4<=x<1。指数形式にしない
      mmuWriteByteData (a++, '0', 1);  //整数部の0
      mmuWriteByteData (a++, '.', 1);  //小数点
      while (++e < 0) {
        mmuWriteByteData (a++, '0', 1);  //小数部の先頭の0の並び
      }
      while (h < o) {
        mmuWriteByteData (a++, '0' + w[h++], 1);  //小数部
      }
    } else {  //x<10^-4または10^len3<=x。指数形式にする
      mmuWriteByteData (a++, '0' + w[h++], 1);  //整数部
      mmuWriteByteData (a++, '.', 1);  //小数部がなくても小数点を書く
      while (h < o) {
        mmuWriteByteData (a++, '0' + w[h++], 1);  //小数部
      }
      mmuWriteByteData (a++, 'E', 1);  //指数部の始まり
      if (0 <= e) {
        mmuWriteByteData (a++, '+', 1);  //指数部の正符号。省略しない
      } else {
        mmuWriteByteData (a++, '-', 1);  //指数部の負符号
        e = -e;
      }
      e = XEiJ.FMT_BCD4[e];
      mmuWriteByteData (a++, '0' + (e >> 8     ), 1);  //指数部の100の位。0でも省略しない
      mmuWriteByteData (a++, '0' + (e >> 4 & 15), 1);  //指数部の10の位
      mmuWriteByteData (a++, '0' + (e      & 15), 1);  //指数部の1の位
    }
    mmuWriteByteData (a, '\0', 1);
    XEiJ.regRn[8] = a;  //末尾の'\0'の位置
  }  //fpkGCVTSub6()

  //fpkFVAL ()
  //  $FE50  __FVAL
  //  文字列を32bit浮動小数点数に変換する
  //  __VALとほぼ同じ
  //  <a0.l:文字列の先頭
  //  >d0.s:32bit浮動小数点数
  //  >d2.l:(先頭が'&'でないとき)65535=32bit浮動小数点数をオーバーフローなしでintに変換できる,0=それ以外
  //  >d3.l:(先頭が'&'でないとき)d2.l==65535のとき32bit浮動小数点数をintに変換した値
  //  >a0.l:変換された文字列の直後('\0'とは限らない)
  //  >ccr:0=エラーなし,CCR_N|CCR_C=文法エラー,CCR_V|CCR_C=オーバーフロー
  public static void fpkFVAL () throws M68kException {
    int a = XEiJ.regRn[8];  //a0
    //先頭の空白を読み飛ばす
    int c = mmuReadByteSignData (a++, 1);
    while (c == ' ' || c == '\t') {
      c = mmuReadByteSignData (a++, 1);
    }
    if (c == '&') {  //&B,&O,&H
      c = mmuReadByteSignData (a++, 1) & 0xdf;
      XEiJ.regRn[8] = a;  //&?の直後
      if (c == 'B') {
        fpkSTOB ();
        FEFunction.fpkLTOF ();
      } else if (c == 'O') {
        fpkSTOO ();
        FEFunction.fpkLTOF ();
      } else if (c == 'H') {
        fpkSTOH ();
        FEFunction.fpkLTOF ();
      } else {
        XEiJ.regCCR = XEiJ.REG_CCR_N | XEiJ.REG_CCR_C;  //文法エラー
      }
    } else {  //&B,&O,&H以外
      FEFunction.fpkSTOF ();
    }
  }  //fpkFVAL()

  //fpkCLMUL ()
  //  $FEE0  __CLMUL
  //  32bit符号あり整数乗算
  //  <(a7).l:32bit符号あり整数。被乗数x
  //  <4(a7).l:32bit符号あり整数。乗数y
  //  >(a7).l:32bit符号あり整数。積x*y。オーバーフローのときは不定
  //  >ccr:cs=オーバーフロー。C以外は不定
  public static void fpkCLMUL () throws M68kException {
    int a7 = XEiJ.regRn[15];
    long l = (long) mmuReadLongData (a7, 1) * (long) mmuReadLongData (a7 + 4, 1);
    int h = (int) l;
    mmuWriteLongData (a7, h, 1);  //オーバーフローのときは積の下位32bit
    XEiJ.regCCR = (long) h == l ? 0 : XEiJ.REG_CCR_C;
  }  //fpkCLMUL()

  //fpkCLDIV ()
  //  $FEE1  __CLDIV
  //  32bit符号あり整数除算
  //  <(a7).l:32bit符号あり整数。被除数x
  //  <4(a7).l:32bit符号あり整数。除数y
  //  >(a7).l:32bit符号あり整数。商x/y。ゼロ除算のときは不定
  //  >ccr:cs=ゼロ除算。C以外は不定
  public static void fpkCLDIV () throws M68kException {
    int a7 = XEiJ.regRn[15];
    int h = mmuReadLongData (a7 + 4, 1);
    if (h == 0) {
      //(a7).lは変化しない
      XEiJ.regCCR = XEiJ.REG_CCR_C;
    } else {
      mmuWriteLongData (a7, mmuReadLongData (a7, 1) / h, 1);
      XEiJ.regCCR = 0;
    }
  }  //fpkCLDIV()

  //fpkCLMOD ()
  //  $FEE2  __CLMOD
  //  32bit符号あり整数剰余算
  //  <(a7).l:32bit符号あり整数。被除数x
  //  <4(a7).l:32bit符号あり整数。除数y
  //  >(a7).l:32bit符号あり整数。余りx%y。ゼロ除算のときは不定
  //  >ccr:cs=ゼロ除算。C以外は不定
  public static void fpkCLMOD () throws M68kException {
    int a7 = XEiJ.regRn[15];
    int h = mmuReadLongData (a7 + 4, 1);
    if (h == 0) {
      //(a7).lは変化しない
      XEiJ.regCCR = XEiJ.REG_CCR_C;
    } else {
      mmuWriteLongData (a7, mmuReadLongData (a7, 1) % h, 1);
      XEiJ.regCCR = 0;
    }
  }  //fpkCLMOD()

  //fpkCUMUL ()
  //  $FEE3  __CUMUL
  //  32bit符号なし整数乗算
  //  <(a7).l:32bit符号なし整数。被乗数x
  //  <4(a7).l:32bit符号なし整数。乗数y
  //  >(a7).l:32bit符号なし整数。積x*y。オーバーフローのときは不定
  //  >ccr:cs=オーバーフロー。C以外は不定
  public static void fpkCUMUL () throws M68kException {
    int a7 = XEiJ.regRn[15];
    long l = (0xffffffffL & mmuReadLongData (a7, 1)) * (0xffffffffL & mmuReadLongData (a7 + 4, 1));
    int h = (int) l;
    mmuWriteLongData (a7, h, 1);
    XEiJ.regCCR = (0xffffffffL & h) == l ? 0 : XEiJ.REG_CCR_C;
  }  //fpkCUMUL()

  //fpkCUDIV ()
  //  $FEE4  __CUDIV
  //  32bit符号なし整数除算
  //  <(a7).l:32bit符号なし整数。被除数x
  //  <4(a7).l:32bit符号なし整数。除数y
  //  >(a7).l:32bit符号なし整数。商x/y。ゼロ除算のときは不定
  //  >ccr:cs=ゼロ除算。C以外は不定
  public static void fpkCUDIV () throws M68kException {
    int a7 = XEiJ.regRn[15];
    int h = mmuReadLongData (a7 + 4, 1);
    if (h == 0) {
      //(a7).lは変化しない
      XEiJ.regCCR = XEiJ.REG_CCR_C;
    } else {
      mmuWriteLongData (a7, (int) ((0xffffffffL & mmuReadLongData (a7, 1)) / (0xffffffffL & h)), 1);
      XEiJ.regCCR = 0;
    }
  }  //fpkCUDIV()

  //fpkCUMOD ()
  //  $FEE5  __CUMOD
  //  32bit符号なし整数剰余算
  //  <(a7).l:32bit符号なし整数。被除数x
  //  <4(a7).l:32bit符号なし整数。除数y
  //  >(a7).l:32bit符号なし整数。余りx%y。ゼロ除算のときは不定
  //  >ccr:cs=ゼロ除算。C以外は不定
  public static void fpkCUMOD () throws M68kException {
    int a7 = XEiJ.regRn[15];
    int h = mmuReadLongData (a7 + 4, 1);
    if (h == 0) {
      //(a7).lは変化しない
      XEiJ.regCCR = XEiJ.REG_CCR_C;
    } else {
      mmuWriteLongData (a7, (int) ((0xffffffffL & mmuReadLongData (a7, 1)) % (0xffffffffL & h)), 1);
      XEiJ.regCCR = 0;
    }
  }  //fpkCUMOD()

  //fpkCLTOD ()
  //  $FEE6  __CLTOD
  //  32bit符号あり整数を64bit浮動小数点数に変換する
  //  <(a7).l:32bit符号あり整数。x
  //  >(a7).d:64bit浮動小数点数。(double)x
  public static void fpkCLTOD () throws M68kException {
    //int→double→[long]→[int,int]
    int a7 = XEiJ.regRn[15];
    long l = Double.doubleToLongBits ((double) mmuReadLongData (a7, 1));
    mmuWriteLongData (a7, (int) (l >>> 32), 1);
    mmuWriteLongData (a7 + 4, (int) l, 1);
  }  //fpkCLTOD()

  //fpkCDTOL ()
  //  $FEE7  __CDTOL
  //  64bit浮動小数点数を32bit符号あり整数に変換する
  //  <(a7).d:64bit浮動小数点数。x
  //  >(a7).l:32bit符号あり整数。(int)x
  //  >ccr:cs=オーバーフロー。C以外は不定
  public static void fpkCDTOL () throws M68kException {
    //[int,int]→[long]→double→int
    int a7 = XEiJ.regRn[15];
    double d = Double.longBitsToDouble ((long) mmuReadLongData (a7, 1) << 32 | 0xffffffffL & mmuReadLongData (a7 + 4, 1));
    mmuWriteLongData (a7, (int) d, 1);  //オーバーフローのときは最小値または最大値
    XEiJ.regCCR = (double) Integer.MIN_VALUE - 1.0 < d && d < (double) Integer.MAX_VALUE + 1.0 ? 0 : XEiJ.REG_CCR_C;  //NaN,±Infはエラー
  }  //fpkCDTOL()

  //fpkCLTOF ()
  //  $FEE8  __CLTOF
  //  32bit符号あり整数を32bit浮動小数点数に変換する
  //  <(a7).l:32bit符号あり整数。x
  //  >(a7).s:32bit浮動小数点数。(float)x
  public static void fpkCLTOF () throws M68kException {
    //int→float→[int]
    int a7 = XEiJ.regRn[15];
    mmuWriteLongData (a7, Float.floatToIntBits ((float) mmuReadLongData (a7, 1)), 1);
  }  //fpkCLTOF()

  //fpkCFTOL ()
  //  $FEE9  __CFTOL
  //  32bit浮動小数点数を32bit符号あり整数に変換する
  //  <(a7).s:32bit浮動小数点数。x
  //  >(a7).l:32bit符号あり整数。(int)x
  //  >ccr:cs=オーバーフロー。C以外は不定
  public static void fpkCFTOL () throws M68kException {
    //[int]→float→int
    int a7 = XEiJ.regRn[15];
    float f = Float.intBitsToFloat (mmuReadLongData (a7, 1));
    mmuWriteLongData (a7, (int) f, 1);
    XEiJ.regCCR = (float) Integer.MIN_VALUE - 1.0F < f && f < (float) Integer.MAX_VALUE + 1.0F ? 0 : XEiJ.REG_CCR_C;  //NaN,±Infはエラー
  }  //fpkCFTOL()

  //fpkCFTOD ()
  //  $FEEA  __CFTOD
  //  32bit浮動小数点数を64bit浮動小数点数に変換する
  //  <(a7).s:32bit浮動小数点数。x
  //  >(a7).d:64bit浮動小数点数。(double)x
  public static void fpkCFTOD () throws M68kException {
    //[int]→float→double→[long]→[int,int]
    int a7 = XEiJ.regRn[15];
    long l = Double.doubleToLongBits ((double) Float.intBitsToFloat (mmuReadLongData (a7, 1)));
    if (FEFunction.FPK_FPCP_NAN && l == 0x7ff8000000000000L) {
      l = 0x7fffffffffffffffL;
    }
    mmuWriteLongData (a7, (int) (l >>> 32), 1);
    mmuWriteLongData (a7 + 4, (int) l, 1);
  }  //fpkCFTOD()

  //fpkCDTOF ()
  //  $FEEB  __CDTOF
  //  64bit浮動小数点数を32bit浮動小数点数に変換する
  //  <(a7).d:64bit浮動小数点数。x
  //  >(a7).s:32bit浮動小数点数。(float)x
  //  >ccr:cs=オーバーフロー。C以外は不定
  public static void fpkCDTOF () throws M68kException {
    //[int,int]→[long]→double→float→[int]
    int a7 = XEiJ.regRn[15];
    double d = Double.longBitsToDouble ((long) mmuReadLongData (a7, 1) << 32 | 0xffffffffL & mmuReadLongData (a7 + 4, 1));
    int h = Float.floatToIntBits ((float) d);
    if (FEFunction.FPK_FPCP_NAN && h == 0x7fc00000) {
      h = 0x7fffffff;
    }
    mmuWriteLongData (a7, h, 1);
    XEiJ.regCCR = (Double.isNaN (d) || Double.isInfinite (d) ||
           Math.abs (d) < (double) Float.MAX_VALUE + 0.5 * (double) Math.ulp (Float.MAX_VALUE) ? 0 : XEiJ.REG_CCR_C);  //アンダーフローはエラーなし
  }  //fpkCDTOF()

  //fpkCDCMP ()
  //  $FEEC  __CDCMP
  //  64bit浮動小数点数の比較
  //  x<=>y
  //  <(a7).d:64bit浮動小数点数。x
  //  <8(a7).d:64bit浮動小数点数。y
  //  >ccr:lt=x<y,eq=x==y,gt=x>y
  public static void fpkCDCMP () throws M68kException {
    //([int,int]→[long]→double)<=>([int,int]→[long]→double)
    int a7 = XEiJ.regRn[15];
    double xd = Double.longBitsToDouble ((long) mmuReadLongData (a7, 1) << 32 | 0xffffffffL & mmuReadLongData (a7 + 4, 1));
    double yd = Double.longBitsToDouble ((long) mmuReadLongData (a7 + 8, 1) << 32 | 0xffffffffL & mmuReadLongData (a7 + 12, 1));
    XEiJ.regCCR = xd < yd ? XEiJ.REG_CCR_N | XEiJ.REG_CCR_C : xd == yd ? XEiJ.REG_CCR_Z : 0;  //どちらかがNaNのときは0
  }  //fpkCDCMP()

  //fpkCDADD ()
  //  $FEED  __CDADD
  //  64bit浮動小数点数の加算
  //  <(a7).d:64bit浮動小数点数。被加算数x
  //  <8(a7).d:64bit浮動小数点数。加算数y
  //  >(a7).d:64bit浮動小数点数。和x+y
  //  >ccr:0=エラーなし,CCR_C=アンダーフロー,CCR_V|CCR_C=オーバーフロー
  public static void fpkCDADD () throws M68kException {
    //([int,int]→[long]→double)+([int,int]→[long]→double)→[long]→[int,int]
    int a7 = XEiJ.regRn[15];
    double xd = Double.longBitsToDouble ((long) mmuReadLongData (a7, 1) << 32 | 0xffffffffL & mmuReadLongData (a7 + 4, 1));
    double yd = Double.longBitsToDouble ((long) mmuReadLongData (a7 + 8, 1) << 32 | 0xffffffffL & mmuReadLongData (a7 + 12, 1));
    double zd = xd + yd;
    long l = Double.doubleToLongBits (zd);
    if (FEFunction.FPK_FPCP_NAN && l == 0x7ff8000000000000L) {
      l = 0x7fffffffffffffffL;
    }
    mmuWriteLongData (a7, (int) (l >>> 32), 1);
    mmuWriteLongData (a7 + 4, (int) l, 1);
    XEiJ.regCCR = (Double.isNaN (xd) || Double.isNaN (yd) ? 0 :  //引数がNaN
           Double.isNaN (zd) ? XEiJ.REG_CCR_C :  //引数がNaNでないのに結果がNaNのときはエラー。(+Inf)+(-Inf)=NaN
           Double.isInfinite (xd) || Double.isInfinite (yd) ? 0 :  //引数が±Inf
           Double.isInfinite (zd) ? XEiJ.REG_CCR_V | XEiJ.REG_CCR_C :  //引数が±Infでないのに結果が±Infのときはオーバーフロー
           0);
  }  //fpkCDADD()

  //fpkCDSUB ()
  //  $FEEE  __CDSUB
  //  64bit浮動小数点数の減算
  //  <(a7).d:64bit浮動小数点数。被減算数x
  //  <8(a7).d:64bit浮動小数点数。減算数y
  //  >(a7).d:64bit浮動小数点数。差x-y
  //  >ccr:cs=エラー,vs=オーバーフロー
  public static void fpkCDSUB () throws M68kException {
    //([int,int]→[long]→double)-([int,int]→[long]→double)→[long]→[int,int]
    int a7 = XEiJ.regRn[15];
    double xd = Double.longBitsToDouble ((long) mmuReadLongData (a7, 1) << 32 | 0xffffffffL & mmuReadLongData (a7 + 4, 1));
    double yd = Double.longBitsToDouble ((long) mmuReadLongData (a7 + 8, 1) << 32 | 0xffffffffL & mmuReadLongData (a7 + 12, 1));
    double zd = xd - yd;
    long l = Double.doubleToLongBits (zd);
    if (FEFunction.FPK_FPCP_NAN && l == 0x7ff8000000000000L) {
      l = 0x7fffffffffffffffL;
    }
    mmuWriteLongData (a7, (int) (l >>> 32), 1);
    mmuWriteLongData (a7 + 4, (int) l, 1);
    XEiJ.regCCR = (Double.isNaN (xd) || Double.isNaN (yd) ? 0 :  //引数がNaN
           Double.isNaN (zd) ? XEiJ.REG_CCR_C :  //引数がNaNでないのに結果がNaNのときはエラー。(+Inf)-(+Inf)=NaN
           Double.isInfinite (xd) || Double.isInfinite (yd) ? 0 :  //引数が±Inf
           Double.isInfinite (zd) ? XEiJ.REG_CCR_V | XEiJ.REG_CCR_C :  //引数が±Infでないのに結果が±Infのときはオーバーフロー
           0);
  }  //fpkCDSUB()

  //fpkCDMUL ()
  //  $FEEF  __CDMUL
  //  64bit浮動小数点数の乗算
  //  <(a7).d:64bit浮動小数点数。被乗数x
  //  <8(a7).d:64bit浮動小数点数。乗数y
  //  >(a7).d:64bit浮動小数点数。積x*y
  //  >ccr:cs=エラー,vs=オーバーフロー
  public static void fpkCDMUL () throws M68kException {
    //([int,int]→[long]→double)*([int,int]→[long]→double)→[long]→[int,int]
    int a7 = XEiJ.regRn[15];
    double xd = Double.longBitsToDouble ((long) mmuReadLongData (a7, 1) << 32 | 0xffffffffL & mmuReadLongData (a7 + 4, 1));
    double yd = Double.longBitsToDouble ((long) mmuReadLongData (a7 + 8, 1) << 32 | 0xffffffffL & mmuReadLongData (a7 + 12, 1));
    double zd = xd * yd;
    long l = Double.doubleToLongBits (zd);
    if (FEFunction.FPK_FPCP_NAN && l == 0x7ff8000000000000L) {
      l = 0x7fffffffffffffffL;
    }
    mmuWriteLongData (a7, (int) (l >>> 32), 1);
    mmuWriteLongData (a7 + 4, (int) l, 1);
    XEiJ.regCCR = (Double.isNaN (xd) || Double.isNaN (yd) ? 0 :  //引数がNaN
           Double.isNaN (zd) ? XEiJ.REG_CCR_C :  //引数がNaNでないのに結果がNaNのときはエラー。(±0)*(±Inf)=NaN
           Double.isInfinite (xd) || Double.isInfinite (yd) ? 0 :  //引数が±Inf
           Double.isInfinite (zd) ? XEiJ.REG_CCR_V | XEiJ.REG_CCR_C :  //引数が±Infでないのに結果が±Infのときはオーバーフロー
           0);
  }  //fpkCDMUL()

  //fpkCDDIV ()
  //  $FEF0  __CDDIV
  //  64bit浮動小数点数の除算
  //  <(a7).d:64bit浮動小数点数。被除数x
  //  <8(a7).d:64bit浮動小数点数。除数y
  //  >(a7).d:64bit浮動小数点数。商x/y。ゼロ除算のときは不定
  //  >ccr:cs=エラー,eq=ゼロ除算,vs=オーバーフロー
  public static void fpkCDDIV () throws M68kException {
    //([int,int]→[long]→double)/([int,int]→[long]→double)→[long]→[int,int]
    int a7 = XEiJ.regRn[15];
    double xd = Double.longBitsToDouble ((long) mmuReadLongData (a7, 1) << 32 | 0xffffffffL & mmuReadLongData (a7 + 4, 1));
    double yd = Double.longBitsToDouble ((long) mmuReadLongData (a7 + 8, 1) << 32 | 0xffffffffL & mmuReadLongData (a7 + 12, 1));
    double zd = xd / yd;
    long l = Double.doubleToLongBits (zd);
    if (FEFunction.FPK_FPCP_NAN && l == 0x7ff8000000000000L) {
      l = 0x7fffffffffffffffL;
    }
    mmuWriteLongData (a7, (int) (l >>> 32), 1);
    mmuWriteLongData (a7 + 4, (int) l, 1);
    XEiJ.regCCR = (Double.isNaN (xd) || Double.isNaN (yd) ? 0 :  //引数がNaN
           Double.isNaN (zd) ? XEiJ.REG_CCR_C :  //引数がNaNでないのに結果がNaNのときはエラー。(±0)/(±0)=NaN
           Double.isInfinite (xd) || Double.isInfinite (yd) ? 0 :  //引数が±Inf。(±Inf)/(±0)=(±Inf)
           yd == 0.0 ? XEiJ.REG_CCR_Z | XEiJ.REG_CCR_C :  //除数が±0のときはゼロ除算
           Double.isInfinite (zd) ? XEiJ.REG_CCR_V | XEiJ.REG_CCR_C :  //引数が±Infでないのに結果が±Infのときはオーバーフロー
           0);
  }  //fpkCDDIV()

  //fpkCDMOD ()
  //  $FEF1  __CDMOD
  //  64bit浮動小数点数の剰余算
  //  <(a7).d:64bit浮動小数点数。被除数x
  //  <8(a7).d:64bit浮動小数点数。除数y
  //  >(a7).d:64bit浮動小数点数。余りx%y。ゼロ除算のときは不定
  //  >ccr:cs=エラー,eq=ゼロ除算
  public static void fpkCDMOD () throws M68kException {
    //([int,int]→[long]→double)%([int,int]→[long]→double)→[long]→[int,int]
    int a7 = XEiJ.regRn[15];
    double xd = Double.longBitsToDouble ((long) mmuReadLongData (a7, 1) << 32 | 0xffffffffL & mmuReadLongData (a7 + 4, 1));
    double yd = Double.longBitsToDouble ((long) mmuReadLongData (a7 + 8, 1) << 32 | 0xffffffffL & mmuReadLongData (a7 + 12, 1));
    double zd = xd % yd;
    long l = Double.doubleToLongBits (zd);
    if (FEFunction.FPK_FPCP_NAN && l == 0x7ff8000000000000L) {
      l = 0x7fffffffffffffffL;
    }
    mmuWriteLongData (a7, (int) (l >>> 32), 1);
    mmuWriteLongData (a7 + 4, (int) l, 1);
    XEiJ.regCCR = (Double.isNaN (xd) || Double.isNaN (yd) ? 0 :  //引数がNaN
           yd == 0.0 ? XEiJ.REG_CCR_Z | XEiJ.REG_CCR_C :  //除数が0のときはゼロ除算。(±Inf)%(±0)=NaN, x%(±0)=(±Inf)
           Double.isNaN (zd) ? XEiJ.REG_CCR_C :  //引数がNaNでないのに結果がNaNのときはエラー。(±Inf)%y=NaN
           Double.isInfinite (xd) || Double.isInfinite (yd) ? 0 :  //引数が±Inf
           Double.isInfinite (zd) ? XEiJ.REG_CCR_V | XEiJ.REG_CCR_C :  //引数が±Infでないのに結果が±Infのときはオーバーフロー
           0);
  }  //fpkCDMOD()

  //fpkCFCMP ()
  //  $FEF2  __CFCMP
  //  32bit浮動小数点数の比較
  //  x<=>y
  //  <(a7).s:32bit浮動小数点数。x
  //  <(a7).s:32bit浮動小数点数。y
  //  >ccr:lt=x<y,eq=x==y,gt=x>y
  public static void fpkCFCMP () throws M68kException {
    //([int]→float)<=>([int]→float)
    int a7 = XEiJ.regRn[15];
    float xf = Float.intBitsToFloat (mmuReadLongData (a7, 1));
    float yf = Float.intBitsToFloat (mmuReadLongData (a7 + 4, 1));
    XEiJ.regCCR = xf < yf ? XEiJ.REG_CCR_N | XEiJ.REG_CCR_C : xf == yf ? XEiJ.REG_CCR_Z : 0;  //どちらかがNaNのときは0
  }  //fpkCFCMP()

  //fpkCFADD ()
  //  $FEF3  __CFADD
  //  32bit浮動小数点数の加算
  //  <(a7).s:32bit浮動小数点数。被加算数x
  //  <4(a7).s:32bit浮動小数点数。加算数y
  //  >(a7).s:32bit浮動小数点数。和x+y
  //  >ccr:cs=エラー,vs=オーバーフロー
  public static void fpkCFADD () throws M68kException {
    //([int]→float)+([int]→float)→[int]
    int a7 = XEiJ.regRn[15];
    float xf = Float.intBitsToFloat (mmuReadLongData (a7, 1));
    float yf = Float.intBitsToFloat (mmuReadLongData (a7 + 4, 1));
    float zf = xf + yf;
    int h = Float.floatToIntBits (zf);
    if (FEFunction.FPK_FPCP_NAN && h == 0x7fc00000) {
      h = 0x7fffffff;
    }
    mmuWriteLongData (a7, h, 1);
    XEiJ.regCCR = (Float.isNaN (xf) || Float.isNaN (yf) ? 0 :  //引数がNaN
           Float.isNaN (zf) ? XEiJ.REG_CCR_C :  //引数がNaNでないのに結果がNaNのときはエラー。(+Inf)+(-Inf)=NaN
           Float.isInfinite (xf) || Float.isInfinite (yf) ? 0 :  //引数が±Inf
           Float.isInfinite (zf) ? XEiJ.REG_CCR_V | XEiJ.REG_CCR_C :  //引数が±Infでないのに結果が±Infのときはオーバーフロー
           0);
  }  //fpkCFADD()

  //fpkCFSUB ()
  //  $FEF4  __CFSUB
  //  32bit浮動小数点数の減算
  //  <(a7).s:32bit浮動小数点数。被減算数x
  //  <4(a7).s:32bit浮動小数点数。減算数y
  //  >(a7).s:32bit浮動小数点数。差x-y
  //  >ccr:cs=エラー,vs=オーバーフロー
  public static void fpkCFSUB () throws M68kException {
    //([int]→float)-([int]→float)→[int]
    int a7 = XEiJ.regRn[15];
    float xf = Float.intBitsToFloat (mmuReadLongData (a7, 1));
    float yf = Float.intBitsToFloat (mmuReadLongData (a7 + 4, 1));
    float zf = xf - yf;
    int h = Float.floatToIntBits (zf);
    if (FEFunction.FPK_FPCP_NAN && h == 0x7fc00000) {
      h = 0x7fffffff;
    }
    mmuWriteLongData (a7, h, 1);
    XEiJ.regCCR = (Float.isNaN (xf) || Float.isNaN (yf) ? 0 :  //引数がNaN
           Float.isNaN (zf) ? XEiJ.REG_CCR_C :  //引数がNaNでないのに結果がNaNのときはエラー。(+Inf)-(+Inf)=NaN
           Float.isInfinite (xf) || Float.isInfinite (yf) ? 0 :  //引数が±Inf
           Float.isInfinite (zf) ? XEiJ.REG_CCR_V | XEiJ.REG_CCR_C :  //引数が±Infでないのに結果が±Infのときはオーバーフロー
           0);
  }  //fpkCFSUB()

  //fpkCFMUL ()
  //  $FEF5  __CFMUL
  //  32bit浮動小数点数の乗算
  //  <(a7).s:32bit浮動小数点数。被乗数x
  //  <4(a7).s:32bit浮動小数点数。乗数y
  //  >(a7).s:32bit浮動小数点数。積x*y
  //  >ccr:0=エラーなし,CCR_C=アンダーフロー,CCR_V|CCR_C=オーバーフロー
  public static void fpkCFMUL () throws M68kException {
    //([int]→float)*([int]→float)→[int]
    int a7 = XEiJ.regRn[15];
    float xf = Float.intBitsToFloat (mmuReadLongData (a7, 1));
    float yf = Float.intBitsToFloat (mmuReadLongData (a7 + 4, 1));
    float zf = xf * yf;
    int h = Float.floatToIntBits (zf);
    if (FEFunction.FPK_FPCP_NAN && h == 0x7fc00000) {
      h = 0x7fffffff;
    }
    mmuWriteLongData (a7, h, 1);
    XEiJ.regCCR = (Float.isNaN (xf) || Float.isNaN (yf) ? 0 :  //引数がNaN
           Float.isNaN (zf) ? XEiJ.REG_CCR_C :  //引数がNaNでないのに結果がNaNのときはエラー。(±0)*(±Inf)=NaN
           Float.isInfinite (xf) || Float.isInfinite (yf) ? 0 :  //引数が±Inf
           Float.isInfinite (zf) ? XEiJ.REG_CCR_V | XEiJ.REG_CCR_C :  //引数が±Infでないのに結果が±Infのときはオーバーフロー
           0);
  }  //fpkCFMUL()

  //fpkCFDIV ()
  //  $FEF6  __CFDIV
  //  32bit浮動小数点数の除算
  //  <(a7).s:32bit浮動小数点数。被除数x
  //  <4(a7).s:32bit浮動小数点数。除数y
  //  >(a7).s:32bit浮動小数点数。商x/y。ゼロ除算のときは不定
  //  >ccr:cs=エラー,eq=ゼロ除算,vs=オーバーフロー
  public static void fpkCFDIV () throws M68kException {
    //([int]→float)/([int]→float)→[int]
    int a7 = XEiJ.regRn[15];
    float xf = Float.intBitsToFloat (mmuReadLongData (a7, 1));
    float yf = Float.intBitsToFloat (mmuReadLongData (a7 + 4, 1));
    float zf = xf / yf;
    int h = Float.floatToIntBits (zf);
    if (FEFunction.FPK_FPCP_NAN && h == 0x7fc00000) {
      h = 0x7fffffff;
    }
    mmuWriteLongData (a7, h, 1);
    XEiJ.regCCR = (Float.isNaN (xf) || Float.isNaN (yf) ? 0 :  //引数がNaN
           Float.isNaN (zf) ? XEiJ.REG_CCR_C :  //引数がNaNでないのに結果がNaNのときはエラー。(±0)/(±0)=NaN
           Float.isInfinite (xf) || Float.isInfinite (yf) ? 0 :  //引数が±Inf。(±Inf)/(±0)=(±Inf)
           yf == 0.0F ? XEiJ.REG_CCR_Z | XEiJ.REG_CCR_C :  //除数が±0のときはゼロ除算
           Float.isInfinite (zf) ? XEiJ.REG_CCR_V | XEiJ.REG_CCR_C :  //引数が±Infでないのに結果が±Infのときはオーバーフロー
           0);
  }  //fpkCFDIV()

  //fpkCFMOD ()
  //  $FEF7  __CFMOD
  //  32bit浮動小数点数の剰余算
  //  <(a7).s:32bit浮動小数点数。被除数x
  //  <4(a7).s:32bit浮動小数点数。除数y
  //  >(a7).s:32bit浮動小数点数。余りx%y。ゼロ除算のときは不定
  //  >ccr:cs=エラー,eq=ゼロ除算
  public static void fpkCFMOD () throws M68kException {
    //([int]→float)%([int]→float)→[int]
    int a7 = XEiJ.regRn[15];
    float xf = Float.intBitsToFloat (mmuReadLongData (a7, 1));
    float yf = Float.intBitsToFloat (mmuReadLongData (a7 + 4, 1));
    float zf = xf % yf;
    int h = Float.floatToIntBits (zf);
    if (FEFunction.FPK_FPCP_NAN && h == 0x7fc00000) {
      h = 0x7fffffff;
    }
    mmuWriteLongData (a7, h, 1);
    XEiJ.regCCR = (Float.isNaN (xf) || Float.isNaN (yf) ? 0 :  //引数がNaN
           yf == 0.0F ? XEiJ.REG_CCR_Z | XEiJ.REG_CCR_C :  //除数が0のときはゼロ除算。(±Inf)%(±0)=NaN, x%(±0)=(±Inf)
           Float.isNaN (zf) ? XEiJ.REG_CCR_C :  //引数がNaNでないのに結果がNaNのときはエラー。(±Inf)%y=NaN
           Float.isInfinite (xf) || Float.isInfinite (yf) ? 0 :  //引数が±Inf
           Float.isInfinite (zf) ? XEiJ.REG_CCR_V | XEiJ.REG_CCR_C :  //引数が±Infでないのに結果が±Infのときはオーバーフロー
           0);
  }  //fpkCFMOD()

  //fpkCDTST ()
  //  $FEF8  __CDTST
  //  64bit浮動小数点数と0の比較
  //  x<=>0
  //  <(a7).d:64bit浮動小数点数。x
  //  >ccr:lt=x<0,eq=x==0,gt=x>0
  public static void fpkCDTST () throws M68kException {
    if (true) {
      int a7 = XEiJ.regRn[15];
      long l = (long) mmuReadLongData (a7, 1) << 32 | 0xffffffffL & mmuReadLongData (a7 + 4, 1);
      XEiJ.regCCR = l << 1 == 0L ? XEiJ.REG_CCR_Z : 0L <= l ? 0 : XEiJ.REG_CCR_N;  //NaNのときは0
    } else {
      //[int,int]→[long]→double
      int a7 = XEiJ.regRn[15];
      double d = Double.longBitsToDouble ((long) mmuReadLongData (a7, 1) << 32 | 0xffffffffL & mmuReadLongData (a7 + 4, 1));
      XEiJ.regCCR = d < 0.0 ? XEiJ.REG_CCR_N : d == 0.0 ? XEiJ.REG_CCR_Z : 0;  //NaNのときは0
    }
  }  //fpkCDTST()

  //fpkCFTST ()
  //  $FEF9  __CFTST
  //  32bit浮動小数点数と0の比較
  //  x<=>0
  //  <(a7).s:32bit浮動小数点数。x
  //  >ccr:lt=x<0,eq=x==0,gt=x>0
  public static void fpkCFTST () throws M68kException {
    //[int]→float
    if (true) {
      int h = mmuReadLongData (XEiJ.regRn[15], 1);
      XEiJ.regCCR = h << 1 == 0 ? XEiJ.REG_CCR_Z : 0 <= h ? 0 : XEiJ.REG_CCR_N;  //NaNのときは0
    } else {
      //([int]→float)<=>0
      float f = Float.intBitsToFloat (mmuReadLongData (XEiJ.regRn[15], 1));
      XEiJ.regCCR = f < 0.0F ? XEiJ.REG_CCR_N : f == 0.0F ? XEiJ.REG_CCR_Z : 0;  //NaNのときは0
    }
  }  //fpkCFTST()

  //fpkCDINC ()
  //  $FEFA  __CDINC
  //  64bit浮動小数点数に1を加える
  //  <(a7).d:64bit浮動小数点数。x
  //  >(a7).d:64bit浮動小数点数。x+1
  public static void fpkCDINC () throws M68kException {
    //([int,int]→[long]→double)+1→[long]→[int,int]
    int a7 = XEiJ.regRn[15];
    double xd = Double.longBitsToDouble ((long) mmuReadLongData (a7, 1) << 32 | 0xffffffffL & mmuReadLongData (a7 + 4, 1));
    double zd = xd + 1.0;
    long l = Double.doubleToLongBits (zd);
    if (FEFunction.FPK_FPCP_NAN && l == 0x7ff8000000000000L) {
      l = 0x7fffffffffffffffL;
    }
    mmuWriteLongData (a7, (int) (l >>> 32), 1);
    mmuWriteLongData (a7 + 4, (int) l, 1);
    XEiJ.regCCR = Double.isInfinite (zd) && !Double.isInfinite (xd) ? XEiJ.REG_CCR_V | XEiJ.REG_CCR_C : 0;  //結果が±Infだが引数が±Infでないときはオーバーフロー
  }  //fpkCDINC()

  //fpkCFINC ()
  //  $FEFB  __CFINC
  //  32bit浮動小数点数に1を加える
  //  <(a7).s:32bit浮動小数点数。x
  //  >(a7).s:32bit浮動小数点数。x+1
  public static void fpkCFINC () throws M68kException {
    //([int]→float)+1→[int]
    int a7 = XEiJ.regRn[15];
    float xf = Float.intBitsToFloat (mmuReadLongData (a7, 1));
    float zf = xf + 1.0F;
    int h = Float.floatToIntBits (zf);
    if (FEFunction.FPK_FPCP_NAN && h == 0x7fc00000) {
      h = 0x7fffffff;
    }
    mmuWriteLongData (a7, h, 1);
    XEiJ.regCCR = Double.isInfinite (zf) && !Float.isInfinite (xf) ? XEiJ.REG_CCR_V | XEiJ.REG_CCR_C : 0;  //結果が±Infだが引数が±Infでないときはオーバーフロー
  }  //fpkCFINC()

  //fpkCDDEC ()
  //  $FEFC  __CDDEC
  //  64bit浮動小数点数から1を引く
  //  <(a7).d:64bit浮動小数点数。x
  //  >(a7).d:64bit浮動小数点数。x-1
  public static void fpkCDDEC () throws M68kException {
    //([int,int]→[long]→double)-1→[long]→[int,int]
    int a7 = XEiJ.regRn[15];
    double xd = Double.longBitsToDouble ((long) mmuReadLongData (a7, 1) << 32 | 0xffffffffL & mmuReadLongData (a7 + 4, 1));
    double zd = xd - 1.0;
    long l = Double.doubleToLongBits (zd);
    if (FEFunction.FPK_FPCP_NAN && l == 0x7ff8000000000000L) {
      l = 0x7fffffffffffffffL;
    }
    mmuWriteLongData (a7, (int) (l >>> 32), 1);
    mmuWriteLongData (a7 + 4, (int) l, 1);
    XEiJ.regCCR = Double.isInfinite (zd) && !Double.isInfinite (xd) ? XEiJ.REG_CCR_V | XEiJ.REG_CCR_C : 0;  //結果が±Infだが引数が±Infでないときはオーバーフロー
  }  //fpkCDDEC()

  //fpkCFDEC ()
  //  $FEFD  __CFDEC
  //  32bit浮動小数点数から1を引く
  //  <(a7).s:32bit浮動小数点数。x
  //  >(a7).s:32bit浮動小数点数。x-1
  public static void fpkCFDEC () throws M68kException {
    //([int]→float)-1→[int]
    int a7 = XEiJ.regRn[15];
    float xf = Float.intBitsToFloat (mmuReadLongData (a7, 1));
    float zf = xf - 1.0F;
    int h = Float.floatToIntBits (zf);
    if (FEFunction.FPK_FPCP_NAN && h == 0x7fc00000) {
      h = 0x7fffffff;
    }
    mmuWriteLongData (a7, h, 1);
    XEiJ.regCCR = Double.isInfinite (zf) && !Float.isInfinite (xf) ? XEiJ.REG_CCR_V | XEiJ.REG_CCR_C : 0;  //結果が±Infだが引数が±Infでないときはオーバーフロー
  }  //fpkCFDEC()



  //========================================================================================
  //$$MMU メモリ管理ユニット

  public static final boolean MMU_DEBUG_COMMAND = false;
  public static final boolean MMU_DEBUG_TRANSLATION = false;
  public static final boolean MMU_NOT_ALLOCATE_CACHE = false;  //true=アドレス変換キャッシュをアロケートしない

  //--------------------------------------------------------------------------------
  //論理アドレスと物理アドレス
  //
  //  ページサイズが4KBの場合
  //              ┌──  7 ──┬──  7 ──┬── 6──┬─────12─────┐
  //               31          2524          1817        1211                     0
  //              ┏━━━━━━┯━━━━━━┯━━━━━┯━━━━━━━━━━━┓
  //        論理  ┃   ルート   │  ポインタ  │  ページ  │        ページ        ┃
  //      アドレス┃インデックス│インデックス インデックス       オフセット      ┃
  //              ┗━━↓━━━┷━━↓━━━┷━━↓━━┷━━━━━↓━━━━━┛
  //          ┌────┘            │            └────┐      └──────┐
  //          │    ルートテーブル    │   ポインタテーブル   │    ページテーブル  │
  //        ┌┼→┏━━━━━━━┓┌┼→┏━━━━━━━┓┌┼→┏━━━━━━━┓│
  //        ││ 0┃              ┃││ 0┃              ┃││ 0┃              ┃│
  //        ││  ┃              ┃││  ┃              ┃│└→┠───────┨│
  //        │└→┠───────┨││  ┃              ┃│    ┃    ページ    ┃│
  //      ルート  ┃    ルート    ┃│└→┠───────┨│┌─← デスクリプタ ┃│
  //     ポインタ ┃ デスクリプタ →┘    ┃   ポインタ   ┃││  ┠───────┨│
  //              ┠───────┨      ┃ デスクリプタ →┘│63┃              ┃│
  //              ┃              ┃      ┠───────┨  │  ┗━━━━━━━┛│
  //           127┃              ┃   127┃              ┃  │                    │
  //              ┗━━━━━━━┛      ┗━━━━━━━┛  │                    │
  //                                  ┌───────────┘      ┌──────┘
  //              ┏━━━━━━━━━↓━━━━━━━━━┯━━━━━↓━━━━━┓
  //        物理  ┃              物理ページ              │        ページ        ┃
  //      アドレス┃               アドレス               │      オフセット      ┃
  //              ┗━━━━━━━━━━━━━━━━━━━┷━━━━━━━━━━━┛
  //               31                                    1211                     0
  //              └─────────20─────────┴─────12─────┘
  //
  //  ページサイズが8KBの場合
  //              ┌──  7 ──┬──  7 ──┬─  5 ─┬───── 13 ─────┐
  //               31          2524          1817      1312                       0
  //              ┏━━━━━━┯━━━━━━┯━━━━┯━━━━━━━━━━━━┓
  //        論理  ┃   ルート   │  ポインタ  │ ページ │         ページ         ┃
  //      アドレス┃インデックス│インデックスインデックス       オフセット       ┃
  //              ┗━━↓━━━┷━━↓━━━┷━━↓━┷━━━━━━↓━━━━━┛
  //          ┌────┘            │            └────┐      └──────┐
  //          │    ルートテーブル    │   ポインタテーブル   │    ページテーブル  │
  //        ┌┼→┏━━━━━━━┓┌┼→┏━━━━━━━┓┌┼→┏━━━━━━━┓│
  //        ││ 0┃              ┃││ 0┃              ┃││ 0┃              ┃│
  //        ││  ┃              ┃││  ┃              ┃│└→┠───────┨│
  //        │└→┠───────┨││  ┃              ┃│    ┃    ページ    ┃│
  //      ルート  ┃    ルート    ┃│└→┠───────┨│┌─← デスクリプタ ┃│
  //     ポインタ ┃ デスクリプタ →┘    ┃   ポインタ   ┃││  ┠───────┨│
  //              ┠───────┨      ┃ デスクリプタ →┘│31┃              ┃│
  //              ┃              ┃      ┠───────┨  │  ┗━━━━━━━┛│
  //           127┃              ┃   127┃              ┃  │                    │
  //              ┗━━━━━━━┛      ┗━━━━━━━┛  │                    │
  //                                  ┌───────────┘      ┌──────┘
  //              ┏━━━━━━━━━↓━━━━━━━━┯━━━━━━↓━━━━━┓
  //        物理  ┃             物理ページ             │         ページ         ┃
  //      アドレス┃              アドレス              │       オフセット       ┃
  //              ┗━━━━━━━━━━━━━━━━━━┷━━━━━━━━━━━━┛
  //               31                                  1312                       0
  //              └──────── 19 ────────┴───── 13 ─────┘
  //
  public static final int MMU_ROOT_INDEX_BIT0       = 25;
  public static final int MMU_POINTER_INDEX_BIT0    = 18;
  public static final int MMU_PAGE_INDEX_BIT0_4KB   = 12;
  public static final int MMU_PAGE_INDEX_BIT0_8KB   = 13;
  public static final int MMU_PAGE_SIZE_4KB         = 1 << MMU_PAGE_INDEX_BIT0_4KB;
  public static final int MMU_PAGE_SIZE_8KB         = 1 << MMU_PAGE_INDEX_BIT0_8KB;
  //                                                    33222222_22221111_111111
  //                                                    10987654_32109876_54321098_76543210
  public static final int MMU_ROOT_INDEX_MASK       = 0b11111110_00000000_00000000_00000000;
  public static final int MMU_POINTER_INDEX_MASK    = 0b00000001_11111100_00000000_00000000;
  public static final int MMU_PAGE_INDEX_MASK_4KB   = 0b00000000_00000011_11110000_00000000;
  public static final int MMU_PAGE_INDEX_MASK_8KB   = 0b00000000_00000011_11100000_00000000;
  public static final int MMU_PAGE_OFFSET_MASK_4KB  = 0b00000000_00000000_00001111_11111111;
  public static final int MMU_PAGE_OFFSET_MASK_8KB  = 0b00000000_00000000_00011111_11111111;
  public static final int MMU_PAGE_ADDRESS_MASK_4KB = 0b11111111_11111111_11110000_00000000;
  public static final int MMU_PAGE_ADDRESS_MASK_8KB = 0b11111111_11111111_11100000_00000000;

  //--------------------------------------------------------------------------------
  //透過変換レジスタ
  //
  //  DTT0  データ透過変換レジスタ0
  //  DTT1  データ透過変換レジスタ1
  //  ITT0  命令透過変換レジスタ0
  //  ITT1  命令透過変換レジスタ1
  //      31  30  29  28  27  26  25  24  23  22  21  20  19  18  17  16  15  14  13  12  11  10   9   8   7   6   5   4   3   2   1   0
  //    ┏━━━━━━━━━━━━━━━┯━━━━━━━━━━━━━━━┯━┯━┯━┯━━━━━┯━┯━┯━┯━━━┯━━━┯━┯━━━┓
  //    ┃      論理アドレスベース      │      論理アドレスマスク      │ E│IS│US│     0    │U1│U0│ 0│  CM  │   0  │ W│   0  ┃
  //    ┗━━━━━━━━━━━━━━━┷━━━━━━━━━━━━━━━┷━┷━┷━┷━━━━━┷━┷━┷━┷━━━┷━━━┷━┷━━━┛
  public static final int MMU_TTR_BASE            = 255 << 24;  //x  Logical Address Base
  public static final int MMU_TTR_MASK            = 255 << 16;  //x  Logical Address Mask
  public static final int MMU_TTR_ENABLE          =   1 << 15;  //x  E   Enable
  public static final int MMU_TTR_IGNORE_FC2      =   1 << 14;  //x  IS  Ignore FC2 when matching
  public static final int MMU_TTR_USER_SUPERVISOR =   1 << 13;  //x  US  User or Supervisor when IS=0
  public static final int MMU_TTR_US_USER         =   0 << 13;  //         Match only if FC2=0 (user mode access)
  public static final int MMU_TTR_US_SUPERVISOR   =   1 << 13;  //         Match only if FC2=1 (supervisor mode access)
  public static final int MMU_TTR_CACHE_MODE      =   3 <<  5;  //x  CM  Cache Mode
  public static final int MMU_TTR_WRITE_PROTECT   =   1 <<  2;  //x  W   Write Protect
  public static int mmuDTT0;  //DTT0
  public static int mmuDTT1;  //DTT1
  public static int mmuITT0;  //ITT0
  public static int mmuITT1;  //ITT1
  //  透過変換マップ
  //    インデックス
  //      a >>> 24
  //    値
  //        bit7   W   0  ライトプロテクトなし
  //                   1  ライトプロテクトあり。ライトのときアクセスフォルト
  //      bit6-5  CM  00  ライトスルー
  //                  01  コピーバック
  //                  10  プリサイズ
  //                  11  インプリサイズ
  //        bit0   E   0  透過変換なし。他のビットも0
  //                   1  透過変換あり
  public static byte[] mmuTTUserData1;  //ユーザデータ透過変換マップ
  public static byte[] mmuTTUserCode1;  //ユーザ命令透過変換マップ
  public static byte[] mmuTTSuperData1;  //スーパーバイザデータ透過変換マップ
  public static byte[] mmuTTSuperCode1;  //スーパーバイザ命令透過変換マップ
  public static byte[] mmuTTUserData2;
  public static byte[] mmuTTUserCode2;
  public static byte[] mmuTTSuperData2;
  public static byte[] mmuTTSuperCode2;

  //d = mmuGetDTT0 ()
  //  DTT0を読む
  public static int mmuGetDTT0 () {
    return mmuDTT0;
  }  //mmuGetDTT0()

  //d = mmuGetDTT1 ()
  //  DTT1を読む
  public static int mmuGetDTT1 () {
    return mmuDTT1;
  }  //mmuGetDTT1()

  //d = mmuGetITT0 ()
  //  ITT0を読む
  public static int mmuGetITT0 () {
    return mmuITT0;
  }  //mmuGetITT0()

  //d = mmuGetITT1 ()
  //  ITT1を読む
  public static int mmuGetITT1 () {
    return mmuITT1;
  }  //mmuGetITT1()

  //mmuSetDTT0 (d)
  //  DTT0に書く
  public static void mmuSetDTT0 (int d) {
    mmuTTSetData (d, mmuDTT1);
    if (MMU_DEBUG_COMMAND) {
      System.out.printf ("%08x mmuSetDTT0(0x%08x)\n", XEiJ.regPC0, mmuDTT0);
    }
  }  //mmuSetDTT0(int)

  //mmuSetDTT1 (d)
  //  DTT1に書く
  public static void mmuSetDTT1 (int d) {
    mmuTTSetData (mmuDTT0, d);
    if (MMU_DEBUG_COMMAND) {
      System.out.printf ("%08x mmuSetDTT1(0x%08x)\n", XEiJ.regPC0, mmuDTT1);
    }
  }  //mmuSetDTT1(int)

  //mmuTTSetData (d0, d1)
  //  DTT0,DTT1に書く
  //  データ透過変換マップを更新する
  public static void mmuTTSetData (int d0, int d1) {
    mmuDTT0 = d0 & 0xffffe364;
    mmuDTT1 = d1 & 0xffffe364;
    //1と2を入れ換える
    {
      byte[] t = mmuTTUserData1;
      mmuTTUserData1 = mmuTTUserData2;
      mmuTTUserData2 = t;
      t = mmuTTSuperData1;
      mmuTTSuperData1 = mmuTTSuperData2;
      mmuTTSuperData2 = t;
    }
    //1に構築する
    //  DTT0とDTT1の両方がヒットしたときDTT0を用いるため、DTT1→DTT0の順に書き込む
    //  DTT1でライトプロテクトされていてもDTT0でライトプロテクトされていなければ書き込める
    Arrays.fill (mmuTTUserData1, (byte) 0);  //透過変換なし
    Arrays.fill (mmuTTSuperData1, (byte) 0);  //透過変換なし
    if ((short) mmuDTT1 < 0) {  //MMU_TTR_ENABLE。DTT1が有効
      int mask = ~mmuDTT1 >>> 16 & 255;
      int base = mmuDTT1 >>> 24 & mask;
      int flag = ((mmuDTT1 & MMU_TTR_WRITE_PROTECT) << (7 - 2) |
                  (mmuDTT1 & MMU_TTR_CACHE_MODE) |
                  1);
      if ((mmuDTT1 & MMU_TTR_IGNORE_FC2) != 0 ||
          (mmuDTT1 & MMU_TTR_USER_SUPERVISOR) == MMU_TTR_US_USER) {  //ユーザモードで有効
        for (int block = 0; block < 256; block++) {
          if ((block & mask) == base) {
            mmuTTUserData1[block] = (byte) flag;
          }
        }
      }
      if ((mmuDTT1 & MMU_TTR_IGNORE_FC2) != 0 ||
          (mmuDTT1 & MMU_TTR_USER_SUPERVISOR) == MMU_TTR_US_SUPERVISOR) {  //スーパーバイザモードで有効
        for (int block = 0; block < 256; block++) {
          if ((block & mask) == base) {
            mmuTTSuperData1[block] = (byte) flag;
          }
        }
      }
    }
    if ((short) mmuDTT0 < 0) {  //MMU_TTR_ENABLE。DTT0が有効
      int mask = ~mmuDTT0 >>> 16 & 255;
      int base = mmuDTT0 >>> 24 & mask;
      int flag = ((mmuDTT0 & MMU_TTR_WRITE_PROTECT) << (7 - 2) |
                  (mmuDTT0 & MMU_TTR_CACHE_MODE) |
                  1);
      if ((mmuDTT0 & MMU_TTR_IGNORE_FC2) != 0 ||
          (mmuDTT0 & MMU_TTR_USER_SUPERVISOR) == MMU_TTR_US_USER) {  //ユーザモードで有効
        for (int block = 0; block < 256; block++) {
          if ((block & mask) == base) {
            mmuTTUserData1[block] = (byte) flag;
          }
        }
      }
      if ((mmuDTT0 & MMU_TTR_IGNORE_FC2) != 0 ||
          (mmuDTT0 & MMU_TTR_USER_SUPERVISOR) == MMU_TTR_US_SUPERVISOR) {  //スーパーバイザモードで有効
        for (int block = 0; block < 256; block++) {
          if ((block & mask) == base) {
            mmuTTSuperData1[block] = (byte) flag;
          }
        }
      }
    }
    //状態が変化したブロックのアドレス変換キャッシュを無効化する
    //  本来は透過変換はアドレス変換キャッシュより優先するので無効化する必要はないが、
    //  ここでは透過変換もアドレス変換キャッシュに乗せているため無効化する必要がある
    if (!Arrays.equals (mmuTTUserData1, mmuTTUserData2)) {
      for (int i = 0; i < 4 * MMU_CACHE_WAYS * MMU_HASH_SIZE; i += 4) {
        int logicalPage = mmuUserDataCache[i];
        if (logicalPage != 1) {  //アドレス変換キャッシュが有効
          int block = logicalPage >>> 24;
          if (mmuTTUserData1[block] != mmuTTUserData2[block]) {  //透過変換の状態が変化した
            mmuUserDataCache[i] = mmuUserDataCache[i + 1] = mmuUserDataCache[i + 2] = mmuUserDataCache[i + 3] = 1;  //アドレス変換キャッシュを無効化する
          }
        }
      }
    }
    if (!Arrays.equals (mmuTTSuperData1, mmuTTSuperData2)) {
      for (int i = 0; i < 4 * MMU_CACHE_WAYS * MMU_HASH_SIZE; i += 4) {
        int logicalPage = mmuSuperDataCache[i];
        if (logicalPage != 1) {  //アドレス変換キャッシュが有効
          int block = logicalPage >>> 24;
          if (mmuTTSuperData1[block] != mmuTTSuperData2[block]) {  //透過変換の状態が変化した
            mmuSuperDataCache[i] = mmuSuperDataCache[i + 1] = mmuSuperDataCache[i + 2] = mmuSuperDataCache[i + 3] = 1;  //アドレス変換キャッシュを無効化する
          }
        }
      }
    }
  }  //mmuTTSetData(int,int)

  //mmuSetITT0 (d)
  //  ITT0に書く
  public static void mmuSetITT0 (int d) {
    mmuTTSetCode (d, mmuITT1);
    if (MMU_DEBUG_COMMAND) {
      System.out.printf ("%08x mmuSetITT0(0x%08x)\n", XEiJ.regPC0, mmuITT0);
    }
  }  //mmuSetITT0(int)

  //mmuSetITT1 (d)
  //  ITT1に書く
  public static void mmuSetITT1 (int d) {
    mmuTTSetCode (mmuITT0, d);
    if (MMU_DEBUG_COMMAND) {
      System.out.printf ("%08x mmuSetITT1(0x%08x)\n", XEiJ.regPC0, mmuITT1);
    }
  }  //mmuSetITT1(int)

  //mmuTTSetCode (d0, d1)
  //  ITT0,ITT1に書く
  //  命令透過変換マップを更新する
  public static void mmuTTSetCode (int d0, int d1) {
    mmuITT0 = d0 & 0xffffe364;
    mmuITT1 = d1 & 0xffffe364;
    //1と2を入れ換える
    {
      byte[] t = mmuTTUserCode1;
      mmuTTUserCode1 = mmuTTUserCode2;
      mmuTTUserCode2 = t;
      t = mmuTTSuperCode1;
      mmuTTSuperCode1 = mmuTTSuperCode2;
      mmuTTSuperCode2 = t;
    }
    //1に構築する
    //  ITT0とITT1の両方がヒットしたときITT0を用いるため、ITT1→ITT0の順に書き込む
    Arrays.fill (mmuTTUserCode1, (byte) 0);  //透過変換なし
    Arrays.fill (mmuTTSuperCode1, (byte) 0);  //透過変換なし
    if ((short) mmuITT1 < 0) {  //MMU_TTR_ENABLE。ITT1が有効
      int mask = ~mmuITT1 >>> 16 & 255;
      int base = mmuITT1 >>> 24 & mask;
      int flag = ((mmuITT1 & MMU_TTR_WRITE_PROTECT) << (7 - 2) |
                  (mmuITT1 & MMU_TTR_CACHE_MODE) |
                  1);
      if ((mmuITT1 & MMU_TTR_IGNORE_FC2) != 0 ||
          (mmuITT1 & MMU_TTR_USER_SUPERVISOR) == MMU_TTR_US_USER) {  //ユーザモードで有効
        for (int block = 0; block < 256; block++) {
          if ((block & mask) == base) {
            mmuTTUserCode1[block] = (byte) flag;
          }
        }
      }
      if ((mmuITT1 & MMU_TTR_IGNORE_FC2) != 0 ||
          (mmuITT1 & MMU_TTR_USER_SUPERVISOR) == MMU_TTR_US_SUPERVISOR) {  //スーパーバイザモードで有効
        for (int block = 0; block < 256; block++) {
          if ((block & mask) == base) {
            mmuTTSuperCode1[block] = (byte) flag;
          }
        }
      }
    }
    if ((short) mmuITT0 < 0) {  //MMU_TTR_ENABLE。ITT0が有効
      int mask = ~mmuITT0 >>> 16 & 255;
      int base = mmuITT0 >>> 24 & mask;
      int flag = ((mmuITT0 & MMU_TTR_WRITE_PROTECT) << (7 - 2) |
                  (mmuITT0 & MMU_TTR_CACHE_MODE) |
                  1);
      if ((mmuITT0 & MMU_TTR_IGNORE_FC2) != 0 ||
          (mmuITT0 & MMU_TTR_USER_SUPERVISOR) == MMU_TTR_US_USER) {  //ユーザモードで有効
        for (int block = 0; block < 256; block++) {
          if ((block & mask) == base) {
            mmuTTUserCode1[block] = (byte) flag;
          }
        }
      }
      if ((mmuITT0 & MMU_TTR_IGNORE_FC2) != 0 ||
          (mmuITT0 & MMU_TTR_USER_SUPERVISOR) == MMU_TTR_US_SUPERVISOR) {  //スーパーバイザモードで有効
        for (int block = 0; block < 256; block++) {
          if ((block & mask) == base) {
            mmuTTSuperCode1[block] = (byte) flag;
          }
        }
      }
    }
    //状態が変化したブロックのアドレス変換キャッシュを無効化する
    //  本来は透過変換はアドレス変換キャッシュより優先するので無効化する必要はないが、
    //  ここでは透過変換もアドレス変換キャッシュに乗せているため無効化する必要がある
    if (!Arrays.equals (mmuTTUserCode1, mmuTTUserCode2)) {
      for (int i = 0; i < 4 * MMU_CACHE_WAYS * MMU_HASH_SIZE; i += 4) {
        int logicalPage = mmuUserCodeCache[i];
        if (logicalPage != 1) {  //アドレス変換キャッシュが有効
          int block = logicalPage >>> 24;
          if (mmuTTUserCode1[block] != mmuTTUserCode2[block]) {  //透過変換の状態が変化した
            mmuUserCodeCache[i] = mmuUserCodeCache[i + 1] = mmuUserCodeCache[i + 2] = mmuUserCodeCache[i + 3] = 1;  //アドレス変換キャッシュを無効化する
          }
        }
      }
    }
    if (!Arrays.equals (mmuTTSuperCode1, mmuTTSuperCode2)) {
      for (int i = 0; i < 4 * MMU_CACHE_WAYS * MMU_HASH_SIZE; i += 4) {
        int logicalPage = mmuSuperCodeCache[i];
        if (logicalPage != 1) {  //アドレス変換キャッシュが有効
          int block = logicalPage >>> 24;
          if (mmuTTSuperCode1[block] != mmuTTSuperCode2[block]) {  //透過変換の状態が変化した
            mmuSuperCodeCache[i] = mmuSuperCodeCache[i + 1] = mmuSuperCodeCache[i + 2] = mmuSuperCodeCache[i + 3] = 1;  //アドレス変換キャッシュを無効化する
          }
        }
      }
    }
  }  //mmuTTSetCode(int,int)

  //--------------------------------------------------------------------------------
  //変換制御レジスタ
  //
  //  TCR  変換制御レジスタ
  //      31  30  29  28  27  26  25  24  23  22  21  20  19  18  17  16  15  14  13  12  11  10   9   8   7   6   5   4   3   2   1   0
  //    ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┯━┯━┯━┯━┯━┯━┯━━━┯━━━┯━┯━━━┯━━━┯━┓
  //    ┃                               0                              │ E│ P NAD NAI FOTC FITC  DCO │  DUO │DWO   DCI │  DUI │ 0┃
  //    ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┷━┷━┷━┷━┷━┷━┷━━━┷━━━┷━┷━━━┷━━━┷━┛
  public static final int MMU_TCR_ENABLE    = 1 << 15;  //x  E     Enable
  public static final int MMU_TCR_PAGE_SIZE = 1 << 14;  //x  P     Page Size
  public static final int MMU_TCR_P_4KB     = 0 << 14;  //           4KB
  public static final int MMU_TCR_P_8KB     = 1 << 14;  //           8KB
  public static final int MMU_TCR_NAD       = 1 << 13;  //x  NAD   No Allocate Mode (Data ATC)。データATCはヒットするが更新されない
  public static final int MMU_TCR_NAI       = 1 << 12;  //x  NAI   No Allocate Mode (Instruction ATC)。命令ATCはヒットするが更新されない
  public static final int MMU_TCR_FOTC      = 1 << 11;  //   FOTC  1/2-Cache Mode (Data ATC)。データATCは0=64エントリ,1=32エントリ
  public static final int MMU_TCR_FITC      = 1 << 10;  //   FITC  1/2-Cache Mode (Instruction ATC)。命令ATCは0=64エントリ,1=32エントリ
  public static final int MMU_TCR_DCO       = 3 <<  8;  //   DCO   Default Cache Mode (Data Cache)。デフォルトデータキャッシュモード
  public static final int MMU_TCR_DUO       = 3 <<  6;  //   DUO   Default UPA bits (Data Cache)。デフォルトデータUPA
  public static final int MMU_TCR_DWO       = 1 <<  5;  //   DWO   Default Write Protect (Data Cache)。デフォルトライトプロテクト
  public static final int MMU_TCR_DCI       = 3 <<  3;  //   DCI   Default Cache Mode (Instruction Cache)。デフォルト命令キャッシュモード
  public static final int MMU_TCR_DUI       = 3 <<  1;  //   DUI   Default UPA bits (Instruction Cache)。デフォルト命令UPA
  public static int mmuTCR;  //TCR
  public static boolean mmuEnabled;  //true=アドレス変換有効
  public static boolean mmu4KB;  //false=8KB,true=4KB
  public static boolean mmuNotAllocateData;  //true=データアドレス変換キャッシュをアロケートしない
  public static boolean mmuNotAllocateCode;  //true=命令アドレス変換キャッシュをアロケートしない
  public static int mmuPageSize;  //ページサイズ
  public static int mmuPageAddressMask;  //ページアドレスのマスク
  public static int mmuPageOffsetMask;  //ページオフセットのマスク
  public static int mmuPageIndexMask;  //ページインデックスのマスク
  public static int mmuPageIndexBit2;  //ページインデックスのbit番号-2
  public static int mmuPageTableMask;  //ページテーブルの先頭アドレスのマスク

  //d = mmuGetTCR ()
  //  TCRを読む
  public static int mmuGetTCR () {
    return mmuTCR;
  }  //mmuGetTCR()

  //mmuSetTCR (d)
  //  TCRに書く
  public static void mmuSetTCR (int d) {
    mmuInvalidateAllCache ();  //高速化のためアドレス変換していないときもキャッシュに乗せているので、アドレス変換を有効にしたときキャッシュを初期化する必要がある
    mmuTCR = d & 0x0000fffe;
    mmuEnabled = (short) d < 0;  //(d & MMU_TCR_ENABLE) != 0
    mmu4KB = (d & MMU_TCR_PAGE_SIZE) == MMU_TCR_P_4KB;
    mmuNotAllocateData = (d & MMU_TCR_NAD) != 0;
    mmuNotAllocateCode = (d & MMU_TCR_NAI) != 0;
    if (mmu4KB) {  //4KB
      mmuPageSize = MMU_PAGE_SIZE_4KB;
      mmuPageAddressMask = MMU_PAGE_ADDRESS_MASK_4KB;
      mmuPageOffsetMask = MMU_PAGE_OFFSET_MASK_4KB;
      mmuPageIndexMask = MMU_PAGE_INDEX_MASK_4KB;
      mmuPageIndexBit2 = MMU_PAGE_INDEX_BIT0_4KB - 2;
      mmuPageTableMask = MMU_DESCRIPTOR_PAGE_TABLE_ADDRESS_4KB;
    } else {  //8KB
      mmuPageSize = MMU_PAGE_SIZE_8KB;
      mmuPageAddressMask = MMU_PAGE_ADDRESS_MASK_8KB;
      mmuPageOffsetMask = MMU_PAGE_OFFSET_MASK_8KB;
      mmuPageIndexMask = MMU_PAGE_INDEX_MASK_8KB;
      mmuPageIndexBit2 = MMU_PAGE_INDEX_BIT0_8KB - 2;
      mmuPageTableMask = MMU_DESCRIPTOR_PAGE_TABLE_ADDRESS_8KB;
    }
    if (MMU_DEBUG_COMMAND) {
      System.out.printf ("%08x mmuSetTCR(0x%08x)\n", XEiJ.regPC0, mmuTCR);
      System.out.printf ("  mmuEnabled=%b\n", mmuEnabled);
      System.out.printf ("  mmu4KB=%b\n", mmu4KB);
      System.out.printf ("  mmuPageSize=0x%08x\n", mmuPageSize);
      System.out.printf ("  mmuPageAddressMask=0x%08x\n", mmuPageAddressMask);
      System.out.printf ("  mmuPageOffsetMask=0x%08x\n", mmuPageOffsetMask);
      System.out.printf ("  mmuPageIndexMask=0x%08x\n", mmuPageIndexMask);
      System.out.printf ("  mmuPageIndexBit2=%d\n", mmuPageIndexBit2);
      System.out.printf ("  mmuPageTableMask=%d\n", mmuPageTableMask);
    }
  }  //mmuSetTCR(int)

  //--------------------------------------------------------------------------------
  //アドレス変換テーブル

  //  URP  ユーザルートポインタ
  //  SRP  スーパーバイザルートポインタ
  //      31  30  29  28  27  26  25  24  23  22  21  20  19  18  17  16  15  14  13  12  11  10   9   8   7   6   5   4   3   2   1   0
  //    ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┯━━━━━━━━━━━━━━━━━┓
  //    ┃                                  ルートテーブルアドレス                                  │                 0                ┃
  //    ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┷━━━━━━━━━━━━━━━━━┛
  public static int mmuURP;  //URP
  public static int mmuSRP;  //SRP

  //d = mmuGetURP ()
  //  URPを読む
  public static int mmuGetURP () {
    return mmuURP;
  }  //mmuGetURP()

  //d = mmuGetSRP ()
  //  SRPを読む
  public static int mmuGetSRP () {
    return mmuSRP;
  }  //mmuGetSRP()

  //mmuSetURP (d)
  //  URPに書く
  public static void mmuSetURP (int d) throws M68kException {
    mmuURP = d &= 0xfffffe00;
    Arrays.fill (mmuUserDataCache, 1);
    Arrays.fill (mmuUserCodeCache, 1);
    if (MMU_DEBUG_COMMAND) {
      System.out.printf ("%08x mmuSetURP(0x%08x)\n", XEiJ.regPC0, mmuURP);
    }
    if (RootPointerList.RTL_ON) {
      RootPointerList.rtlSetRootPointer (d, false);
    }
  }  //mmuSetURP(int)

  //mmuSetSRP (d)
  //  SRPに書く
  public static void mmuSetSRP (int d) {
    mmuSRP = d &= 0xfffffe00;
    Arrays.fill (mmuSuperDataCache, 1);
    Arrays.fill (mmuSuperCodeCache, 1);
    if (MMU_DEBUG_COMMAND) {
      System.out.printf ("%08x mmuSetSRP(0x%08x)\n", XEiJ.regPC0, mmuSRP);
    }
    if (RootPointerList.RTL_ON) {
      RootPointerList.rtlSetRootPointer (d, true);
    }
  }  //mmuSetSRP(int)

  //  デスクリプタ
  //
  //    ルートテーブルデスクリプタ
  //      31  30  29  28  27  26  25  24  23  22  21  20  19  18  17  16  15  14  13  12  11  10   9   8   7   6   5   4   3   2   1   0
  //    ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┯━━━━━━━━━┯━┯━┯━━━┓
  //    ┃                                 ポインタテーブルアドレス                                 │         X        │ U│ W│  UDT ┃
  //    ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┷━━━━━━━━━┷━┷━┷━━━┛
  //
  //    4KBポインタテーブルデスクリプタ
  //      31  30  29  28  27  26  25  24  23  22  21  20  19  18  17  16  15  14  13  12  11  10   9   8   7   6   5   4   3   2   1   0
  //    ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┯━━━┯━┯━┯━━━┓
  //    ┃                                        ページテーブルアドレス                                        │   X  │ U│ W│  UDT ┃
  //    ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┷━━━┷━┷━┷━━━┛
  //
  //    8KBポインタテーブルデスクリプタ
  //      31  30  29  28  27  26  25  24  23  22  21  20  19  18  17  16  15  14  13  12  11  10   9   8   7   6   5   4   3   2   1   0
  //    ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┯━┯━┯━┯━━━┓
  //    ┃                                          ページテーブルアドレス                                          │ X│ U│ W│  UDT ┃
  //    ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┷━┷━┷━┷━━━┛
  //
  //    4KBページテーブルデスクリプタ
  //      31  30  29  28  27  26  25  24  23  22  21  20  19  18  17  16  15  14  13  12  11  10   9   8   7   6   5   4   3   2   1   0
  //    ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┯━┯━┯━┯━┯━┯━━━┯━┯━┯━┯━━━┓
  //    ┃                              物理ページアドレス                              │UR│ G│U1│U0│ S│  CM  │ M│ U│ W│  PDT ┃
  //    ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┷━┷━┷━┷━┷━┷━━━┷━┷━┷━┷━━━┛
  //
  //    8KBページテーブルデスクリプタ
  //      31  30  29  28  27  26  25  24  23  22  21  20  19  18  17  16  15  14  13  12  11  10   9   8   7   6   5   4   3   2   1   0
  //    ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┯━┯━┯━┯━┯━┯━┯━━━┯━┯━┯━┯━━━┓
  //    ┃                            物理ページアドレス                            │UR│UR│ G│U1│U0│ S│  CM  │ M│ U│ W│  PDT ┃
  //    ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┷━┷━┷━┷━┷━┷━┷━━━┷━┷━┷━┷━━━┛
  //
  //    間接ページテーブルデスクリプタ
  //      31  30  29  28  27  26  25  24  23  22  21  20  19  18  17  16  15  14  13  12  11  10   9   8   7   6   5   4   3   2   1   0
  //    ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┯━━━┓
  //    ┃                                              ページデスクリプタアドレス                                              │  PDT ┃
  //    ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┷━━━┛
  public static final int MMU_DESCRIPTOR_POINTER_TABLE_ADDRESS  = -1 <<  9;  //x  Pointer Table Address
  public static final int MMU_DESCRIPTOR_PAGE_TABLE_ADDRESS_4KB = -1 <<  6;  //x  Page Table Address (4KB)
  public static final int MMU_DESCRIPTOR_PAGE_TABLE_ADDRESS_8KB = -1 <<  5;  //x  Page Table Address (8KB)
  public static final int MMU_DESCRIPTOR_GLOBAL                 =  1 << 10;  //x  G    Global
  public static final int MMU_DESCRIPTOR_SUPERVISOR_PROTECTED   =  1 <<  7;  //x  S    Supervisor Protected
  public static final int MMU_DESCRIPTOR_CACHE_MODE             =  3 <<  5;  //x  CM   Cache Mode
  public static final int MMU_DESCRIPTOR_MODIFIED               =  1 <<  4;  //x  M    Modified
  public static final int MMU_DESCRIPTOR_USED                   =  1 <<  3;  //x  U    Used
  public static final int MMU_DESCRIPTOR_WRITE_PROTECTED        =  1 <<  2;  //x  W    Write Protected
  public static final int MMU_DESCRIPTOR_UDT                    =  2 <<  0;  //x  UDT  Upper Level Descriptor Type
  public static final int MMU_DESCRIPTOR_PDT                    =  3 <<  0;  //x  PDT  Page Descriptor Type
  public static final int MMU_DESCRIPTOR_TYPE_INVALID           =  0 <<  0;  //          Invalid
  public static final int MMU_DESCRIPTOR_TYPE_INDIRECT          =  2 <<  0;  //          Indirect
  public static final int MMU_DESCRIPTOR_INDIRECT_ADDRESS       = -1 <<  2;  //x  Descriptor Address

  //--------------------------------------------------------------------------------
  //アドレス変換キャッシュ
  //
  //  構造
  //    ユーザモード
  //      ライン0
  //        エントリ0
  //          [0]  論理ページアドレス。リード用。1=無効
  //          [1]  論理ページアドレス。ライト用。修正済みかつライトプロテクトされていないときだけ有効。1=無効
  //          [2]  物理ページアドレス。1=無効
  //          [3]  フラグ。bit10:グローバル,bit6-5:キャッシュモード,bit0:無効
  //        エントリ1
  //        エントリ2
  //        エントリ3
  //      ライン1
  //          :
  //      ライン63
  //    スーパーバイザモード
  //      ライン0
  //        エントリ0
  //          [0]  論理ページアドレス。リード用。1=無効
  //          [1]  論理ページアドレス。ライト用。修正済みかつライトプロテクトされていないときだけ有効。1=無効
  //          [2]  物理ページアドレス。1=無効
  //          [3]  フラグ。bit10:グローバル,bit6-5:キャッシュモード,bit0:無効
  //        エントリ1
  //        エントリ2
  //        エントリ3
  //      ライン1
  //          :
  //      ライン63
  //
  //  ハッシュ関数
  //    次の関数で32bitの論理ページアドレスを6bitのライン番号に変換する
  //      a * 0x5efc103f >>> 26
  //    32bitの中に幅6bit以内で6bitまでセットする組み合わせは1+1+2+4+8+16+32*27=896通りあるが、
  //    それらをa*x>>>26で0~63になるべく均一に分散させる係数を2^32通りの中から探して以下の24個を得た
  //      0x5efbf041  0x5efc0fc1  0x5efc103f  0x5f03efc1  0x5f03f03f  0x5f040fbf
  //      0x60fbf041  0x60fc0fc1  0x60fc103f  0x6103efc1  0x6103f03f  0x61040fbf
  //      0x9efbf041  0x9efc0fc1  0x9efc103f  0x9f03efc1  0x9f03f03f  0x9f040fbf
  //      0xa0fbf041  0xa0fc0fc1  0xa0fc103f  0xa103efc1  0xa103f03f  0xa1040fbf
  //    この中で(0..63)<<12と(0..63)<<13がそれぞれすべて分離するのは
  //      0x5efc103f
  //      0x60fc103f
  //      0x9efc103f
  //      0xa0fc103f
  //    この4個はほぼ同じパターンなので0x5efc103fを係数として用いることにする
  //      perl -e "for$x(0x5efc103f){printf'  //        0x%x%c',$x,10;for$b(7..15){@c=(0)x64;for$n(0..63){$a=$n<<$b;$c[$a*$x>>26&63]++;}printf'  //        %2d %s%c',$b,join('',@c),10;}}"
  //      0x5efc103f
  //       7 2111111111111111111111111111111101111111111111111111111111111111
  //       8 1111111111111111111111111111111111111111111111111111111111111111
  //       9 1111111111111111111111111111111111111111111111111111111111111111
  //      10 1111111111111111111111111111111111111111111111111111111111111111
  //      11 1111111111111111111111111111111111111111111111111111111111111111
  //      12 1111111111111111111111111111111111111111111111111111111111111111
  //      13 1111111111111111111111111111111111111111111111111111111111111111
  //      14 1111111111111111111111111111111111111111111111111111111111111111
  //      15 2011111111111111111111111111111111111111111111111111111111111111
  //    ページサイズが2^8=256バイトから2^14=16384バイトまで、それぞれ先頭の64ページがすべて異なるハッシュ値を持つことがわかる
  //
  //  1wayセットアソシアティブ
  //    ハッシュ値が衝突したときの速度低下を抑えるため4waysにしてみたが効果がなさそうなので1wayに戻してある
  //    ハッシュ関数を工夫してあるので4waysにしてもほとんどの場合は1番目でヒットするか4番目まですべてミスするかのどちらかになる
  //    1wayを4waysにするとミスしたときの条件分岐が1回から4回に増えてテーブルサーチの開始が遅れる
  //    2ways以上では参照するときに1番目に比較するエントリとアロケートするときに押し出すエントリを適切に選択するための仕組みが必要
  //
  //  LRU(least recently used)方式(2ways以上の場合)
  //    アロケートはラインの中で最も古いエントリを切り捨てて最も新しいエントリを追加する方法で行う
  //    アドレス変換キャッシュは最も新しいエントリが繰り返しアクセスされる場合が多く、ハッシュ関数で十分に分散させられているので、
  //    ここではエントリを常に新しい順にソートしておく方法を用いる
  //    2番目以降のエントリがヒットしたときエントリを並べ替えなければならないので遅くなるが、1番目のヒット率が十分に高ければ問題ない
  //
  //  グローバル
  //    関連する命令
  //      PFLUSHA       アドレス変換キャッシュのすべてのエントリを無効化する
  //      PFLUSHAN      アドレス変換キャッシュのNonGlobalなエントリを無効化する
  //      PFLUSH (An)   アドレス変換キャッシュの、DFC=1またはDFC=2ならばユーザモード、DFC=5またはDFC=6ならばスーパーバイザモードの、
  //                    論理ページアドレスがAnのエントリを無効化する
  //      PFLUSHN (An)  アドレス変換キャッシュの、DFC=1またはDFC=2ならばユーザモード、DFC=5またはDFC=6ならばスーパーバイザモードの、
  //                    論理ページアドレスがAnかつNonGlobalのエントリを無効化する
  //    グローバルはこれらの命令の動作を変更する以外の機能を持たない
  //
  //  キャッシュモード
  //
  public static final int MMU_HASH_BITS = 6;
  public static final int MMU_HASH_SIZE = 1 << MMU_HASH_BITS;
  public static final int MMU_HASH_COEFF = 0x5efc103f;  //ハッシュ関数の係数
  public static final int MMU_CACHE_WAYS = 1;  //1=1way,4=4waysセットアソシアティブ
  public static final int[] mmuUserDataCache = new int[4 * MMU_CACHE_WAYS * MMU_HASH_SIZE];
  public static final int[] mmuUserCodeCache = new int[4 * MMU_CACHE_WAYS * MMU_HASH_SIZE];
  public static final int[] mmuSuperDataCache = new int[4 * MMU_CACHE_WAYS * MMU_HASH_SIZE];
  public static final int[] mmuSuperCodeCache = new int[4 * MMU_CACHE_WAYS * MMU_HASH_SIZE];

  //mmuInvalidateAllCache ()
  //  PFLUSHA
  //  アドレス変換キャッシュのすべてのエントリを無効化する
  public static void mmuInvalidateAllCache () {
    Arrays.fill (mmuUserDataCache, 1);
    Arrays.fill (mmuUserCodeCache, 1);
    Arrays.fill (mmuSuperDataCache, 1);
    Arrays.fill (mmuSuperCodeCache, 1);
  }  //mmuInvalidateAllCache()

  //mmuInvalidateAllNonGlobalCache ()
  //  PFLUSHAN
  //  アドレス変換キャッシュのNonGlobalなエントリを無効化する
  public static void mmuInvalidateAllNonGlobalCache () {
    for (int i = 0; i < 4 * MMU_CACHE_WAYS * MMU_HASH_SIZE; i += 4) {
      if ((mmuUserDataCache[i + 3] & (MMU_DESCRIPTOR_GLOBAL | 1)) == 0) {  //エントリが有効かつNonGlobal
        mmuUserDataCache[i] = mmuUserDataCache[i + 1] = mmuUserDataCache[i + 2] = mmuUserDataCache[i + 3] = 1;
      }
      if ((mmuUserCodeCache[i + 3] & (MMU_DESCRIPTOR_GLOBAL | 1)) == 0) {  //エントリが有効かつNonGlobal
        mmuUserCodeCache[i] = mmuUserCodeCache[i + 1] = mmuUserCodeCache[i + 2] = mmuUserCodeCache[i + 3] = 1;
      }
      if ((mmuSuperDataCache[i + 3] & (MMU_DESCRIPTOR_GLOBAL | 1)) == 0) {  //エントリが有効かつNonGlobal
        mmuSuperDataCache[i] = mmuSuperDataCache[i + 1] = mmuSuperDataCache[i + 2] = mmuSuperDataCache[i + 3] = 1;
      }
      if ((mmuSuperCodeCache[i + 3] & (MMU_DESCRIPTOR_GLOBAL | 1)) == 0) {  //エントリが有効かつNonGlobal
        mmuSuperCodeCache[i] = mmuSuperCodeCache[i + 1] = mmuSuperCodeCache[i + 2] = mmuSuperCodeCache[i + 3] = 1;
      }
    }
  }  //mmuInvalidateAllNonGlobalCache()

  //mmuInvalidateCache (a)
  //  PFLUSH (An)
  //  アドレス変換キャッシュの、DFC=1またはDFC=2ならばユーザモード、DFC=5またはDFC=6ならばスーパーバイザモードの、
  //  論理ページアドレスがAnのエントリを無効化する
  public static void mmuInvalidateCache (int a) {
    int logicalPage = a & mmuPageAddressMask;
    boolean supervisor = (0b10011111 << 24 << XEiJ.mpuDFC) < 0;
    boolean instruction = (0b00101010 << 24 << XEiJ.mpuDFC) < 0;
    int[] cache = (supervisor ?
                   instruction ? mmuSuperCodeCache : mmuSuperDataCache :
                   instruction ? mmuUserCodeCache : mmuUserDataCache);
    int head = (logicalPage * MMU_HASH_COEFF >>> -MMU_HASH_BITS) * (4 * MMU_CACHE_WAYS);  //先頭のエントリ
    if (MMU_CACHE_WAYS == 1) {  //1way
      if (cache[head] == logicalPage) {  //エントリが有効かつ論理ページアドレスがAn
        cache[head] = cache[head + 1] = cache[head + 2] = cache[head + 3] = 1;  //末尾を空ける
        return;
      }
    } else {  //2ways以上
      int tail = head + (4 * MMU_CACHE_WAYS - 4);  //末尾のエントリ
      for (int i = head; i <= tail; i += 4) {
        if (cache[i] == logicalPage) {  //エントリが有効かつ論理ページアドレスがAn
          for (int j = i; j < tail; j += 4) {  //後ろを詰める
            cache[j    ] = cache[j + 4];
            cache[j + 1] = cache[j + 5];
            cache[j + 2] = cache[j + 6];
            cache[j + 3] = cache[j + 7];
          }
          cache[tail] = cache[tail + 1] = cache[tail + 2] = cache[tail + 3] = 1;  //末尾を空ける
          return;
        }
      }
    }
  }  //mmuInvalidateCache(int)

  //mmuInvalidateNonGlobalCache (a)
  //  PFLUSHN (An)
  //  アドレス変換キャッシュの、DFC=1またはDFC=2ならばユーザモード、DFC=5またはDFC=6ならばスーパーバイザモードの、
  //  論理ページアドレスがAnかつNonGlobalのエントリを無効化する
  public static void mmuInvalidateNonGlobalCache (int a) {
    int logicalPage = a & mmuPageAddressMask;
    boolean supervisor = (0b10011111 << 24 << XEiJ.mpuDFC) < 0;
    boolean instruction = (0b00101010 << 24 << XEiJ.mpuDFC) < 0;
    int[] cache = (supervisor ?
                   instruction ? mmuSuperCodeCache : mmuSuperDataCache :
                   instruction ? mmuUserCodeCache : mmuUserDataCache);
    int head = (logicalPage * MMU_HASH_COEFF >>> -MMU_HASH_BITS) * (4 * MMU_CACHE_WAYS);  //先頭のエントリ
    if (MMU_CACHE_WAYS == 1) {  //1way
      if (cache[head] == logicalPage) {  //エントリが有効かつ論理ページアドレスがAn
        if ((cache[head + 3] & (MMU_DESCRIPTOR_GLOBAL | 1)) == 0) {  //エントリが有効かつNonGlobal
          cache[head] = cache[head + 1] = cache[head + 2] = cache[head + 3] = 1;  //末尾を空ける
        }
        return;  //論理ページアドレスがAnのエントリは1つだけなのでそれがNonGlobalでなければ何もしないで終了する
      }
    } else {  //2ways以上
      int tail = head + (4 * MMU_CACHE_WAYS - 4);  //末尾のエントリ
      for (int i = head; i <= tail; i += 4) {
        if (cache[i] == logicalPage) {  //エントリが有効かつ論理ページアドレスがAn
          if ((cache[i + 3] & (MMU_DESCRIPTOR_GLOBAL | 1)) == 0) {  //エントリが有効かつNonGlobal
            for (int j = i; j < tail; j += 4) {  //後ろを詰める
              cache[j    ] = cache[j + 4];
              cache[j + 1] = cache[j + 5];
              cache[j + 2] = cache[j + 6];
              cache[j + 3] = cache[j + 7];
            }
            cache[tail] = cache[tail + 1] = cache[tail + 2] = cache[tail + 3] = 1;  //末尾を空ける
          }
          return;  //論理ページアドレスがAnのエントリは1つだけなのでそれがNonGlobalでなければ何もしないで終了する
        }
      }
    }
  }  //mmuInvalidateNonGlobalCache(int)

  //--------------------------------------------------------------------------------
  //初期化

  //mmuInit ()
  //  初期化
  public static void mmuInit () {
    mmuTTUserData1 = new byte[256];
    mmuTTUserCode1 = new byte[256];
    mmuTTSuperData1 = new byte[256];
    mmuTTSuperCode1 = new byte[256];
    mmuTTUserData2 = new byte[256];
    mmuTTUserCode2 = new byte[256];
    mmuTTSuperData2 = new byte[256];
    mmuTTSuperCode2 = new byte[256];
    mmuReset ();
  }  //mmuInit()

  //mmuReset ()
  //  リセット
  public static void mmuReset () {
    mmuTTSetData (0, 0);
    mmuTTSetCode (0, 0);
    mmuSetTCR (0);
  }  //mmuReset()

  //--------------------------------------------------------------------------------
  //バスアクセス
  //
  //    ByteSign  byte  バイト符号拡張
  //    ByteZero  int   バイトゼロ拡張
  //    WordSign  int   ワード符号拡張
  //    WordZero  int   ワードゼロ拡張
  //    Long      int   ロング
  //    Quad      long  クワッド
  //
  //    Data    データ  1  先頭
  //    Second  データ  1  2番目
  //    Even    データ  2  先頭
  //    Four    データ  4  先頭
  //    Code    コード  2  先頭
  //    Opword  コード  2  先頭(命令ワード)
  //    Exword  コード  2  2番目(拡張ワード)
  //
  //  バイト
  //       0   1   2   3   4   5   6   7   8   9  10  11  12  13  14  15
  //    ┳━┯━┯━┯━┳━┯━┯━┯━┳━┯━┯━┯━┳━┯━┯━┯━┳
  //    ┃  │  │  │  ┃  │  │  │  ┃  │  │  │  ┃  │  │  │  ┃
  //    ┻━┷━┷━┷━┻━┷━┷━┷━┻━┷━┷━┷━┻━┷━┷━┷━┻
  //    ┏━┓
  //    ┃ B┃
  //    ┗━┛
  //        0
  //
  //  ワード
  //    偶数
  //       0   1   2   3   4   5   6   7   8   9  10  11  12  13  14  15
  //    ┳━┯━┯━┯━┳━┯━┯━┯━┳━┯━┯━┯━┳━┯━┯━┯━┳
  //    ┃  │  │  │  ┃  │  │  │  ┃  │  │  │  ┃  │  │  │  ┃
  //    ┻━┷━┷━┷━┻━┷━┷━┷━┻━┷━┷━┷━┻━┷━┷━┷━┻
  //    ┏━━━┓
  //    ┃   W  ┃
  //    ┗━━━┛
  //            0
  //    奇数
  //      -1   0   1   2   3   4   5   6   7   8   9  10  11  12  13  14
  //    ┳━┯━┯━┯━┳━┯━┯━┯━┳━┯━┯━┯━┳━┯━┯━┯━┳
  //    ┃  │  │  │  ┃  │  │  │  ┃  │  │  │  ┃  │  │  │  ┃
  //    ┻━┷━┷━┷━┻━┷━┷━┷━┻━┷━┷━┷━┻━┷━┷━┷━┻
  //        ┏━┳━┓
  //        ┃ B┃ B┃
  //        ┗━┻━┛
  //            8   0
  //
  //  ロング
  //    4の倍数
  //       0   1   2   3   4   5   6   7   8   9  10  11  12  13  14  15
  //    ┳━┯━┯━┯━┳━┯━┯━┯━┳━┯━┯━┯━┳━┯━┯━┯━┳
  //    ┃  │  │  │  ┃  │  │  │  ┃  │  │  │  ┃  │  │  │  ┃
  //    ┻━┷━┷━┷━┻━┷━┷━┷━┻━┷━┷━┷━┻━┷━┷━┷━┻
  //    ┏━━━━━━━┓
  //    ┃       L      ┃
  //    ┗━━━━━━━┛
  //                    0
  //    4の倍数+1
  //      -1   0   1   2   3   4   5   6   7   8   9  10  11  12  13  14
  //    ┳━┯━┯━┯━┳━┯━┯━┯━┳━┯━┯━┯━┳━┯━┯━┯━┳
  //    ┃  │  │  │  ┃  │  │  │  ┃  │  │  │  ┃  │  │  │  ┃
  //    ┻━┷━┷━┷━┻━┷━┷━┷━┻━┷━┷━┷━┻━┷━┷━┷━┻
  //        ┏━┳━━━┳━┓
  //        ┃ B┃   W  ┃ B┃
  //        ┗━┻━━━┻━┛
  //           24       8   0
  //    4の倍数+2
  //      -2  -1   0   1   2   3   4   5   6   7   8   9  10  11  12  13
  //    ┳━┯━┯━┯━┳━┯━┯━┯━┳━┯━┯━┯━┳━┯━┯━┯━┳
  //    ┃  │  │  │  ┃  │  │  │  ┃  │  │  │  ┃  │  │  │  ┃
  //    ┻━┷━┷━┷━┻━┷━┷━┷━┻━┷━┷━┷━┻━┷━┷━┷━┻
  //            ┏━━━┳━━━┓
  //            ┃   W  ┃   W  ┃
  //            ┗━━━┻━━━┛
  //                   16       0
  //    4の倍数+3
  //      -3  -2  -1   0   1   2   3   4   5   6   7   8   9  10  11  12
  //    ┳━┯━┯━┯━┳━┯━┯━┯━┳━┯━┯━┯━┳━┯━┯━┯━┳
  //    ┃  │  │  │  ┃  │  │  │  ┃  │  │  │  ┃  │  │  │  ┃
  //    ┻━┷━┷━┷━┻━┷━┷━┷━┻━┷━┷━┷━┻━┷━┷━┷━┻
  //                ┏━┳━━━┳━┓
  //                ┃ B┃   W  ┃ B┃
  //                ┗━┻━━━┻━┛
  //                   24       8   0
  //
  //  クワッド
  //    4の倍数
  //       0   1   2   3   4   5   6   7   8   9  10  11  12  13  14  15
  //    ┳━┯━┯━┯━┳━┯━┯━┯━┳━┯━┯━┯━┳━┯━┯━┯━┳
  //    ┃  │  │  │  ┃  │  │  │  ┃  │  │  │  ┃  │  │  │  ┃
  //    ┻━┷━┷━┷━┻━┷━┷━┷━┻━┷━┷━┷━┻━┷━┷━┷━┻
  //    ┏━━━━━━━┳━━━━━━━┓
  //    ┃       L      ┃       L      ┃
  //    ┗━━━━━━━┻━━━━━━━┛
  //                   32               0
  //    4の倍数+1
  //      -1   0   1   2   3   4   5   6   7   8   9  10  11  12  13  14
  //    ┳━┯━┯━┯━┳━┯━┯━┯━┳━┯━┯━┯━┳━┯━┯━┯━┳
  //    ┃  │  │  │  ┃  │  │  │  ┃  │  │  │  ┃  │  │  │  ┃
  //    ┻━┷━┷━┷━┻━┷━┷━┷━┻━┷━┷━┷━┻━┷━┷━┷━┻
  //        ┏━┳━━━┳━━━━━━━┳━┓
  //        ┃ B┃   W  ┃       L      ┃ B┃
  //        ┗━┻━━━┻━━━━━━━┻━┛
  //           56      40               8   0
  //    4の倍数+2
  //      -2  -1   0   1   2   3   4   5   6   7   8   9  10  11  12  13
  //    ┳━┯━┯━┯━┳━┯━┯━┯━┳━┯━┯━┯━┳━┯━┯━┯━┳
  //    ┃  │  │  │  ┃  │  │  │  ┃  │  │  │  ┃  │  │  │  ┃
  //    ┻━┷━┷━┷━┻━┷━┷━┷━┻━┷━┷━┷━┻━┷━┷━┷━┻
  //            ┏━━━┳━━━━━━━┳━━━┓
  //            ┃   W  ┃       L      ┃   W  ┃
  //            ┗━━━┻━━━━━━━┻━━━┛
  //                   48              16       0
  //    4の倍数+3
  //      -3  -2  -1   0   1   2   3   4   5   6   7   8   9  10  11  12
  //    ┳━┯━┯━┯━┳━┯━┯━┯━┳━┯━┯━┯━┳━┯━┯━┯━┳
  //    ┃  │  │  │  ┃  │  │  │  ┃  │  │  │  ┃  │  │  │  ┃
  //    ┻━┷━┷━┷━┻━┷━┷━┷━┻━┷━┷━┷━┻━┷━┷━┷━┻
  //                ┏━┳━━━━━━━┳━━━┳━┓
  //                ┃ B┃       L      ┃   W  ┃ B┃
  //                ┗━┻━━━━━━━┻━━━┻━┛
  //                   56              24       8   0
  //

  //--------------------------------------------------------------------------------
  //ピーク
  //  デバッガ用
  //  エラーや副作用なしでリードする
  //  アドレス変換はピーク
  //  ページフォルトやバスエラーのときは-1をキャストした値を返す

  //d = mmuPeekByteSign (a, f)
  //  ピークバイト符号拡張
  public static byte mmuPeekByteSign (int a, int f) {
    f = f == -1 ? XEiJ.regSRS != 0 ? 5 : 1 : f & 7;
    MemoryMappedDevice[] mm = (DataBreakPoint.DBP_ON ?
                               (f & 4) != 0 ? DataBreakPoint.dbpSuperMap : DataBreakPoint.dbpUserMap :
                               (f & 4) != 0 ? XEiJ.busSuperMap : XEiJ.busUserMap);
    //    01234567
    if (0b01100110 << 24 << f < 0) {  //SFC=1,2,5,6。アドレス変換あり
      int a0 = mmuTranslatePeek (a, f & 4, f & 2);
      return (a ^ a0) != 1 ? mm[a0 >>> XEiJ.BUS_PAGE_BITS].mmdPbs (a0) : -1;
    } else if (f != 7) {  //SFC=0,3,4。アドレス変換なし
      return mm[a >>> XEiJ.BUS_PAGE_BITS].mmdPbs (a);
    } else {
      return -1;
    }
  }  //mmuPeekByteSign(int,int)

  //d = mmuPeekByteZero (a, f)
  //  ピークバイトゼロ拡張
  public static int mmuPeekByteZero (int a, int f) {
    f = f == -1 ? XEiJ.regSRS != 0 ? 5 : 1 : f & 7;
    MemoryMappedDevice[] mm = (DataBreakPoint.DBP_ON ?
                               (f & 4) != 0 ? DataBreakPoint.dbpSuperMap : DataBreakPoint.dbpUserMap :
                               (f & 4) != 0 ? XEiJ.busSuperMap : XEiJ.busUserMap);
    //    01234567
    if (0b01100110 << 24 << f < 0) {  //SFC=1,2,5,6。アドレス変換あり
      int a0 = mmuTranslatePeek (a, f & 4, f & 2);
      return (a ^ a0) != 1 ? mm[a0 >>> XEiJ.BUS_PAGE_BITS].mmdPbz (a0) : 0xff;
      //                                                        ^        ^^^^
    } else if (f != 7) {  //SFC=0,3,4。アドレス変換なし
      return mm[a >>> XEiJ.BUS_PAGE_BITS].mmdPbz (a);
      //                                       ^
    } else {
      return 0xff;
      //     ^^^^
    }
  }  //mmuPeekByteZero(int,int)

  //d = mmuPeekByteSignData (a, supervisor)
  //  ピークバイト符号拡張(データ)
  public static byte mmuPeekByteSignData (int a, int supervisor) {
    MemoryMappedDevice[] mm = supervisor != 0 ? DataBreakPoint.DBP_ON ? DataBreakPoint.dbpSuperMap : XEiJ.busSuperMap : DataBreakPoint.DBP_ON ? DataBreakPoint.dbpUserMap : XEiJ.busUserMap;
    int a0 = mmuTranslatePeek (a, supervisor, 0);
    return (a ^ a0) == 1 ? -1 : mm[a0 >>> XEiJ.BUS_PAGE_BITS].mmdPbs (a0);
  }  //mmuPeekByteSignData(int,int)

  //d = mmuPeekByteSignCode (a, supervisor)
  //  ピークバイト符号拡張(コード)
  public static byte mmuPeekByteSignCode (int a, int supervisor) {
    MemoryMappedDevice[] mm = supervisor != 0 ? DataBreakPoint.DBP_ON ? DataBreakPoint.dbpSuperMap : XEiJ.busSuperMap : DataBreakPoint.DBP_ON ? DataBreakPoint.dbpUserMap : XEiJ.busUserMap;
    int a0 = mmuTranslatePeek (a, supervisor, 1);
    return (a ^ a0) == 1 ? -1 : mm[a0 >>> XEiJ.BUS_PAGE_BITS].mmdPbs (a0);
  }  //mmuPeekByteSignCode(int,int)

  //d = mmuPeekByteZeroData (a, supervisor)
  //  ピークバイトゼロ拡張(データ)
  public static int mmuPeekByteZeroData (int a, int supervisor) {
    MemoryMappedDevice[] mm = supervisor != 0 ? DataBreakPoint.DBP_ON ? DataBreakPoint.dbpSuperMap : XEiJ.busSuperMap : DataBreakPoint.DBP_ON ? DataBreakPoint.dbpUserMap : XEiJ.busUserMap;
    int a0 = mmuTranslatePeek (a, supervisor, 0);
    return (a ^ a0) == 1 ? 255 : mm[a0 >>> XEiJ.BUS_PAGE_BITS].mmdPbz (a0);
  }  //mmuPeekByteZeroData(int,int)

  //d = mmuPeekByteZeroCode (a, supervisor)
  //  ピークバイトゼロ拡張(コード)
  public static int mmuPeekByteZeroCode (int a, int supervisor) {
    MemoryMappedDevice[] mm = supervisor != 0 ? DataBreakPoint.DBP_ON ? DataBreakPoint.dbpSuperMap : XEiJ.busSuperMap : DataBreakPoint.DBP_ON ? DataBreakPoint.dbpUserMap : XEiJ.busUserMap;
    int a0 = mmuTranslatePeek (a, supervisor, 1);
    return (a ^ a0) == 1 ? 255 : mm[a0 >>> XEiJ.BUS_PAGE_BITS].mmdPbz (a0);
  }  //mmuPeekByteZeroCode(int,int)

  //d = mmuPeekWordSign (a, f)
  //  ピークワード符号拡張
  public static int mmuPeekWordSign (int a, int f) {
    f = f == -1 ? XEiJ.regSRS != 0 ? 5 : 1 : f & 7;
    MemoryMappedDevice[] mm = (DataBreakPoint.DBP_ON ?
                               (f & 4) != 0 ? DataBreakPoint.dbpSuperMap : DataBreakPoint.dbpUserMap :
                               (f & 4) != 0 ? XEiJ.busSuperMap : XEiJ.busUserMap);
    //    01234567
    if (0b01100110 << 24 << f < 0) {  //SFC=1,2,5,6。アドレス変換あり
      int a0 = mmuTranslatePeek (a, f & 4, f & 2);
      if ((a & 1) == 0) {  //偶数
        return (a ^ a0) != 1 ? mm[a0 >>> XEiJ.BUS_PAGE_BITS].mmdPws (a0) : -1;
      } else {  //奇数
        int a1 = mmuTranslatePeek (a + 1, f & 4, f & 2);
        return (((a     ^ a0) != 1 ? mm[a0 >>> XEiJ.BUS_PAGE_BITS].mmdPbs (a0) :  -1) << 8 |
                ((a + 1 ^ a1) != 1 ? mm[a1 >>> XEiJ.BUS_PAGE_BITS].mmdPbz (a1) : 255));
      }
    } else if (f != 7) {  //SFC=0,3,4。アドレス変換なし
      if ((a & 1) == 0) {  //偶数
        return mm[a >>> XEiJ.BUS_PAGE_BITS].mmdPws (a);
      } else {  //奇数
        return (mm[a     >>> XEiJ.BUS_PAGE_BITS].mmdPbs (a    ) << 8 |
                mm[a + 1 >>> XEiJ.BUS_PAGE_BITS].mmdPbz (a + 1));
      }
    } else {
      return -1;
    }
  }  //mmuPeekWordSign(int,int)

  //d = mmuPeekWordSignData (a, supervisor)
  //  ピークワード符号拡張(データ)
  public static int mmuPeekWordSignData (int a, int supervisor) {
    MemoryMappedDevice[] mm = supervisor != 0 ? DataBreakPoint.DBP_ON ? DataBreakPoint.dbpSuperMap : XEiJ.busSuperMap : DataBreakPoint.DBP_ON ? DataBreakPoint.dbpUserMap : XEiJ.busUserMap;
    int a0 = mmuTranslatePeek (a, supervisor, 0);  //a+1が必要なので上書き不可
    if ((a & 1) == 0) {  //偶数
      return (a0 & 1) != 0 ? -1 : mm[a0 >>> XEiJ.BUS_PAGE_BITS].mmdPws (a0);
    } else {  //奇数
      int a1 = mmuTranslatePeek (a + 1, supervisor, 0);
      return (((a0 & 1) == 0 ?  -1 : mm[a0 >>> XEiJ.BUS_PAGE_BITS].mmdPbs (a0)) << 8 |
              ((a1 & 1) != 0 ? 255 : mm[a1 >>> XEiJ.BUS_PAGE_BITS].mmdPbz (a1)));
    }
  }  //mmuPeekWordSignData(int,int)

  //d = mmuPeekWordSignEven (a, supervisor)
  //  ピークワード符号拡張(偶数)
  public static int mmuPeekWordSignEven (int a, int supervisor) {
    MemoryMappedDevice[] mm = supervisor != 0 ? DataBreakPoint.DBP_ON ? DataBreakPoint.dbpSuperMap : XEiJ.busSuperMap : DataBreakPoint.DBP_ON ? DataBreakPoint.dbpUserMap : XEiJ.busUserMap;
    a = mmuTranslatePeek (a, supervisor, 0);
    return (a & 1) != 0 ? -1 : mm[a >>> XEiJ.BUS_PAGE_BITS].mmdPws (a);
  }  //mmuPeekWordSignEven(int,int)

  //d = mmuPeekWordSignCode (a, supervisor)
  //  ピークワード符号拡張(コード)
  public static int mmuPeekWordSignCode (int a, int supervisor) {
    MemoryMappedDevice[] mm = supervisor != 0 ? DataBreakPoint.DBP_ON ? DataBreakPoint.dbpSuperMap : XEiJ.busSuperMap : DataBreakPoint.DBP_ON ? DataBreakPoint.dbpUserMap : XEiJ.busUserMap;
    a = mmuTranslatePeek (a, supervisor, 1);
    return (a & 1) != 0 ? -1 : mm[a >>> XEiJ.BUS_PAGE_BITS].mmdPws (a);
  }  //mmuPeekWordSignCode(int,int)

  //d = mmuPeekWordZeroData (a, supervisor)
  //  ピークワードゼロ拡張(データ)
  public static int mmuPeekWordZeroData (int a, int supervisor) {
    MemoryMappedDevice[] mm = supervisor != 0 ? DataBreakPoint.DBP_ON ? DataBreakPoint.dbpSuperMap : XEiJ.busSuperMap : DataBreakPoint.DBP_ON ? DataBreakPoint.dbpUserMap : XEiJ.busUserMap;
    int a0 = mmuTranslatePeek (a, supervisor, 0);  //a+1が必要なので上書き不可
    if ((a & 1) == 0) {  //偶数
      return (a0 & 1) != 0 ? 65535 : mm[a0 >>> XEiJ.BUS_PAGE_BITS].mmdPwz (a0);
    } else {  //奇数
      int a1 = mmuTranslatePeek (a + 1, supervisor, 0);
      return (((a0 & 1) == 0 ? 255 : mm[a0 >>> XEiJ.BUS_PAGE_BITS].mmdPbz (a0)) << 8 |
              ((a1 & 1) != 0 ? 255 : mm[a1 >>> XEiJ.BUS_PAGE_BITS].mmdPbz (a1)));
    }
  }  //mmuPeekWordZeroData(int,int)

  //d = mmuPeekWordZeroEven (a, supervisor)
  //  ピークワードゼロ拡張(偶数)
  public static int mmuPeekWordZeroEven (int a, int supervisor) {
    MemoryMappedDevice[] mm = supervisor != 0 ? DataBreakPoint.DBP_ON ? DataBreakPoint.dbpSuperMap : XEiJ.busSuperMap : DataBreakPoint.DBP_ON ? DataBreakPoint.dbpUserMap : XEiJ.busUserMap;
    a = mmuTranslatePeek (a, supervisor, 0);
    return (a & 1) != 0 ? 65535 : mm[a >>> XEiJ.BUS_PAGE_BITS].mmdPwz (a);
  }  //mmuPeekWordZeroEven(int,int)

  //d = mmuPeekWordZeroCode (a, supervisor)
  //  ピークワードゼロ拡張(コード)
  public static int mmuPeekWordZeroCode (int a, int supervisor) {
    MemoryMappedDevice[] mm = supervisor != 0 ? DataBreakPoint.DBP_ON ? DataBreakPoint.dbpSuperMap : XEiJ.busSuperMap : DataBreakPoint.DBP_ON ? DataBreakPoint.dbpUserMap : XEiJ.busUserMap;
    a = mmuTranslatePeek (a, supervisor, 1);
    return (a & 1) != 0 ? 65535 : mm[a >>> XEiJ.BUS_PAGE_BITS].mmdPwz (a);
  }  //mmuPeekWordZeroCode(int,int)

  //d = mmuPeekLong (a, f)
  //  ピークロング
  public static int mmuPeekLong (int a, int f) {
    f = f == -1 ? XEiJ.regSRS != 0 ? 5 : 1 : f & 7;
    MemoryMappedDevice[] mm = (DataBreakPoint.DBP_ON ?
                               (f & 4) != 0 ? DataBreakPoint.dbpSuperMap : DataBreakPoint.dbpUserMap :
                               (f & 4) != 0 ? XEiJ.busSuperMap : XEiJ.busUserMap);
    //    01234567
    if (0b01100110 << 24 << f < 0) {  //SFC=1,2,5,6。アドレス変換あり
      int a0 = mmuTranslatePeek (a, f & 4, f & 2);
      if ((a & 3) == 0) {  //4の倍数
        return (a ^ a0) != 1 ? mm[a0 >>> XEiJ.BUS_PAGE_BITS].mmdPls (a0) : -1;
      } else if ((a & 1) == 0) {  //4の倍数ではない偶数
        int a2 = mmuTranslatePeek (a + 2, f & 4, f & 2);
        return (((a     ^ a0) != 1 ? mm[a0 >>> XEiJ.BUS_PAGE_BITS].mmdPws (a0) :    -1) << 16 |
                ((a + 2 ^ a2) != 1 ? mm[a2 >>> XEiJ.BUS_PAGE_BITS].mmdPwz (a2) : 65535));
      } else {  //奇数
        int a1 = mmuTranslatePeek (a + 1, f & 4, f & 2);
        int a3 = mmuTranslatePeek (a + 3, f & 4, f & 2);
        return (((a     ^ a0) != 1 ? mm[a0 >>> XEiJ.BUS_PAGE_BITS].mmdPbs (a0) :    -1) << 24 |
                ((a + 1 ^ a1) != 1 ? mm[a1 >>> XEiJ.BUS_PAGE_BITS].mmdPwz (a1) : 65535) <<  8 |
                ((a + 3 ^ a3) != 1 ? mm[a3 >>> XEiJ.BUS_PAGE_BITS].mmdPbz (a3) :   255));
      }
    } else if (f != 7) {  //SFC=0,3,4。アドレス変換なし
      if ((a & 3) == 0) {  //4の倍数
        return mm[a >>> XEiJ.BUS_PAGE_BITS].mmdPls (a);
      } else if ((a & 1) == 0) {  //4の倍数ではない偶数
        return (mm[a     >>> XEiJ.BUS_PAGE_BITS].mmdPws (a    ) << 16 |
                mm[a + 2 >>> XEiJ.BUS_PAGE_BITS].mmdPwz (a + 2));
      } else {  //奇数
        return (mm[a     >>> XEiJ.BUS_PAGE_BITS].mmdPbs (a    ) << 24 |
                mm[a + 1 >>> XEiJ.BUS_PAGE_BITS].mmdPwz (a + 1) <<  8 |
                mm[a + 3 >>> XEiJ.BUS_PAGE_BITS].mmdPbz (a + 3));
      }
    } else {
      return -1;
    }
  }  //mmuPeekLong(int,int)

  //d = mmuPeekLongData (a, supervisor)
  //  ピークロング(データ)
  public static int mmuPeekLongData (int a, int supervisor) {
    MemoryMappedDevice[] mm = supervisor != 0 ? DataBreakPoint.DBP_ON ? DataBreakPoint.dbpSuperMap : XEiJ.busSuperMap : DataBreakPoint.DBP_ON ? DataBreakPoint.dbpUserMap : XEiJ.busUserMap;
    int a0 = mmuTranslatePeek (a, supervisor, 0);  //a+1,a+2,a+3が必要なので上書き不可
    if ((a & 3) == 0) {  //4の倍数
      return (a0 & 1) != 0 ? -1 : mm[a0 >>> XEiJ.BUS_PAGE_BITS].mmdPls (a0);
    } else if ((a & 1) == 0) {  //4の倍数+2
      int a2 = mmuTranslatePeek (a + 2, supervisor, 0);
      return (((a0 & 1) != 0 ?    -1 : mm[a0 >>> XEiJ.BUS_PAGE_BITS].mmdPws (a0)) << 16 |
              ((a2 & 1) != 0 ? 65535 : mm[a2 >>> XEiJ.BUS_PAGE_BITS].mmdPwz (a2)));
    } else {  //奇数
      int a1 = mmuTranslatePeek (a + 1, supervisor, 0);
      int a3 = mmuTranslatePeek (a + 3, supervisor, 0);
      return (((a0 & 1) == 0 ?    -1 : mm[a0 >>> XEiJ.BUS_PAGE_BITS].mmdPbs (a0)) << 24 |
              ((a1 & 1) != 0 ? 65535 : mm[a1 >>> XEiJ.BUS_PAGE_BITS].mmdPwz (a1)) << 16 |
              ((a3 & 1) != 0 ?   255 : mm[a3 >>> XEiJ.BUS_PAGE_BITS].mmdPbz (a3)));
    }
  }  //mmuPeekLongData(int,int)

  //d = mmuPeekLongEven (a, supervisor)
  //  ピークロング(偶数)
  public static int mmuPeekLongEven (int a, int supervisor) {
    MemoryMappedDevice[] mm = supervisor != 0 ? DataBreakPoint.DBP_ON ? DataBreakPoint.dbpSuperMap : XEiJ.busSuperMap : DataBreakPoint.DBP_ON ? DataBreakPoint.dbpUserMap : XEiJ.busUserMap;
    int a0 = mmuTranslatePeek (a, supervisor, 0);  //a+2が必要なので上書き不可
    if ((a & 2) == 0) {  //4の倍数
      return (a0 & 1) != 0 ? -1 : mm[a0 >>> XEiJ.BUS_PAGE_BITS].mmdPls (a0);
    } else {  //4の倍数+2
      int a2 = mmuTranslatePeek (a + 2, supervisor, 0);
      return (((a0 & 1) != 0 ?    -1 : mm[a0 >>> XEiJ.BUS_PAGE_BITS].mmdPws (a0)) << 16 |
              ((a2 & 1) != 0 ? 65535 : mm[a2 >>> XEiJ.BUS_PAGE_BITS].mmdPwz (a2)));
    }
  }  //mmuPeekLongEven(int,int)

  //d = mmuPeekLongFour (a, supervisor)
  //  ピークロング(4の倍数)
  public static int mmuPeekLongFour (int a, int supervisor) {
    MemoryMappedDevice[] mm = supervisor != 0 ? DataBreakPoint.DBP_ON ? DataBreakPoint.dbpSuperMap : XEiJ.busSuperMap : DataBreakPoint.DBP_ON ? DataBreakPoint.dbpUserMap : XEiJ.busUserMap;
    a = mmuTranslatePeek (a, supervisor, 0);
    return (a & 1) != 0 ? -1 : mm[a >>> XEiJ.BUS_PAGE_BITS].mmdPls (a);
  }  //mmuPeekLongFour(int,int)

  //d = mmuPeekLongCode (a, supervisor)
  //  ピークロング(コード)
  public static int mmuPeekLongCode (int a, int supervisor) {
    MemoryMappedDevice[] mm = supervisor != 0 ? DataBreakPoint.DBP_ON ? DataBreakPoint.dbpSuperMap : XEiJ.busSuperMap : DataBreakPoint.DBP_ON ? DataBreakPoint.dbpUserMap : XEiJ.busUserMap;
    int a0 = mmuTranslatePeek (a, supervisor, 1);  //a+2が必要なので上書き不可
    if ((a & 2) == 0) {  //4の倍数
      return (a0 & 1) != 0 ? -1 : mm[a0 >>> XEiJ.BUS_PAGE_BITS].mmdPls (a0);
    } else {  //4の倍数+2
      int a2 = mmuTranslatePeek (a + 2, supervisor, 1);
      return (((a0 & 1) != 0 ?    -1 : mm[a0 >>> XEiJ.BUS_PAGE_BITS].mmdPws (a0)) << 16 |
              ((a2 & 1) != 0 ? 65535 : mm[a2 >>> XEiJ.BUS_PAGE_BITS].mmdPwz (a2)));
    }
  }  //mmuPeekLongCode(int,int)

  //d = mmuPeekQuad (a, f)
  //  ピーククワッド
  public static long mmuPeekQuad (int a, int f) {
    return (long) mmuPeekLong (a, f) << 32 | mmuPeekLong (a + 4, f) & 0xffffffffL;
  }  //mmuPeekQuad(int,int)

  //d = mmuPeekQuadData (a, supervisor)
  //  ピーククワッド(データ)
  public static long mmuPeekQuadData (int a, int supervisor) {
    MemoryMappedDevice[] mm = supervisor != 0 ? DataBreakPoint.DBP_ON ? DataBreakPoint.dbpSuperMap : XEiJ.busSuperMap : DataBreakPoint.DBP_ON ? DataBreakPoint.dbpUserMap : XEiJ.busUserMap;
    int a0 = mmuTranslatePeek (a, supervisor, 0);  //a+1,a+2,a+3,a+4,a+5,a+6,a+7が必要なので上書き不可
    if ((a & 3) == 0) {  //4の倍数
      int a4 = mmuTranslatePeek (a + 4, supervisor, 0);  //4の倍数
      return ((long) ((a0 & 1) != 0 ? -1 : mm[a0 >>> XEiJ.BUS_PAGE_BITS].mmdPls (a0)) << 32 |
              (long) ((a4 & 1) != 0 ? -1 : mm[a4 >>> XEiJ.BUS_PAGE_BITS].mmdPls (a4)) & 0x00000000ffffffffL);
    } else if ((a & 1) == 0) {  //4の倍数+2
      int a2 = mmuTranslatePeek (a + 2, supervisor, 0);  //4の倍数
      int a6 = mmuTranslatePeek (a + 6, supervisor, 0);  //4の倍数
      return ((long) ((a0 & 1) != 0 ?    -1 : mm[a0 >>> XEiJ.BUS_PAGE_BITS].mmdPws (a0)) << 48 |
              (long) ((a2 & 1) != 0 ?    -1 : mm[a2 >>> XEiJ.BUS_PAGE_BITS].mmdPls (a2)) << 16 & 0x0000ffffffff0000L |
              (long) ((a6 & 1) != 0 ? 65535 : mm[a6 >>> XEiJ.BUS_PAGE_BITS].mmdPwz (a6)));
    } else if ((a & 3) == 1) {  //4の倍数+1
      int a1 = mmuTranslatePeek (a + 1, supervisor, 0);  //4の倍数+2
      int a3 = mmuTranslatePeek (a + 3, supervisor, 0);  //4の倍数
      int a7 = mmuTranslatePeek (a + 7, supervisor, 0);  //4の倍数
      return ((long) ((a0 & 1) != 0 ?    -1 : mm[a0 >>> XEiJ.BUS_PAGE_BITS].mmdPbs (a0)) << 56 |
              (long) ((a1 & 1) != 0 ? 65535 : mm[a1 >>> XEiJ.BUS_PAGE_BITS].mmdPwz (a1)) << 40 |
              (long) ((a3 & 1) != 0 ?    -1 : mm[a3 >>> XEiJ.BUS_PAGE_BITS].mmdPls (a3)) <<  8 & 0x000000ffffffff00L |
              (long) ((a7 & 1) != 0 ?   255 : mm[a7 >>> XEiJ.BUS_PAGE_BITS].mmdPbz (a7)));
    } else {  //4の倍数+3
      int a1 = mmuTranslatePeek (a + 1, supervisor, 0);  //4の倍数
      int a5 = mmuTranslatePeek (a + 5, supervisor, 0);  //4の倍数
      int a7 = mmuTranslatePeek (a + 7, supervisor, 0);  //4の倍数+2
      return ((long) ((a0 & 1) != 0 ?    -1 : mm[a0 >>> XEiJ.BUS_PAGE_BITS].mmdPbs (a0)) << 56 |
              (long) ((a1 & 1) != 0 ?    -1 : mm[a1 >>> XEiJ.BUS_PAGE_BITS].mmdPls (a1)) << 24 & 0x00ffffffff000000L |
              (long) ((a5 & 1) != 0 ? 65535 : mm[a5 >>> XEiJ.BUS_PAGE_BITS].mmdPwz (a5)) <<  8 |
              (long) ((a7 & 1) != 0 ?   255 : mm[a7 >>> XEiJ.BUS_PAGE_BITS].mmdPbz (a7)));
    }
  }  //mmuPeekQuadData(int,int)

  //d = mmuPeekQuadEven (a, supervisor)
  //  ピーククワッド(偶数)
  public static long mmuPeekQuadEven (int a, int supervisor) {
    MemoryMappedDevice[] mm = supervisor != 0 ? DataBreakPoint.DBP_ON ? DataBreakPoint.dbpSuperMap : XEiJ.busSuperMap : DataBreakPoint.DBP_ON ? DataBreakPoint.dbpUserMap : XEiJ.busUserMap;
    int a0 = mmuTranslatePeek (a, supervisor, 0);  //a+2,a+4,a+6が必要なので上書き不可
    if ((a & 2) == 0) {  //4の倍数
      int a4 = mmuTranslatePeek (a + 4, supervisor, 0);  //4の倍数
      return ((long) ((a0 & 1) != 0 ? -1 : mm[a0 >>> XEiJ.BUS_PAGE_BITS].mmdPls (a0)) << 32 |
              (long) ((a4 & 1) != 0 ? -1 : mm[a4 >>> XEiJ.BUS_PAGE_BITS].mmdPls (a4)) & 0x00000000ffffffffL);
    } else {  //4の倍数+2
      int a2 = mmuTranslatePeek (a + 2, supervisor, 0);  //4の倍数
      int a6 = mmuTranslatePeek (a + 6, supervisor, 0);  //4の倍数
      return ((long) ((a0 & 1) != 0 ?    -1 : mm[a0 >>> XEiJ.BUS_PAGE_BITS].mmdPws (a0)) << 48 |
              (long) ((a2 & 1) != 0 ?    -1 : mm[a2 >>> XEiJ.BUS_PAGE_BITS].mmdPls (a2)) << 16 & 0x0000ffffffff0000L |
              (long) ((a6 & 1) != 0 ? 65535 : mm[a6 >>> XEiJ.BUS_PAGE_BITS].mmdPwz (a6)));
    }
  }  //mmuPeekQuadEven(int,int)

  //d = mmuPeekQuadFour (a, supervisor)
  //  ピーククワッド(4の倍数)
  public static long mmuPeekQuadFour (int a, int supervisor) {
    MemoryMappedDevice[] mm = supervisor != 0 ? DataBreakPoint.DBP_ON ? DataBreakPoint.dbpSuperMap : XEiJ.busSuperMap : DataBreakPoint.DBP_ON ? DataBreakPoint.dbpUserMap : XEiJ.busUserMap;
    int a0 = mmuTranslatePeek (a    , supervisor, 0);  //4の倍数。a+4が必要なので上書き不可
    int a4 = mmuTranslatePeek (a + 4, supervisor, 0);  //4の倍数
    return ((long) ((a0 & 1) != 0 ? -1 : mm[a0 >>> XEiJ.BUS_PAGE_BITS].mmdPls (a0)) << 32 |
            (long) ((a4 & 1) != 0 ? -1 : mm[a4 >>> XEiJ.BUS_PAGE_BITS].mmdPls (a4)) & 0x00000000ffffffffL);
  }  //mmuPeekQuadFour(int,int)

  //d = mmuPeekQuadCode (a, supervisor)
  //  ピーククワッド(コード)
  public static long mmuPeekQuadCode (int a, int supervisor) {
    MemoryMappedDevice[] mm = supervisor != 0 ? DataBreakPoint.DBP_ON ? DataBreakPoint.dbpSuperMap : XEiJ.busSuperMap : DataBreakPoint.DBP_ON ? DataBreakPoint.dbpUserMap : XEiJ.busUserMap;
    int a0 = mmuTranslatePeek (a, supervisor, 1);  //a+2,a+4,a+6が必要なので上書き不可
    if ((a & 2) == 0) {  //4の倍数
      int a4 = mmuTranslatePeek (a + 4, supervisor, 1);
      return ((long) ((a0 & 1) != 0 ? -1 : mm[a0 >>> XEiJ.BUS_PAGE_BITS].mmdPls (a0)) << 32 |
              (long) ((a4 & 1) != 0 ? -1 : mm[a4 >>> XEiJ.BUS_PAGE_BITS].mmdPls (a4)) & 0x00000000ffffffffL);
    } else {  //4の倍数+2
      int a2 = mmuTranslatePeek (a + 2, supervisor, 1);  //4の倍数
      int a6 = mmuTranslatePeek (a + 6, supervisor, 1);  //4の倍数
      return ((long) ((a0 & 1) != 0 ?    -1 : mm[a0 >>> XEiJ.BUS_PAGE_BITS].mmdPws (a0)) << 48 |
              (long) ((a2 & 1) != 0 ?    -1 : mm[a2 >>> XEiJ.BUS_PAGE_BITS].mmdPls (a2)) << 16 & 0x0000ffffffff0000L |
              (long) ((a6 & 1) != 0 ? 65535 : mm[a6 >>> XEiJ.BUS_PAGE_BITS].mmdPwz (a6)));
    }
  }  //mmuPeekQuadCode(int,int)

  //mmuPeekExtended (a, b, f)
  //  ピークエクステンデッド
  public static void mmuPeekExtended (int a, byte[] b, int f) {
    for (int i = 0; i < 12; i++) {
      b[i] = mmuPeekByteSign (a + i, f);
    }
  }  //mmuPeekExtended(int,int,byte[])

  //len = mmuPeekStrlen (a, l)
  public static int mmuPeekStrlen (int a, int l, int supervisor) {
    for (int i = 0; i < l; i++) {
      if (mmuPeekByteZeroData (a + i, supervisor) == 0) {
        return i;
      }
    }
    return l;
  }  //mmuPeekStrlen(int,int,int)

  //bool = mmuPeekEquals (a, str)
  //  アドレスaから始まるSJISの文字列とstrをSJISに変換してエスケープシーケンスを展開した文字列を比較する
  //  終端の\0まで比較するときはstrに\0を含めること
  //  \x??で任意のSJISの文字を書ける
  //  SJISに変換できない文字は'※'とみなす
  //  スーパーバイザモード比較する
  public static boolean mmuPeekEquals (int a, String str) {
    int len = str.length ();
    for (int i = 0; i < len; i++) {
      int c = str.charAt (i);
      if (c == '\\') {  //エスケープシーケンス。SJIS変換を省略する
        int d = i + 1 < len ? str.charAt (i + 1) : -1;  //2文字目
        if ((d & -4) == '0') {  // \[0-3][0-7]{0,2}
          c = d & 7;
          d = i + 2 < len ? str.charAt (i + 2) : -1;  //3文字目
          if ((d & -8) == '0') {
            c = c << 3 | (d & 7);
            d = i + 3 < len ? str.charAt (i + 3) : -1;  //4文字目
            if ((d & -8) == '0') {
              c = c << 3 | (d & 7);
              i++;  //4文字
            }
            i++;  //3文字
          }
          i++;  //2文字
        } else if ((d & -4) == '4') {  // \[4-7][0-7]?
          c = d & 7;
          d = i + 2 < len ? str.charAt (i + 2) : -1;  //3文字目
          if ((d & -8) == '0') {
            c = c << 3 | (d & 7);
            i++;  //3文字
          }
          i++;  //2文字
        } else if (d == 'b') {  // \b
          c = 0x08;  //BS
          i++;  //2文字
        } else if (d == 't') {  // \t
          c = 0x09;  //HT
          i++;  //2文字
        } else if (d == 'n') {  // \n
          c = 0x0a;  //LF
          i++;  //2文字
        } else if (d == 'v') {  // \v
          c = 0x0b;  //VT
          i++;  //2文字
        } else if (d == 'f') {  // \f
          c = 0x0c;  //FF
          i++;  //2文字
        } else if (d == 'r') {  // \r
          c = 0x0d;  //CR
          i++;  //2文字
        } else if (d == 'x' &&
                   i + 3 < len &&
                   CharacterCode.chrIsXdigit (str.charAt (i + 2)) &&
                   CharacterCode.chrIsXdigit (str.charAt (i + 3))) {  // \x[0-9A-Fa-f]{2}
          c = (CharacterCode.chrDigit (str.charAt (i + 2)) << 4 |
               CharacterCode.chrDigit (str.charAt (i + 3)));
          i += 3;  //4文字
        } else if ('!' <= d && d <= '~') {
          c = d;
          i++;  //2文字
        }
        if (mmuPeekByteZeroData (a++, 1) != c) {
          return false;
        }
      } else {  //エスケープシーケンス以外
        int s = CharacterCode.chrCharToSJIS[c];
        if (s == 0 && c != 0) {
          s = 0x81a6;  //'※'
        }
        if (s >> 8 != 0) {  //2バイトコード
          if (mmuPeekByteZeroData (a++, 1) != s >> 8) {
            return false;
          }
        }
        if (mmuPeekByteZeroData (a++, 1) != (s & 0xff)) {
          return false;
        }
      }
    }  //for
    return true;
  }  //mmuPeekEquals

  //s = mmuPeekStringL (a, l, supervisor)
  //sb = mmuPeekStringL (sb, a, l, supervisor)
  //  ピークストリング(長さ指定)
  //  文字列を読み出す
  //  対応する文字がないときは'.'または'※'になる
  //  制御コードは'.'になる
  public static String mmuPeekStringL (int a, int l, int supervisor) {
    return mmuPeekStringL (new StringBuilder (), a, l, supervisor).toString ();
  }  //mmuPeekStringL(int,int,int)
  public static StringBuilder mmuPeekStringL (StringBuilder sb, int a, int l, int supervisor) {
    for (int i = 0; i < l; i++) {
      int s = mmuPeekByteZeroData (a + i, supervisor);
      char c;
      if (0x81 <= s && s <= 0x9f || 0xe0 <= s && s <= 0xef) {  //SJISの2バイトコードの1バイト目
        int t = i + 1 < l ? mmuPeekByteZeroData (a + i + 1, supervisor) : 0;
        if (0x40 <= t && t != 0x7f && t <= 0xfc) {  //SJISの2バイトコードの2バイト目
          c = CharacterCode.chrSJISToChar[s << 8 | t];  //2バイトで変換する
          if (c == 0) {  //対応する文字がない
            c = '※';
          }
          i++;
        } else {  //SJISの2バイトコードの2バイト目ではない
          c = '.';  //SJISの2バイトコードの1バイト目ではなかった
        }
      } else {  //SJISの2バイトコードの1バイト目ではない
        c = CharacterCode.chrSJISToChar[s];  //1バイトで変換する
        if (c < 0x20 || c == 0x7f) {  //対応する文字がないまたは制御コード
          c = '.';
        }
      }
      sb.append (c);
    }
    return sb;
  }  //mmuPeekString(StringBuilder,int,int,int)

  //s = mmuPeekStringZ (a, f)
  //sb = mmuPeekStringZ (sb, a, f)
  //  ピークストリング
  //  文字列をSJISからUTF-16に変換しながらメモリから読み出す
  //  '\0'の手前まで読み出す
  //  UTF-16に変換できない文字は'\ufffd'になる
  public static String mmuPeekStringZ (int a, int f) {
    return mmuPeekStringZ (new StringBuilder (), a, f).toString ();
  }  //mmuPeekStringZ(int,int)
  public static StringBuilder mmuPeekStringZ (StringBuilder sb, int a, int f) {
    for (;;) {
      int s = mmuPeekByteSign (a++, f) & 255;
      if (s == 0) {
        break;
      }
      int u;
      if (0x81 <= s && s <= 0x9f || 0xe0 <= s && s <= 0xef) {  //SJISの2バイトコードの1バイト目
        int t = mmuPeekByteSign (a++, f) & 255;
        if (t == 0) {
          sb.append ('\ufffd');
          break;
        }
        if (0x40 <= t && t != 0x7f && t <= 0xfc) {  //SJISの2バイトコードの2バイト目
          t |= s << 8;
          u = CharacterCode.chrSJISToChar[t];  //2バイトで変換する
          if (u == 0) {  //変換できない
            u = 0xfffd;
          }
        } else {  //SJISの2バイトコードの2バイト目ではない
          u = 0xfffd;
        }
      } else {  //SJISの2バイトコードの1バイト目ではない
        u = CharacterCode.chrSJISToChar[s];  //1バイトで変換する
        if (u == 0) {  //変換できない
          u = 0xfffd;
        }
      }
      sb.append ((char) u);
    }
    return sb;
  }  //mmuPeekStringZ(StringBuilder,int,int)

  //--------------------------------------------------------------------------------
  //リード
  //  アドレス変換はリード
  //  FSLWのRead and WriteはRead

  //d = mmuReadByteSignData (a, supervisor)
  //  リードバイト符号拡張(データ)
  public static byte mmuReadByteSignData (int a, int supervisor) throws M68kException {
    if (supervisor != 0) {  //スーパーバイザモード
      m60FSLW = M60_FSLW_IOMA_FIRST | M60_FSLW_RW_READ | M60_FSLW_SIZE_BYTE | M60_FSLW_TM_SUPER_DATA;
      int a0 = mmuTranslateReadSuperData (a);
      return (DataBreakPoint.DBP_ON ? DataBreakPoint.dbpSuperMap : XEiJ.busSuperMap)[a0 >>> XEiJ.BUS_PAGE_BITS].mmdRbs (a0);
    } else {  //ユーザモード
      m60FSLW = M60_FSLW_IOMA_FIRST | M60_FSLW_RW_READ | M60_FSLW_SIZE_BYTE | M60_FSLW_TM_USER_DATA;
      int a0 = mmuTranslateReadUserData (a);
      return (DataBreakPoint.DBP_ON ? DataBreakPoint.dbpUserMap : XEiJ.busUserMap)[a0 >>> XEiJ.BUS_PAGE_BITS].mmdRbs (a0);
    }
  }  //mmuReadByteSignData(int,int)

  //d = mmuReadByteZeroData (a, supervisor)
  //  リードバイトゼロ拡張(データ)
  public static int mmuReadByteZeroData (int a, int supervisor) throws M68kException {
    if (supervisor != 0) {  //スーパーバイザモード
      m60FSLW = M60_FSLW_IOMA_FIRST | M60_FSLW_RW_READ | M60_FSLW_SIZE_BYTE | M60_FSLW_TM_SUPER_DATA;
      int a0 = mmuTranslateReadSuperData (a);
      return (DataBreakPoint.DBP_ON ? DataBreakPoint.dbpSuperMap : XEiJ.busSuperMap)[a0 >>> XEiJ.BUS_PAGE_BITS].mmdRbz (a0);
    } else {  //ユーザモード
      m60FSLW = M60_FSLW_IOMA_FIRST | M60_FSLW_RW_READ | M60_FSLW_SIZE_BYTE | M60_FSLW_TM_USER_DATA;
      int a0 = mmuTranslateReadUserData (a);
      return (DataBreakPoint.DBP_ON ? DataBreakPoint.dbpUserMap : XEiJ.busUserMap)[a0 >>> XEiJ.BUS_PAGE_BITS].mmdRbz (a0);
    }
  }  //mmuReadByteZeroData(int,int)

  //d = mmuReadByteSignExword (a, supervisor)
  //  リードバイト符号拡張(拡張ワード)
  public static byte mmuReadByteSignExword (int a, int supervisor) throws M68kException {
    if (supervisor != 0) {  //スーパーバイザモード
      m60FSLW = M60_FSLW_IOMA_EXWORD | M60_FSLW_RW_READ | M60_FSLW_SIZE_BYTE | M60_FSLW_TM_SUPER_CODE;
      int a0 = mmuTranslateReadSuperCode (a);
      return (DataBreakPoint.DBP_ON ? DataBreakPoint.dbpSuperMap : XEiJ.busSuperMap)[a0 >>> XEiJ.BUS_PAGE_BITS].mmdRbs (a0);
    } else {  //ユーザモード
      m60FSLW = M60_FSLW_IOMA_EXWORD | M60_FSLW_RW_READ | M60_FSLW_SIZE_BYTE | M60_FSLW_TM_USER_CODE;
      int a0 = mmuTranslateReadUserCode (a);
      return (DataBreakPoint.DBP_ON ? DataBreakPoint.dbpUserMap : XEiJ.busUserMap)[a0 >>> XEiJ.BUS_PAGE_BITS].mmdRbs (a0);
    }
  }  //mmuReadByteSignExword(int,int)

  //d = mmuReadByteZeroExword (a, supervisor)
  //  リードバイトゼロ拡張(拡張ワード)
  public static int mmuReadByteZeroExword (int a, int supervisor) throws M68kException {
    if (supervisor != 0) {  //スーパーバイザモード
      m60FSLW = M60_FSLW_IOMA_EXWORD | M60_FSLW_RW_READ | M60_FSLW_SIZE_BYTE | M60_FSLW_TM_SUPER_CODE;
      int a0 = mmuTranslateReadSuperCode (a);
      return (DataBreakPoint.DBP_ON ? DataBreakPoint.dbpSuperMap : XEiJ.busSuperMap)[a0 >>> XEiJ.BUS_PAGE_BITS].mmdRbz (a0);
    } else {  //ユーザモード
      m60FSLW = M60_FSLW_IOMA_EXWORD | M60_FSLW_RW_READ | M60_FSLW_SIZE_BYTE | M60_FSLW_TM_USER_CODE;
      int a0 = mmuTranslateReadUserCode (a);
      return (DataBreakPoint.DBP_ON ? DataBreakPoint.dbpUserMap : XEiJ.busUserMap)[a0 >>> XEiJ.BUS_PAGE_BITS].mmdRbz (a0);
    }
  }  //mmuReadByteZeroExword(int,int)

  //d = mmuReadWordSignData (a, supervisor)
  //  リードワード符号拡張(データ)
  public static int mmuReadWordSignData (int a, int supervisor) throws M68kException {
    if (supervisor != 0) {  //スーパーバイザモード
      m60FSLW = M60_FSLW_IOMA_FIRST | M60_FSLW_RW_READ | M60_FSLW_SIZE_WORD | M60_FSLW_TM_SUPER_DATA;
      int a0 = mmuTranslateReadSuperData (a);  //a+1が必要なので上書き不可
      if ((a & 1) == 0) {  //偶数
        return (DataBreakPoint.DBP_ON ? DataBreakPoint.dbpSuperMap : XEiJ.busSuperMap)[a0 >>> XEiJ.BUS_PAGE_BITS].mmdRws (a0);
      } else {  //奇数
        int d0 = (DataBreakPoint.DBP_ON ? DataBreakPoint.dbpSuperMap : XEiJ.busSuperMap)[a0 >>> XEiJ.BUS_PAGE_BITS].mmdRbs (a0);
        m60FSLW ^= M60_FSLW_IOMA_FIRST ^ M60_FSLW_IOMA_SECOND;
        int a1 = mmuTranslateReadSuperData (a + 1);  //偶数
        return (d0 << 8 |
                (DataBreakPoint.DBP_ON ? DataBreakPoint.dbpSuperMap : XEiJ.busSuperMap)[a1 >>> XEiJ.BUS_PAGE_BITS].mmdRbz (a1));
      }
    } else {  //ユーザモード
      m60FSLW = M60_FSLW_IOMA_FIRST | M60_FSLW_RW_READ | M60_FSLW_SIZE_WORD | M60_FSLW_TM_USER_DATA;
      int a0 = mmuTranslateReadUserData (a);  //a+1が必要なので上書き不可
      if ((a & 1) == 0) {  //偶数
        return (DataBreakPoint.DBP_ON ? DataBreakPoint.dbpUserMap : XEiJ.busUserMap)[a0 >>> XEiJ.BUS_PAGE_BITS].mmdRws (a0);
      } else {  //奇数
        int d0 = (DataBreakPoint.DBP_ON ? DataBreakPoint.dbpUserMap : XEiJ.busUserMap)[a0 >>> XEiJ.BUS_PAGE_BITS].mmdRbs (a0);
        m60FSLW ^= M60_FSLW_IOMA_FIRST ^ M60_FSLW_IOMA_SECOND;
        int a1 = mmuTranslateReadUserData (a + 1);  //偶数
        return (d0 << 8 |
                (DataBreakPoint.DBP_ON ? DataBreakPoint.dbpUserMap : XEiJ.busUserMap)[a1 >>> XEiJ.BUS_PAGE_BITS].mmdRbz (a1));
      }
    }
  }  //mmuReadWordSignData(int,int)

  //d = mmuReadWordZeroData (a, supervisor)
  //  リードワードゼロ拡張(データ)
  public static int mmuReadWordZeroData (int a, int supervisor) throws M68kException {
    if (supervisor != 0) {  //スーパーバイザモード
      m60FSLW = M60_FSLW_IOMA_FIRST | M60_FSLW_RW_READ | M60_FSLW_SIZE_WORD | M60_FSLW_TM_SUPER_DATA;
      int a0 = mmuTranslateReadSuperData (a);  //a+1が必要なので上書き不可
      if ((a & 1) == 0) {  //偶数
        return (DataBreakPoint.DBP_ON ? DataBreakPoint.dbpSuperMap : XEiJ.busSuperMap)[a0 >>> XEiJ.BUS_PAGE_BITS].mmdRwz (a0);
      } else {  //奇数
        int d0 = (DataBreakPoint.DBP_ON ? DataBreakPoint.dbpSuperMap : XEiJ.busSuperMap)[a0 >>> XEiJ.BUS_PAGE_BITS].mmdRbz (a0);
        m60FSLW ^= M60_FSLW_IOMA_FIRST ^ M60_FSLW_IOMA_SECOND;
        int a1 = mmuTranslateReadSuperData (a + 1);  //偶数
        return (d0 << 8 |
                (DataBreakPoint.DBP_ON ? DataBreakPoint.dbpSuperMap : XEiJ.busSuperMap)[a1 >>> XEiJ.BUS_PAGE_BITS].mmdRbz (a1));
      }
    } else {  //ユーザモード
      m60FSLW = M60_FSLW_IOMA_FIRST | M60_FSLW_RW_READ | M60_FSLW_SIZE_WORD | M60_FSLW_TM_USER_DATA;
      int a0 = mmuTranslateReadUserData (a);  //a+1が必要なので上書き不可
      if ((a & 1) == 0) {  //偶数
        return (DataBreakPoint.DBP_ON ? DataBreakPoint.dbpUserMap : XEiJ.busUserMap)[a0 >>> XEiJ.BUS_PAGE_BITS].mmdRwz (a0);
      } else {  //奇数
        int d0 = (DataBreakPoint.DBP_ON ? DataBreakPoint.dbpUserMap : XEiJ.busUserMap)[a0 >>> XEiJ.BUS_PAGE_BITS].mmdRbz (a0);
        m60FSLW ^= M60_FSLW_IOMA_FIRST ^ M60_FSLW_IOMA_SECOND;
        int a1 = mmuTranslateReadUserData (a + 1);  //偶数
        return (d0 << 8 |
                (DataBreakPoint.DBP_ON ? DataBreakPoint.dbpUserMap : XEiJ.busUserMap)[a1 >>> XEiJ.BUS_PAGE_BITS].mmdRbz (a1));
      }
    }
  }  //mmuReadWordZeroData(int,int)

  //d = mmuReadWordSignEven (a, supervisor)
  //  リードワード符号拡張(偶数)
  public static int mmuReadWordSignEven (int a, int supervisor) throws M68kException {
    if (supervisor != 0) {  //スーパーバイザモード
      m60FSLW = M60_FSLW_IOMA_FIRST | M60_FSLW_RW_READ | M60_FSLW_SIZE_WORD | M60_FSLW_TM_SUPER_DATA;
      a = mmuTranslateReadSuperData (a);
      return (DataBreakPoint.DBP_ON ? DataBreakPoint.dbpSuperMap : XEiJ.busSuperMap)[a >>> XEiJ.BUS_PAGE_BITS].mmdRws (a);
    } else {  //ユーザモード
      m60FSLW = M60_FSLW_IOMA_FIRST | M60_FSLW_RW_READ | M60_FSLW_SIZE_WORD | M60_FSLW_TM_USER_DATA;
      a = mmuTranslateReadUserData (a);
      return (DataBreakPoint.DBP_ON ? DataBreakPoint.dbpUserMap : XEiJ.busUserMap)[a >>> XEiJ.BUS_PAGE_BITS].mmdRws (a);
    }
  }  //mmuReadWordSignEven(int,int)

  //d = mmuReadWordZeroEven (a, supervisor)
  //  リードワードゼロ拡張(偶数)
  public static int mmuReadWordZeroEven (int a, int supervisor) throws M68kException {
    if (supervisor != 0) {  //スーパーバイザモード
      m60FSLW = M60_FSLW_IOMA_FIRST | M60_FSLW_RW_READ | M60_FSLW_SIZE_WORD | M60_FSLW_TM_SUPER_DATA;
      a = mmuTranslateReadSuperData (a);
      return (DataBreakPoint.DBP_ON ? DataBreakPoint.dbpSuperMap : XEiJ.busSuperMap)[a >>> XEiJ.BUS_PAGE_BITS].mmdRwz (a);
    } else {  //ユーザモード
      m60FSLW = M60_FSLW_IOMA_FIRST | M60_FSLW_RW_READ | M60_FSLW_SIZE_WORD | M60_FSLW_TM_USER_DATA;
      a = mmuTranslateReadUserData (a);
      return (DataBreakPoint.DBP_ON ? DataBreakPoint.dbpUserMap : XEiJ.busUserMap)[a >>> XEiJ.BUS_PAGE_BITS].mmdRwz (a);
    }
  }  //mmuReadWordZeroEven(int,int)

  //d = mmuReadWordSignExword (a, supervisor)
  //  リードワード符号拡張(拡張ワード)
  public static int mmuReadWordSignExword (int a, int supervisor) throws M68kException {
    if (supervisor != 0) {  //スーパーバイザモード
      m60FSLW = M60_FSLW_IOMA_EXWORD | M60_FSLW_RW_READ | M60_FSLW_SIZE_WORD | M60_FSLW_TM_SUPER_CODE;
      a = mmuTranslateReadSuperCode (a);
      return (DataBreakPoint.DBP_ON ? DataBreakPoint.dbpSuperMap : XEiJ.busSuperMap)[a >>> XEiJ.BUS_PAGE_BITS].mmdRws (a);
    } else {  //ユーザモード
      m60FSLW = M60_FSLW_IOMA_EXWORD | M60_FSLW_RW_READ | M60_FSLW_SIZE_WORD | M60_FSLW_TM_USER_CODE;
      a = mmuTranslateReadUserCode (a);
      return (DataBreakPoint.DBP_ON ? DataBreakPoint.dbpUserMap : XEiJ.busUserMap)[a >>> XEiJ.BUS_PAGE_BITS].mmdRws (a);
    }
  }  //mmuReadWordSignExword(int,int)

  //d = mmuReadWordZeroExword (a, supervisor)
  //  リードワードゼロ拡張(拡張ワード)
  public static int mmuReadWordZeroExword (int a, int supervisor) throws M68kException {
    if (supervisor != 0) {  //スーパーバイザモード
      m60FSLW = M60_FSLW_IOMA_EXWORD | M60_FSLW_RW_READ | M60_FSLW_SIZE_WORD | M60_FSLW_TM_SUPER_CODE;
      a = mmuTranslateReadSuperCode (a);
      return (DataBreakPoint.DBP_ON ? DataBreakPoint.dbpSuperMap : XEiJ.busSuperMap)[a >>> XEiJ.BUS_PAGE_BITS].mmdRwz (a);
    } else {  //ユーザモード
      m60FSLW = M60_FSLW_IOMA_EXWORD | M60_FSLW_RW_READ | M60_FSLW_SIZE_WORD | M60_FSLW_TM_USER_CODE;
      a = mmuTranslateReadUserCode (a);
      return (DataBreakPoint.DBP_ON ? DataBreakPoint.dbpUserMap : XEiJ.busUserMap)[a >>> XEiJ.BUS_PAGE_BITS].mmdRwz (a);
    }
  }  //mmuReadWordZeroExword(int,int)

  //d = mmuReadWordSignOpword (a, supervisor)
  //  リードワード符号拡張(命令ワード)
  public static int mmuReadWordSignOpword (int a, int supervisor) throws M68kException {
    if (supervisor != 0) {  //スーパーバイザモード
      m60FSLW = M60_FSLW_IOMA_OPWORD | M60_FSLW_RW_READ | M60_FSLW_SIZE_WORD | M60_FSLW_TM_SUPER_CODE;
      a = mmuTranslateReadSuperCode (a);
      return (InstructionBreakPoint.IBP_ON ? InstructionBreakPoint.ibpOp1SuperMap : DataBreakPoint.DBP_ON ? DataBreakPoint.dbpSuperMap : XEiJ.busSuperMap)[a >>> XEiJ.BUS_PAGE_BITS].mmdRws (a);
    } else {  //ユーザモード
      m60FSLW = M60_FSLW_IOMA_OPWORD | M60_FSLW_RW_READ | M60_FSLW_SIZE_WORD | M60_FSLW_TM_USER_CODE;
      a = mmuTranslateReadUserCode (a);
      return (InstructionBreakPoint.IBP_ON ? InstructionBreakPoint.ibpOp1UserMap : DataBreakPoint.DBP_ON ? DataBreakPoint.dbpUserMap : XEiJ.busUserMap)[a >>> XEiJ.BUS_PAGE_BITS].mmdRws (a);
    }
  }  //mmuReadWordSignOpword(int,int)

  //d = mmuReadWordZeroOpword (a, supervisor)
  //  リードワードゼロ拡張(命令ワード)
  public static int mmuReadWordZeroOpword (int a, int supervisor) throws M68kException {
    if (supervisor != 0) {  //スーパーバイザモード
      m60FSLW = M60_FSLW_IOMA_OPWORD | M60_FSLW_RW_READ | M60_FSLW_SIZE_WORD | M60_FSLW_TM_SUPER_CODE;
      a = mmuTranslateReadSuperCode (a);
      return (InstructionBreakPoint.IBP_ON ? InstructionBreakPoint.ibpOp1SuperMap : DataBreakPoint.DBP_ON ? DataBreakPoint.dbpSuperMap : XEiJ.busSuperMap)[a >>> XEiJ.BUS_PAGE_BITS].mmdRwz (a);
    } else {  //ユーザモード
      m60FSLW = M60_FSLW_IOMA_OPWORD | M60_FSLW_RW_READ | M60_FSLW_SIZE_WORD | M60_FSLW_TM_USER_CODE;
      a = mmuTranslateReadUserCode (a);
      return (InstructionBreakPoint.IBP_ON ? InstructionBreakPoint.ibpOp1UserMap : DataBreakPoint.DBP_ON ? DataBreakPoint.dbpUserMap : XEiJ.busUserMap)[a >>> XEiJ.BUS_PAGE_BITS].mmdRwz (a);
    }
  }  //mmuReadWordZeroOpword(int,int)

  //d = mmuReadLongData (a, supervisor)
  //  リードロング(データ)
  public static int mmuReadLongData (int a, int supervisor) throws M68kException {
    if (supervisor != 0) {  //スーパーバイザモード
      m60FSLW = M60_FSLW_IOMA_FIRST | M60_FSLW_RW_READ | M60_FSLW_SIZE_LONG | M60_FSLW_TM_SUPER_DATA;
      int a0 = mmuTranslateReadSuperData (a);  //a+1,a+2,a+3が必要なので上書き不可
      if ((a & 3) == 0) {  //4の倍数
        return (DataBreakPoint.DBP_ON ? DataBreakPoint.dbpSuperMap : XEiJ.busSuperMap)[a0 >>> XEiJ.BUS_PAGE_BITS].mmdRls (a0);
      } else if ((a & 1) == 0) {  //4の倍数+2
        int d0 = (DataBreakPoint.DBP_ON ? DataBreakPoint.dbpSuperMap : XEiJ.busSuperMap)[a0 >>> XEiJ.BUS_PAGE_BITS].mmdRws (a0);
        m60FSLW ^= M60_FSLW_IOMA_FIRST ^ M60_FSLW_IOMA_SECOND;
        int a2 = mmuTranslateReadSuperData (a + 2);  //偶数
        return (d0 << 16 |
                (DataBreakPoint.DBP_ON ? DataBreakPoint.dbpSuperMap : XEiJ.busSuperMap)[a2 >>> XEiJ.BUS_PAGE_BITS].mmdRwz (a2));
      } else {  //奇数
        int d0 = (DataBreakPoint.DBP_ON ? DataBreakPoint.dbpSuperMap : XEiJ.busSuperMap)[a0 >>> XEiJ.BUS_PAGE_BITS].mmdRbs (a0);
        m60FSLW ^= M60_FSLW_IOMA_FIRST ^ M60_FSLW_IOMA_SECOND;
        int a1 = mmuTranslateReadSuperData (a + 1);  //偶数
        int a3 = mmuTranslateReadSuperData (a + 3);  //偶数
        return (d0 << 24 |
                (DataBreakPoint.DBP_ON ? DataBreakPoint.dbpSuperMap : XEiJ.busSuperMap)[a1 >>> XEiJ.BUS_PAGE_BITS].mmdRwz (a1) << 8 |
                (DataBreakPoint.DBP_ON ? DataBreakPoint.dbpSuperMap : XEiJ.busSuperMap)[a3 >>> XEiJ.BUS_PAGE_BITS].mmdRbz (a3));
      }
    } else {  //ユーザモード
      m60FSLW = M60_FSLW_IOMA_FIRST | M60_FSLW_RW_READ | M60_FSLW_SIZE_LONG | M60_FSLW_TM_USER_DATA;
      int a0 = mmuTranslateReadUserData (a);  //a+1,a+2,a+3が必要なので上書き不可
      if ((a & 3) == 0) {  //4の倍数
        return (DataBreakPoint.DBP_ON ? DataBreakPoint.dbpUserMap : XEiJ.busUserMap)[a0 >>> XEiJ.BUS_PAGE_BITS].mmdRls (a0);
      } else if ((a & 1) == 0) {  //4の倍数+2
        int d0 = (DataBreakPoint.DBP_ON ? DataBreakPoint.dbpUserMap : XEiJ.busUserMap)[a0 >>> XEiJ.BUS_PAGE_BITS].mmdRws (a0);
        m60FSLW ^= M60_FSLW_IOMA_FIRST ^ M60_FSLW_IOMA_SECOND;
        int a2 = mmuTranslateReadUserData (a + 2);  //偶数
        return (d0 << 16 |
                (DataBreakPoint.DBP_ON ? DataBreakPoint.dbpUserMap : XEiJ.busUserMap)[a2 >>> XEiJ.BUS_PAGE_BITS].mmdRwz (a2));
      } else {  //奇数
        int d0 = (DataBreakPoint.DBP_ON ? DataBreakPoint.dbpUserMap : XEiJ.busUserMap)[a0 >>> XEiJ.BUS_PAGE_BITS].mmdRbs (a0);
        m60FSLW ^= M60_FSLW_IOMA_FIRST ^ M60_FSLW_IOMA_SECOND;
        int a1 = mmuTranslateReadUserData (a + 1);  //偶数
        int a3 = mmuTranslateReadUserData (a + 3);  //偶数
        return (d0 << 24 |
                (DataBreakPoint.DBP_ON ? DataBreakPoint.dbpUserMap : XEiJ.busUserMap)[a1 >>> XEiJ.BUS_PAGE_BITS].mmdRwz (a1) << 8 |
                (DataBreakPoint.DBP_ON ? DataBreakPoint.dbpUserMap : XEiJ.busUserMap)[a3 >>> XEiJ.BUS_PAGE_BITS].mmdRbz (a3));
      }
    }
  }  //mmuReadLongData(int,int)

  //d = mmuReadLongEven (a, supervisor)
  //  リードロング(偶数)
  public static int mmuReadLongEven (int a, int supervisor) throws M68kException {
    if (supervisor != 0) {  //スーパーバイザモード
      m60FSLW = M60_FSLW_IOMA_FIRST | M60_FSLW_RW_READ | M60_FSLW_SIZE_LONG | M60_FSLW_TM_SUPER_DATA;
      int a0 = mmuTranslateReadSuperData (a);  //a+2が必要なので上書き不可
      if ((a & 2) == 0) {  //4の倍数
        return (DataBreakPoint.DBP_ON ? DataBreakPoint.dbpSuperMap : XEiJ.busSuperMap)[a0 >>> XEiJ.BUS_PAGE_BITS].mmdRls (a0);
      } else {  //4の倍数+2
        int d0 = (DataBreakPoint.DBP_ON ? DataBreakPoint.dbpSuperMap : XEiJ.busSuperMap)[a0 >>> XEiJ.BUS_PAGE_BITS].mmdRws (a0);
        m60FSLW ^= M60_FSLW_IOMA_FIRST ^ M60_FSLW_IOMA_SECOND;
        int a2 = mmuTranslateReadSuperData (a + 2);  //偶数
        return (d0 << 16 |
                (DataBreakPoint.DBP_ON ? DataBreakPoint.dbpSuperMap : XEiJ.busSuperMap)[a2 >>> XEiJ.BUS_PAGE_BITS].mmdRwz (a2));
      }
    } else {  //ユーザモード
      m60FSLW = M60_FSLW_IOMA_FIRST | M60_FSLW_RW_READ | M60_FSLW_SIZE_LONG | M60_FSLW_TM_USER_DATA;
      int a0 = mmuTranslateReadUserData (a);  //a+2が必要なので上書き不可
      if ((a & 2) == 0) {  //4の倍数
        return (DataBreakPoint.DBP_ON ? DataBreakPoint.dbpUserMap : XEiJ.busUserMap)[a0 >>> XEiJ.BUS_PAGE_BITS].mmdRls (a0);
      } else {  //4の倍数+2
        int d0 = (DataBreakPoint.DBP_ON ? DataBreakPoint.dbpUserMap : XEiJ.busUserMap)[a0 >>> XEiJ.BUS_PAGE_BITS].mmdRws (a0);
        m60FSLW ^= M60_FSLW_IOMA_FIRST ^ M60_FSLW_IOMA_SECOND;
        int a2 = mmuTranslateReadUserData (a + 2);  //偶数
        return (d0 << 16 |
                (DataBreakPoint.DBP_ON ? DataBreakPoint.dbpUserMap : XEiJ.busUserMap)[a2 >>> XEiJ.BUS_PAGE_BITS].mmdRwz (a2));
      }
    }
  }  //mmuReadLongEven(int,int)

  //d = mmuReadLongExword (a, supervisor)
  //  リードロング(拡張ワード)
  public static int mmuReadLongExword (int a, int supervisor) throws M68kException {
    if (supervisor != 0) {  //スーパーバイザモード
      m60FSLW = M60_FSLW_IOMA_EXWORD | M60_FSLW_RW_READ | M60_FSLW_SIZE_LONG | M60_FSLW_TM_SUPER_CODE;
      int a0 = mmuTranslateReadSuperData (a);  //a+2が必要なので上書き不可
      if ((a & 2) == 0) {  //4の倍数
        return (DataBreakPoint.DBP_ON ? DataBreakPoint.dbpSuperMap : XEiJ.busSuperMap)[a0 >>> XEiJ.BUS_PAGE_BITS].mmdRls (a0);
      } else {  //4の倍数+2
        int a2 = mmuTranslateReadSuperData (a + 2);  //偶数
        return ((DataBreakPoint.DBP_ON ? DataBreakPoint.dbpSuperMap : XEiJ.busSuperMap)[a0 >>> XEiJ.BUS_PAGE_BITS].mmdRws (a0) << 16 |
                (DataBreakPoint.DBP_ON ? DataBreakPoint.dbpSuperMap : XEiJ.busSuperMap)[a2 >>> XEiJ.BUS_PAGE_BITS].mmdRwz (a2));
      }
    } else {  //ユーザモード
      m60FSLW = M60_FSLW_IOMA_EXWORD | M60_FSLW_RW_READ | M60_FSLW_SIZE_LONG | M60_FSLW_TM_USER_CODE;
      int a0 = mmuTranslateReadUserData (a);  //a+2が必要なので上書き不可
      if ((a & 2) == 0) {  //4の倍数
        return (DataBreakPoint.DBP_ON ? DataBreakPoint.dbpUserMap : XEiJ.busUserMap)[a0 >>> XEiJ.BUS_PAGE_BITS].mmdRls (a0);
      } else {  //4の倍数+2
        int a2 = mmuTranslateReadUserData (a + 2);  //偶数
        return ((DataBreakPoint.DBP_ON ? DataBreakPoint.dbpUserMap : XEiJ.busUserMap)[a0 >>> XEiJ.BUS_PAGE_BITS].mmdRws (a0) << 16 |
                (DataBreakPoint.DBP_ON ? DataBreakPoint.dbpUserMap : XEiJ.busUserMap)[a2 >>> XEiJ.BUS_PAGE_BITS].mmdRwz (a2));
      }
    }
  }  //mmuReadLongExword(int,int)

  //d = mmuReadLongFour (a, supervisor)
  //  リードロング(4の倍数)
  public static int mmuReadLongFour (int a, int supervisor) throws M68kException {
    if (supervisor != 0) {  //スーパーバイザモード
      m60FSLW = M60_FSLW_IOMA_FIRST | M60_FSLW_RW_READ | M60_FSLW_SIZE_LONG | M60_FSLW_TM_SUPER_DATA;
      a = mmuTranslateReadSuperData (a);
      return (DataBreakPoint.DBP_ON ? DataBreakPoint.dbpSuperMap : XEiJ.busSuperMap)[a >>> XEiJ.BUS_PAGE_BITS].mmdRls (a);
    } else {  //ユーザモード
      m60FSLW = M60_FSLW_IOMA_FIRST | M60_FSLW_RW_READ | M60_FSLW_SIZE_LONG | M60_FSLW_TM_USER_DATA;
      a = mmuTranslateReadUserData (a);
      return (DataBreakPoint.DBP_ON ? DataBreakPoint.dbpUserMap : XEiJ.busUserMap)[a >>> XEiJ.BUS_PAGE_BITS].mmdRls (a);
    }
  }  //mmuReadLongFour(int,int)

  //l = mmuReadQuadData (a, supervisor)
  //  リードクワッド(データ)
  public static long mmuReadQuadData (int a, int supervisor) throws M68kException {
    long d;
    if (supervisor != 0) {  //スーパーバイザモード
      final MemoryMappedDevice[] map = DataBreakPoint.DBP_ON ? DataBreakPoint.dbpSuperMap : XEiJ.busSuperMap;
      m60FSLW = M60_FSLW_IOMA_FIRST | M60_FSLW_RW_READ | M60_FSLW_SIZE_QUAD | M60_FSLW_TM_SUPER_DATA;
      int t = mmuTranslateReadSuperData (a);
      if ((a & 3) == 0) {  //4n
        d = (long) map[t >>> XEiJ.BUS_PAGE_BITS].mmdRls (t);
        m60FSLW = M60_FSLW_IOMA_SECOND | M60_FSLW_RW_READ | M60_FSLW_SIZE_QUAD | M60_FSLW_TM_SUPER_DATA;
        t = mmuTranslateReadSuperData (a + 4);
        d = d << 32 | (0xffffffffL & (long) map[t >>> XEiJ.BUS_PAGE_BITS].mmdRls (t));
      } else if ((a & 1) == 0) {  //4n+2
        d = (long) map[t >>> XEiJ.BUS_PAGE_BITS].mmdRws (t);
        m60FSLW = M60_FSLW_IOMA_SECOND | M60_FSLW_RW_READ | M60_FSLW_SIZE_QUAD | M60_FSLW_TM_SUPER_DATA;
        t = mmuTranslateReadSuperData (a + 2);
        d = d << 32 | (0xffffffffL & (long) map[t >>> XEiJ.BUS_PAGE_BITS].mmdRls (t));
        m60FSLW = M60_FSLW_IOMA_SECOND | M60_FSLW_RW_READ | M60_FSLW_SIZE_QUAD | M60_FSLW_TM_SUPER_DATA;
        t = mmuTranslateReadSuperData (a + 6);
        d = d << 16 | (long) map[t >>> XEiJ.BUS_PAGE_BITS].mmdRwz (t);
      } else if ((a & 3) == 1) {  //4n+1
        d = (long) map[t >>> XEiJ.BUS_PAGE_BITS].mmdRbs (t);
        m60FSLW = M60_FSLW_IOMA_SECOND | M60_FSLW_RW_READ | M60_FSLW_SIZE_QUAD | M60_FSLW_TM_SUPER_DATA;
        t = mmuTranslateReadSuperData (a + 1);
        d = d << 16 | (long) map[t >>> XEiJ.BUS_PAGE_BITS].mmdRwz (t);
        m60FSLW = M60_FSLW_IOMA_SECOND | M60_FSLW_RW_READ | M60_FSLW_SIZE_QUAD | M60_FSLW_TM_SUPER_DATA;
        t = mmuTranslateReadSuperData (a + 3);
        d = d << 32 | (0xffffffffL & (long) map[t >>> XEiJ.BUS_PAGE_BITS].mmdRls (t));
        m60FSLW = M60_FSLW_IOMA_SECOND | M60_FSLW_RW_READ | M60_FSLW_SIZE_QUAD | M60_FSLW_TM_SUPER_DATA;
        t = mmuTranslateReadSuperData (a + 7);
        d = d << 8 | (long) map[t >>> XEiJ.BUS_PAGE_BITS].mmdRbz (t);
      } else {  //  //4n+3
        d = (long) map[t >>> XEiJ.BUS_PAGE_BITS].mmdRbs (t);
        m60FSLW = M60_FSLW_IOMA_SECOND | M60_FSLW_RW_READ | M60_FSLW_SIZE_QUAD | M60_FSLW_TM_SUPER_DATA;
        t = mmuTranslateReadSuperData (a + 1);
        d = d << 32 | (0xffffffffL & (long) map[t >>> XEiJ.BUS_PAGE_BITS].mmdRls (t));
        m60FSLW = M60_FSLW_IOMA_SECOND | M60_FSLW_RW_READ | M60_FSLW_SIZE_QUAD | M60_FSLW_TM_SUPER_DATA;
        t = mmuTranslateReadSuperData (a + 5);
        d = d << 16 | (long) map[t >>> XEiJ.BUS_PAGE_BITS].mmdRwz (t);
        m60FSLW = M60_FSLW_IOMA_SECOND | M60_FSLW_RW_READ | M60_FSLW_SIZE_QUAD | M60_FSLW_TM_SUPER_DATA;
        t = mmuTranslateReadSuperData (a + 7);
        d = d << 8 | (long) map[t >>> XEiJ.BUS_PAGE_BITS].mmdRbz (t);
      }
    } else {  //ユーザモード
      final MemoryMappedDevice[] map = DataBreakPoint.DBP_ON ? DataBreakPoint.dbpUserMap : XEiJ.busUserMap;
      m60FSLW = M60_FSLW_IOMA_FIRST | M60_FSLW_RW_READ | M60_FSLW_SIZE_QUAD | M60_FSLW_TM_USER_DATA;
      int t = mmuTranslateReadUserData (a);
      if ((a & 3) == 0) {  //4n
        d = (long) map[t >>> XEiJ.BUS_PAGE_BITS].mmdRls (t);
        m60FSLW = M60_FSLW_IOMA_SECOND | M60_FSLW_RW_READ | M60_FSLW_SIZE_QUAD | M60_FSLW_TM_USER_DATA;
        t = mmuTranslateReadUserData (a + 4);
        d = d << 32 | (0xffffffffL & (long) map[t >>> XEiJ.BUS_PAGE_BITS].mmdRls (t));
      } else if ((a & 1) == 0) {  //4n+2
        d = (long) map[t >>> XEiJ.BUS_PAGE_BITS].mmdRws (t);
        m60FSLW = M60_FSLW_IOMA_SECOND | M60_FSLW_RW_READ | M60_FSLW_SIZE_QUAD | M60_FSLW_TM_USER_DATA;
        t = mmuTranslateReadUserData (a + 2);
        d = d << 32 | (0xffffffffL & (long) map[t >>> XEiJ.BUS_PAGE_BITS].mmdRls (t));
        m60FSLW = M60_FSLW_IOMA_SECOND | M60_FSLW_RW_READ | M60_FSLW_SIZE_QUAD | M60_FSLW_TM_USER_DATA;
        t = mmuTranslateReadUserData (a + 6);
        d = d << 16 | (long) map[t >>> XEiJ.BUS_PAGE_BITS].mmdRwz (t);
      } else if ((a & 3) == 1) {  //4n+1
        d = (long) map[t >>> XEiJ.BUS_PAGE_BITS].mmdRbs (t);
        m60FSLW = M60_FSLW_IOMA_SECOND | M60_FSLW_RW_READ | M60_FSLW_SIZE_QUAD | M60_FSLW_TM_USER_DATA;
        t = mmuTranslateReadUserData (a + 1);
        d = d << 16 | (long) map[t >>> XEiJ.BUS_PAGE_BITS].mmdRwz (t);
        m60FSLW = M60_FSLW_IOMA_SECOND | M60_FSLW_RW_READ | M60_FSLW_SIZE_QUAD | M60_FSLW_TM_USER_DATA;
        t = mmuTranslateReadUserData (a + 3);
        d = d << 32 | (0xffffffffL & (long) map[t >>> XEiJ.BUS_PAGE_BITS].mmdRls (t));
        m60FSLW = M60_FSLW_IOMA_SECOND | M60_FSLW_RW_READ | M60_FSLW_SIZE_QUAD | M60_FSLW_TM_USER_DATA;
        t = mmuTranslateReadUserData (a + 7);
        d = d << 8 | (long) map[t >>> XEiJ.BUS_PAGE_BITS].mmdRbz (t);
      } else {  //  //4n+3
        d = (long) map[t >>> XEiJ.BUS_PAGE_BITS].mmdRbs (t);
        m60FSLW = M60_FSLW_IOMA_SECOND | M60_FSLW_RW_READ | M60_FSLW_SIZE_QUAD | M60_FSLW_TM_USER_DATA;
        t = mmuTranslateReadUserData (a + 1);
        d = d << 32 | (0xffffffffL & (long) map[t >>> XEiJ.BUS_PAGE_BITS].mmdRls (t));
        m60FSLW = M60_FSLW_IOMA_SECOND | M60_FSLW_RW_READ | M60_FSLW_SIZE_QUAD | M60_FSLW_TM_USER_DATA;
        t = mmuTranslateReadUserData (a + 5);
        d = d << 16 | (long) map[t >>> XEiJ.BUS_PAGE_BITS].mmdRwz (t);
        m60FSLW = M60_FSLW_IOMA_SECOND | M60_FSLW_RW_READ | M60_FSLW_SIZE_QUAD | M60_FSLW_TM_USER_DATA;
        t = mmuTranslateReadUserData (a + 7);
        d = d << 8 | (long) map[t >>> XEiJ.BUS_PAGE_BITS].mmdRbz (t);
      }
    }
    return d;
  }  //mmuReadQuadData(int,int)

  //l = mmuReadQuadSecond (a, supervisor)
  //  リードクワッド(2番目)
  //  エクステンデッドとラインの2番目で使う
  public static long mmuReadQuadSecond (int a, int supervisor) throws M68kException {
    long d;
    if (supervisor != 0) {  //スーパーバイザモード
      final MemoryMappedDevice[] map = DataBreakPoint.DBP_ON ? DataBreakPoint.dbpSuperMap : XEiJ.busSuperMap;
      m60FSLW = M60_FSLW_IOMA_SECOND | M60_FSLW_RW_READ | M60_FSLW_SIZE_QUAD | M60_FSLW_TM_SUPER_DATA;
      int t = mmuTranslateReadSuperData (a);
      if ((a & 3) == 0) {  //4n
        d = (long) map[t >>> XEiJ.BUS_PAGE_BITS].mmdRls (t);
        m60FSLW = M60_FSLW_IOMA_SECOND | M60_FSLW_RW_READ | M60_FSLW_SIZE_QUAD | M60_FSLW_TM_SUPER_DATA;
        t = mmuTranslateReadSuperData (a + 4);
        d = d << 32 | (0xffffffffL & (long) map[t >>> XEiJ.BUS_PAGE_BITS].mmdRls (t));
      } else if ((a & 1) == 0) {  //4n+2
        d = (long) map[t >>> XEiJ.BUS_PAGE_BITS].mmdRws (t);
        m60FSLW = M60_FSLW_IOMA_SECOND | M60_FSLW_RW_READ | M60_FSLW_SIZE_QUAD | M60_FSLW_TM_SUPER_DATA;
        t = mmuTranslateReadSuperData (a + 2);
        d = d << 32 | (0xffffffffL & (long) map[t >>> XEiJ.BUS_PAGE_BITS].mmdRls (t));
        m60FSLW = M60_FSLW_IOMA_SECOND | M60_FSLW_RW_READ | M60_FSLW_SIZE_QUAD | M60_FSLW_TM_SUPER_DATA;
        t = mmuTranslateReadSuperData (a + 6);
        d = d << 16 | (long) map[t >>> XEiJ.BUS_PAGE_BITS].mmdRwz (t);
      } else if ((a & 3) == 1) {  //4n+1
        d = (long) map[t >>> XEiJ.BUS_PAGE_BITS].mmdRbs (t);
        m60FSLW = M60_FSLW_IOMA_SECOND | M60_FSLW_RW_READ | M60_FSLW_SIZE_QUAD | M60_FSLW_TM_SUPER_DATA;
        t = mmuTranslateReadSuperData (a + 1);
        d = d << 16 | (long) map[t >>> XEiJ.BUS_PAGE_BITS].mmdRwz (t);
        m60FSLW = M60_FSLW_IOMA_SECOND | M60_FSLW_RW_READ | M60_FSLW_SIZE_QUAD | M60_FSLW_TM_SUPER_DATA;
        t = mmuTranslateReadSuperData (a + 3);
        d = d << 32 | (0xffffffffL & (long) map[t >>> XEiJ.BUS_PAGE_BITS].mmdRls (t));
        m60FSLW = M60_FSLW_IOMA_SECOND | M60_FSLW_RW_READ | M60_FSLW_SIZE_QUAD | M60_FSLW_TM_SUPER_DATA;
        t = mmuTranslateReadSuperData (a + 7);
        d = d << 8 | (long) map[t >>> XEiJ.BUS_PAGE_BITS].mmdRbz (t);
      } else {  //  //4n+3
        d = (long) map[t >>> XEiJ.BUS_PAGE_BITS].mmdRbs (t);
        m60FSLW = M60_FSLW_IOMA_SECOND | M60_FSLW_RW_READ | M60_FSLW_SIZE_QUAD | M60_FSLW_TM_SUPER_DATA;
        t = mmuTranslateReadSuperData (a + 1);
        d = d << 32 | (0xffffffffL & (long) map[t >>> XEiJ.BUS_PAGE_BITS].mmdRls (t));
        m60FSLW = M60_FSLW_IOMA_SECOND | M60_FSLW_RW_READ | M60_FSLW_SIZE_QUAD | M60_FSLW_TM_SUPER_DATA;
        t = mmuTranslateReadSuperData (a + 5);
        d = d << 16 | (long) map[t >>> XEiJ.BUS_PAGE_BITS].mmdRwz (t);
        m60FSLW = M60_FSLW_IOMA_SECOND | M60_FSLW_RW_READ | M60_FSLW_SIZE_QUAD | M60_FSLW_TM_SUPER_DATA;
        t = mmuTranslateReadSuperData (a + 7);
        d = d << 8 | (long) map[t >>> XEiJ.BUS_PAGE_BITS].mmdRbz (t);
      }
    } else {  //ユーザモード
      final MemoryMappedDevice[] map = DataBreakPoint.DBP_ON ? DataBreakPoint.dbpUserMap : XEiJ.busUserMap;
      m60FSLW = M60_FSLW_IOMA_SECOND | M60_FSLW_RW_READ | M60_FSLW_SIZE_QUAD | M60_FSLW_TM_USER_DATA;
      int t = mmuTranslateReadUserData (a);
      if ((a & 3) == 0) {  //4n
        d = (long) map[t >>> XEiJ.BUS_PAGE_BITS].mmdRls (t);
        m60FSLW = M60_FSLW_IOMA_SECOND | M60_FSLW_RW_READ | M60_FSLW_SIZE_QUAD | M60_FSLW_TM_USER_DATA;
        t = mmuTranslateReadUserData (a + 4);
        d = d << 32 | (0xffffffffL & (long) map[t >>> XEiJ.BUS_PAGE_BITS].mmdRls (t));
      } else if ((a & 1) == 0) {  //4n+2
        d = (long) map[t >>> XEiJ.BUS_PAGE_BITS].mmdRws (t);
        m60FSLW = M60_FSLW_IOMA_SECOND | M60_FSLW_RW_READ | M60_FSLW_SIZE_QUAD | M60_FSLW_TM_USER_DATA;
        t = mmuTranslateReadUserData (a + 2);
        d = d << 32 | (0xffffffffL & (long) map[t >>> XEiJ.BUS_PAGE_BITS].mmdRls (t));
        m60FSLW = M60_FSLW_IOMA_SECOND | M60_FSLW_RW_READ | M60_FSLW_SIZE_QUAD | M60_FSLW_TM_USER_DATA;
        t = mmuTranslateReadUserData (a + 6);
        d = d << 16 | (long) map[t >>> XEiJ.BUS_PAGE_BITS].mmdRwz (t);
      } else if ((a & 3) == 1) {  //4n+1
        d = (long) map[t >>> XEiJ.BUS_PAGE_BITS].mmdRbs (t);
        m60FSLW = M60_FSLW_IOMA_SECOND | M60_FSLW_RW_READ | M60_FSLW_SIZE_QUAD | M60_FSLW_TM_USER_DATA;
        t = mmuTranslateReadUserData (a + 1);
        d = d << 16 | (long) map[t >>> XEiJ.BUS_PAGE_BITS].mmdRwz (t);
        m60FSLW = M60_FSLW_IOMA_SECOND | M60_FSLW_RW_READ | M60_FSLW_SIZE_QUAD | M60_FSLW_TM_USER_DATA;
        t = mmuTranslateReadUserData (a + 3);
        d = d << 32 | (0xffffffffL & (long) map[t >>> XEiJ.BUS_PAGE_BITS].mmdRls (t));
        m60FSLW = M60_FSLW_IOMA_SECOND | M60_FSLW_RW_READ | M60_FSLW_SIZE_QUAD | M60_FSLW_TM_USER_DATA;
        t = mmuTranslateReadUserData (a + 7);
        d = d << 8 | (long) map[t >>> XEiJ.BUS_PAGE_BITS].mmdRbz (t);
      } else {  //  //4n+3
        d = (long) map[t >>> XEiJ.BUS_PAGE_BITS].mmdRbs (t);
        m60FSLW = M60_FSLW_IOMA_SECOND | M60_FSLW_RW_READ | M60_FSLW_SIZE_QUAD | M60_FSLW_TM_USER_DATA;
        t = mmuTranslateReadUserData (a + 1);
        d = d << 32 | (0xffffffffL & (long) map[t >>> XEiJ.BUS_PAGE_BITS].mmdRls (t));
        m60FSLW = M60_FSLW_IOMA_SECOND | M60_FSLW_RW_READ | M60_FSLW_SIZE_QUAD | M60_FSLW_TM_USER_DATA;
        t = mmuTranslateReadUserData (a + 5);
        d = d << 16 | (long) map[t >>> XEiJ.BUS_PAGE_BITS].mmdRwz (t);
        m60FSLW = M60_FSLW_IOMA_SECOND | M60_FSLW_RW_READ | M60_FSLW_SIZE_QUAD | M60_FSLW_TM_USER_DATA;
        t = mmuTranslateReadUserData (a + 7);
        d = d << 8 | (long) map[t >>> XEiJ.BUS_PAGE_BITS].mmdRbz (t);
      }
    }
    return d;
  }  //mmuReadQuadSecond(int,int)

  //l = mmuReadQuadExword (a, supervisor)
  //  リードクワッド(拡張ワード)
  //  イミディエイトで使う
  public static long mmuReadQuadExword (int a, int supervisor) throws M68kException {
    if (supervisor != 0) {  //スーパーバイザモード
      m60FSLW = M60_FSLW_IOMA_EXWORD | M60_FSLW_RW_READ | M60_FSLW_SIZE_QUAD | M60_FSLW_TM_SUPER_CODE;
      int a0 = mmuTranslateReadSuperData (a);  //a+2,a+4,a+6が必要なので上書き不可
      if ((a & 2) == 0) {  //4の倍数
        int a4 = mmuTranslateReadSuperData (a + 4);  //4の倍数
        return ((long) (DataBreakPoint.DBP_ON ? DataBreakPoint.dbpSuperMap : XEiJ.busSuperMap)[a0 >>> XEiJ.BUS_PAGE_BITS].mmdRls (a0) << 32 |
                (long) (DataBreakPoint.DBP_ON ? DataBreakPoint.dbpSuperMap : XEiJ.busSuperMap)[a4 >>> XEiJ.BUS_PAGE_BITS].mmdRls (a4) & 0x00000000ffffffffL);
      } else {  //4の倍数+2
        int a2 = mmuTranslateReadSuperData (a + 2);  //4の倍数
        int a6 = mmuTranslateReadSuperData (a + 6);  //4の倍数
        return ((long) (DataBreakPoint.DBP_ON ? DataBreakPoint.dbpSuperMap : XEiJ.busSuperMap)[a0 >>> XEiJ.BUS_PAGE_BITS].mmdRws (a0) << 48 |
                (long) (DataBreakPoint.DBP_ON ? DataBreakPoint.dbpSuperMap : XEiJ.busSuperMap)[a2 >>> XEiJ.BUS_PAGE_BITS].mmdRls (a2) << 16 & 0x0000ffffffff0000L |
                (long) (DataBreakPoint.DBP_ON ? DataBreakPoint.dbpSuperMap : XEiJ.busSuperMap)[a6 >>> XEiJ.BUS_PAGE_BITS].mmdRwz (a6));
      }
    } else {  //ユーザモード
      m60FSLW = M60_FSLW_IOMA_EXWORD | M60_FSLW_RW_READ | M60_FSLW_SIZE_QUAD | M60_FSLW_TM_USER_CODE;
      int a0 = mmuTranslateReadUserData (a);  //a+2,a+4,a+6が必要なので上書き不可
      if ((a & 2) == 0) {  //4の倍数
        int a4 = mmuTranslateReadUserData (a + 4);  //4の倍数
        return ((long) (DataBreakPoint.DBP_ON ? DataBreakPoint.dbpUserMap : XEiJ.busUserMap)[a0 >>> XEiJ.BUS_PAGE_BITS].mmdRls (a0) << 32 |
                (long) (DataBreakPoint.DBP_ON ? DataBreakPoint.dbpUserMap : XEiJ.busUserMap)[a4 >>> XEiJ.BUS_PAGE_BITS].mmdRls (a4) & 0x00000000ffffffffL);
      } else {  //4の倍数+2
        int a2 = mmuTranslateReadUserData (a + 2);  //4の倍数
        int a6 = mmuTranslateReadUserData (a + 6);  //4の倍数
        return ((long) (DataBreakPoint.DBP_ON ? DataBreakPoint.dbpUserMap : XEiJ.busUserMap)[a0 >>> XEiJ.BUS_PAGE_BITS].mmdRws (a0) << 48 |
                (long) (DataBreakPoint.DBP_ON ? DataBreakPoint.dbpUserMap : XEiJ.busUserMap)[a2 >>> XEiJ.BUS_PAGE_BITS].mmdRls (a2) << 16 & 0x0000ffffffff0000L |
                (long) (DataBreakPoint.DBP_ON ? DataBreakPoint.dbpUserMap : XEiJ.busUserMap)[a6 >>> XEiJ.BUS_PAGE_BITS].mmdRwz (a6));
      }
    }
  }  //mmuReadQuadExword(int,int)

  //--------------------------------------------------------------------------------
  //リードモディファイライトのリード
  //  アドレス変換はライト
  //  FSLWのRead and WriteはRead-Modify-Write

  //d = mmuModifyByteSignData (a, supervisor)
  //  リードモディファイライトのリードバイト符号拡張(データ)
  public static byte mmuModifyByteSignData (int a, int supervisor) throws M68kException {
    if (supervisor != 0) {  //スーパーバイザモード
      m60FSLW = M60_FSLW_IOMA_FIRST | M60_FSLW_RW_MODIFY | M60_FSLW_SIZE_BYTE | M60_FSLW_TM_SUPER_DATA;
      int a0 = mmuTranslateWriteSuperData (a);
      return (a ^ a0) == 1 ? -1 : (DataBreakPoint.DBP_ON ? DataBreakPoint.dbpSuperMap : XEiJ.busSuperMap)[a0 >>> XEiJ.BUS_PAGE_BITS].mmdRbs (a0);
    } else {  //ユーザモード
      m60FSLW = M60_FSLW_IOMA_FIRST | M60_FSLW_RW_MODIFY | M60_FSLW_SIZE_BYTE | M60_FSLW_TM_USER_DATA;
      int a0 = mmuTranslateWriteUserData (a);
      return (a ^ a0) == 1 ? -1 : (DataBreakPoint.DBP_ON ? DataBreakPoint.dbpUserMap : XEiJ.busUserMap)[a0 >>> XEiJ.BUS_PAGE_BITS].mmdRbs (a0);
    }
  }  //mmuModifyByteSignData(int,int)

  //d = mmuModifyByteZeroData (a, supervisor)
  //  リードモディファイライトのリードバイトゼロ拡張(データ)
  public static int mmuModifyByteZeroData (int a, int supervisor) throws M68kException {
    if (supervisor != 0) {  //スーパーバイザモード
      m60FSLW = M60_FSLW_IOMA_FIRST | M60_FSLW_RW_MODIFY | M60_FSLW_SIZE_BYTE | M60_FSLW_TM_SUPER_DATA;
      int a0 = mmuTranslateWriteSuperData (a);
      return (a ^ a0) == 1 ? 255 : (DataBreakPoint.DBP_ON ? DataBreakPoint.dbpSuperMap : XEiJ.busSuperMap)[a0 >>> XEiJ.BUS_PAGE_BITS].mmdRbz (a0);
    } else {  //ユーザモード
      m60FSLW = M60_FSLW_IOMA_FIRST | M60_FSLW_RW_MODIFY | M60_FSLW_SIZE_BYTE | M60_FSLW_TM_USER_DATA;
      int a0 = mmuTranslateWriteUserData (a);
      return (a ^ a0) == 1 ? 255 : (DataBreakPoint.DBP_ON ? DataBreakPoint.dbpUserMap : XEiJ.busUserMap)[a0 >>> XEiJ.BUS_PAGE_BITS].mmdRbz (a0);
    }
  }  //mmuModifyByteZeroData(int,int)

  //d = mmuModifyWordSignData (a, supervisor)
  //  リードモディファイライトのリードワード符号拡張(データ)
  public static int mmuModifyWordSignData (int a, int supervisor) throws M68kException {
    if (supervisor != 0) {  //スーパーバイザモード
      m60FSLW = M60_FSLW_IOMA_FIRST | M60_FSLW_RW_MODIFY | M60_FSLW_SIZE_WORD | M60_FSLW_TM_SUPER_DATA;
      int a0 = mmuTranslateWriteSuperData (a);  //a+1が必要なので上書き不可
      if ((a & 1) == 0) {  //偶数
        return (DataBreakPoint.DBP_ON ? DataBreakPoint.dbpSuperMap : XEiJ.busSuperMap)[a0 >>> XEiJ.BUS_PAGE_BITS].mmdRws (a0);
      } else {  //奇数
        int d0 = (DataBreakPoint.DBP_ON ? DataBreakPoint.dbpSuperMap : XEiJ.busSuperMap)[a0 >>> XEiJ.BUS_PAGE_BITS].mmdRbs (a0);
        m60FSLW ^= M60_FSLW_IOMA_FIRST ^ M60_FSLW_IOMA_SECOND;
        int a1 = mmuTranslateWriteSuperData (a + 1);  //偶数
        return (d0 << 8 |
                (DataBreakPoint.DBP_ON ? DataBreakPoint.dbpSuperMap : XEiJ.busSuperMap)[a1 >>> XEiJ.BUS_PAGE_BITS].mmdRbz (a1));
      }
    } else {  //ユーザモード
      m60FSLW = M60_FSLW_IOMA_FIRST | M60_FSLW_RW_MODIFY | M60_FSLW_SIZE_WORD | M60_FSLW_TM_USER_DATA;
      int a0 = mmuTranslateWriteUserData (a);  //a+1が必要なので上書き不可
      if ((a & 1) == 0) {  //偶数
        return (DataBreakPoint.DBP_ON ? DataBreakPoint.dbpUserMap : XEiJ.busUserMap)[a0 >>> XEiJ.BUS_PAGE_BITS].mmdRws (a0);
      } else {  //奇数
        int d0 = (DataBreakPoint.DBP_ON ? DataBreakPoint.dbpUserMap : XEiJ.busUserMap)[a0 >>> XEiJ.BUS_PAGE_BITS].mmdRbs (a0);
        m60FSLW ^= M60_FSLW_IOMA_FIRST ^ M60_FSLW_IOMA_SECOND;
        int a1 = mmuTranslateWriteUserData (a + 1);  //偶数
        return (d0 << 8 |
                (DataBreakPoint.DBP_ON ? DataBreakPoint.dbpUserMap : XEiJ.busUserMap)[a1 >>> XEiJ.BUS_PAGE_BITS].mmdRbz (a1));
      }
    }
  }  //mmuModifyWordSignData(int,int)

  //d = mmuModifyWordZeroData (a, supervisor)
  //  リードモディファイライトのリードワードゼロ拡張(データ)
  public static int mmuModifyWordZeroData (int a, int supervisor) throws M68kException {
    if (supervisor != 0) {  //スーパーバイザモード
      m60FSLW = M60_FSLW_IOMA_FIRST | M60_FSLW_RW_MODIFY | M60_FSLW_SIZE_WORD | M60_FSLW_TM_SUPER_DATA;
      int a0 = mmuTranslateWriteSuperData (a);  //a+1が必要なので上書き不可
      if ((a & 1) == 0) {  //偶数
        return (DataBreakPoint.DBP_ON ? DataBreakPoint.dbpSuperMap : XEiJ.busSuperMap)[a0 >>> XEiJ.BUS_PAGE_BITS].mmdRwz (a0);
      } else {  //奇数
        int d0 = (DataBreakPoint.DBP_ON ? DataBreakPoint.dbpSuperMap : XEiJ.busSuperMap)[a0 >>> XEiJ.BUS_PAGE_BITS].mmdRbz (a0);
        m60FSLW ^= M60_FSLW_IOMA_FIRST ^ M60_FSLW_IOMA_SECOND;
        int a1 = mmuTranslateWriteSuperData (a + 1);  //偶数
        return (d0 << 8 |
                (DataBreakPoint.DBP_ON ? DataBreakPoint.dbpSuperMap : XEiJ.busSuperMap)[a1 >>> XEiJ.BUS_PAGE_BITS].mmdRbz (a1));
      }
    } else {  //ユーザモード
      m60FSLW = M60_FSLW_IOMA_FIRST | M60_FSLW_RW_MODIFY | M60_FSLW_SIZE_WORD | M60_FSLW_TM_USER_DATA;
      int a0 = mmuTranslateWriteUserData (a);  //a+1が必要なので上書き不可
      if ((a & 1) == 0) {  //偶数
        return (DataBreakPoint.DBP_ON ? DataBreakPoint.dbpUserMap : XEiJ.busUserMap)[a0 >>> XEiJ.BUS_PAGE_BITS].mmdRwz (a0);
      } else {  //奇数
        int d0 = (DataBreakPoint.DBP_ON ? DataBreakPoint.dbpUserMap : XEiJ.busUserMap)[a0 >>> XEiJ.BUS_PAGE_BITS].mmdRbz (a0);
        m60FSLW ^= M60_FSLW_IOMA_FIRST ^ M60_FSLW_IOMA_SECOND;
        int a1 = mmuTranslateWriteUserData (a + 1);  //偶数
        return (d0 << 8 |
                (DataBreakPoint.DBP_ON ? DataBreakPoint.dbpUserMap : XEiJ.busUserMap)[a1 >>> XEiJ.BUS_PAGE_BITS].mmdRbz (a1));
      }
    }
  }  //mmuModifyWordZeroData(int,int)

  //d = mmuModifyWordSignEven (a, supervisor)
  //  リードモディファイライトのリードワード符号拡張(偶数)
  public static int mmuModifyWordSignEven (int a, int supervisor) throws M68kException {
    if (supervisor != 0) {  //スーパーバイザモード
      m60FSLW = M60_FSLW_IOMA_FIRST | M60_FSLW_RW_MODIFY | M60_FSLW_SIZE_WORD | M60_FSLW_TM_SUPER_DATA;
      a = mmuTranslateWriteSuperData (a);
      return (DataBreakPoint.DBP_ON ? DataBreakPoint.dbpSuperMap : XEiJ.busSuperMap)[a >>> XEiJ.BUS_PAGE_BITS].mmdRws (a);
    } else {  //ユーザモード
      m60FSLW = M60_FSLW_IOMA_FIRST | M60_FSLW_RW_MODIFY | M60_FSLW_SIZE_WORD | M60_FSLW_TM_USER_DATA;
      a = mmuTranslateWriteUserData (a);
      return (DataBreakPoint.DBP_ON ? DataBreakPoint.dbpUserMap : XEiJ.busUserMap)[a >>> XEiJ.BUS_PAGE_BITS].mmdRws (a);
    }
  }  //mmuModifyWordSignEven(int,int)

  //d = mmuModifyWordZeroEven (a, supervisor)
  //  リードモディファイライトのリードワードゼロ拡張(偶数)
  public static int mmuModifyWordZeroEven (int a, int supervisor) throws M68kException {
    if (supervisor != 0) {  //スーパーバイザモード
      m60FSLW = M60_FSLW_IOMA_FIRST | M60_FSLW_RW_MODIFY | M60_FSLW_SIZE_WORD | M60_FSLW_TM_SUPER_DATA;
      a = mmuTranslateWriteSuperData (a);
      return (DataBreakPoint.DBP_ON ? DataBreakPoint.dbpSuperMap : XEiJ.busSuperMap)[a >>> XEiJ.BUS_PAGE_BITS].mmdRwz (a);
    } else {  //ユーザモード
      m60FSLW = M60_FSLW_IOMA_FIRST | M60_FSLW_RW_MODIFY | M60_FSLW_SIZE_WORD | M60_FSLW_TM_USER_DATA;
      a = mmuTranslateWriteUserData (a);
      return (DataBreakPoint.DBP_ON ? DataBreakPoint.dbpUserMap : XEiJ.busUserMap)[a >>> XEiJ.BUS_PAGE_BITS].mmdRwz (a);
    }
  }  //mmuModifyWordZeroEven(int,int)

  //d = mmuModifyLongData (a, supervisor)
  //  リードモディファイライトのリードロング(データ)
  public static int mmuModifyLongData (int a, int supervisor) throws M68kException {
    if (supervisor != 0) {  //スーパーバイザモード
      m60FSLW = M60_FSLW_IOMA_FIRST | M60_FSLW_RW_MODIFY | M60_FSLW_SIZE_LONG | M60_FSLW_TM_SUPER_DATA;
      int a0 = mmuTranslateWriteSuperData (a);  //a+1,a+2,a+3が必要なので上書き不可
      if ((a & 3) == 0) {  //4の倍数
        return (DataBreakPoint.DBP_ON ? DataBreakPoint.dbpSuperMap : XEiJ.busSuperMap)[a0 >>> XEiJ.BUS_PAGE_BITS].mmdRls (a0);
      } else if ((a & 1) == 0) {  //4の倍数+2
        int d0 = (DataBreakPoint.DBP_ON ? DataBreakPoint.dbpSuperMap : XEiJ.busSuperMap)[a0 >>> XEiJ.BUS_PAGE_BITS].mmdRws (a0);
        m60FSLW ^= M60_FSLW_IOMA_FIRST ^ M60_FSLW_IOMA_SECOND;
        int a2 = mmuTranslateWriteSuperData (a + 2);  //偶数
        return (d0 << 16 |
                (DataBreakPoint.DBP_ON ? DataBreakPoint.dbpSuperMap : XEiJ.busSuperMap)[a2 >>> XEiJ.BUS_PAGE_BITS].mmdRwz (a2));
      } else {  //奇数
        int d0 = (DataBreakPoint.DBP_ON ? DataBreakPoint.dbpSuperMap : XEiJ.busSuperMap)[a0 >>> XEiJ.BUS_PAGE_BITS].mmdRbs (a0);
        m60FSLW ^= M60_FSLW_IOMA_FIRST ^ M60_FSLW_IOMA_SECOND;
        int a1 = mmuTranslateWriteSuperData (a + 1);  //偶数
        int a3 = mmuTranslateWriteSuperData (a + 3);  //偶数
        return (d0 << 24 |
                (DataBreakPoint.DBP_ON ? DataBreakPoint.dbpSuperMap : XEiJ.busSuperMap)[a1 >>> XEiJ.BUS_PAGE_BITS].mmdRwz (a1) << 8 |
                (DataBreakPoint.DBP_ON ? DataBreakPoint.dbpSuperMap : XEiJ.busSuperMap)[a3 >>> XEiJ.BUS_PAGE_BITS].mmdRbz (a3));
      }
    } else {  //ユーザモード
      m60FSLW = M60_FSLW_IOMA_FIRST | M60_FSLW_RW_MODIFY | M60_FSLW_SIZE_LONG | M60_FSLW_TM_USER_DATA;
      int a0 = mmuTranslateWriteUserData (a);  //a+1,a+2,a+3が必要なので上書き不可
      if ((a & 3) == 0) {  //4の倍数
        return (DataBreakPoint.DBP_ON ? DataBreakPoint.dbpUserMap : XEiJ.busUserMap)[a0 >>> XEiJ.BUS_PAGE_BITS].mmdRls (a0);
      } else if ((a & 1) == 0) {  //4の倍数+2
        int d0 = (DataBreakPoint.DBP_ON ? DataBreakPoint.dbpUserMap : XEiJ.busUserMap)[a0 >>> XEiJ.BUS_PAGE_BITS].mmdRws (a0);
        m60FSLW ^= M60_FSLW_IOMA_FIRST ^ M60_FSLW_IOMA_SECOND;
        int a2 = mmuTranslateWriteUserData (a + 2);  //偶数
        return (d0 << 16 |
                (DataBreakPoint.DBP_ON ? DataBreakPoint.dbpUserMap : XEiJ.busUserMap)[a2 >>> XEiJ.BUS_PAGE_BITS].mmdRwz (a2));
      } else {  //奇数
        int d0 = (DataBreakPoint.DBP_ON ? DataBreakPoint.dbpUserMap : XEiJ.busUserMap)[a0 >>> XEiJ.BUS_PAGE_BITS].mmdRbs (a0);
        m60FSLW ^= M60_FSLW_IOMA_FIRST ^ M60_FSLW_IOMA_SECOND;
        int a1 = mmuTranslateWriteUserData (a + 1);  //偶数
        int a3 = mmuTranslateWriteUserData (a + 3);  //偶数
        return (d0 << 24 |
                (DataBreakPoint.DBP_ON ? DataBreakPoint.dbpUserMap : XEiJ.busUserMap)[a1 >>> XEiJ.BUS_PAGE_BITS].mmdRwz (a1) << 8 |
                (DataBreakPoint.DBP_ON ? DataBreakPoint.dbpUserMap : XEiJ.busUserMap)[a3 >>> XEiJ.BUS_PAGE_BITS].mmdRbz (a3));
      }
    }
  }  //mmuModifyLongData(int,int)

  //d = mmuModifyLongEven (a, supervisor)
  //  リードモディファイライトのリードロング(偶数)
  public static int mmuModifyLongEven (int a, int supervisor) throws M68kException {
    if (supervisor != 0) {  //スーパーバイザモード
      m60FSLW = M60_FSLW_IOMA_FIRST | M60_FSLW_RW_MODIFY | M60_FSLW_SIZE_LONG | M60_FSLW_TM_SUPER_DATA;
      int a0 = mmuTranslateWriteSuperData (a);  //a+2が必要なので上書き不可
      if ((a & 2) == 0) {  //4の倍数
        return (DataBreakPoint.DBP_ON ? DataBreakPoint.dbpSuperMap : XEiJ.busSuperMap)[a0 >>> XEiJ.BUS_PAGE_BITS].mmdRls (a0);
      } else {  //4の倍数+2
        int d0 = (DataBreakPoint.DBP_ON ? DataBreakPoint.dbpSuperMap : XEiJ.busSuperMap)[a0 >>> XEiJ.BUS_PAGE_BITS].mmdRws (a0);
        m60FSLW ^= M60_FSLW_IOMA_FIRST ^ M60_FSLW_IOMA_SECOND;
        int a2 = mmuTranslateWriteSuperData (a + 2);  //偶数
        return (d0 << 16 |
                (DataBreakPoint.DBP_ON ? DataBreakPoint.dbpSuperMap : XEiJ.busSuperMap)[a2 >>> XEiJ.BUS_PAGE_BITS].mmdRwz (a2));
      }
    } else {  //ユーザモード
      m60FSLW = M60_FSLW_IOMA_FIRST | M60_FSLW_RW_MODIFY | M60_FSLW_SIZE_LONG | M60_FSLW_TM_USER_DATA;
      int a0 = mmuTranslateWriteUserData (a);  //a+2が必要なので上書き不可
      if ((a & 2) == 0) {  //4の倍数
        return (DataBreakPoint.DBP_ON ? DataBreakPoint.dbpUserMap : XEiJ.busUserMap)[a0 >>> XEiJ.BUS_PAGE_BITS].mmdRls (a0);
      } else {  //4の倍数+2
        int d0 = (DataBreakPoint.DBP_ON ? DataBreakPoint.dbpUserMap : XEiJ.busUserMap)[a0 >>> XEiJ.BUS_PAGE_BITS].mmdRws (a0);
        m60FSLW ^= M60_FSLW_IOMA_FIRST ^ M60_FSLW_IOMA_SECOND;
        int a2 = mmuTranslateWriteUserData (a + 2);  //偶数
        return (d0 << 16 |
                (DataBreakPoint.DBP_ON ? DataBreakPoint.dbpUserMap : XEiJ.busUserMap)[a2 >>> XEiJ.BUS_PAGE_BITS].mmdRwz (a2));
      }
    }
  }  //mmuModifyLongEven(int,int)

  //d = mmuModifyLongFour (a, supervisor)
  //  リードモディファイライトのリードロング(4の倍数)
  public static int mmuModifyLongFour (int a, int supervisor) throws M68kException {
    if (supervisor != 0) {  //スーパーバイザモード
      m60FSLW = M60_FSLW_IOMA_FIRST | M60_FSLW_RW_MODIFY | M60_FSLW_SIZE_LONG | M60_FSLW_TM_SUPER_DATA;
      a = mmuTranslateWriteSuperData (a);
      return (DataBreakPoint.DBP_ON ? DataBreakPoint.dbpSuperMap : XEiJ.busSuperMap)[a >>> XEiJ.BUS_PAGE_BITS].mmdRls (a);
    } else {  //ユーザモード
      m60FSLW = M60_FSLW_IOMA_FIRST | M60_FSLW_RW_MODIFY | M60_FSLW_SIZE_LONG | M60_FSLW_TM_USER_DATA;
      a = mmuTranslateWriteUserData (a);
      return (DataBreakPoint.DBP_ON ? DataBreakPoint.dbpUserMap : XEiJ.busUserMap)[a >>> XEiJ.BUS_PAGE_BITS].mmdRls (a);
    }
  }  //mmuModifyLongFour(int,int)

  //--------------------------------------------------------------------------------
  //ポーク
  //  デバッガ用
  //  エラーや副作用なしでライトする

  //mmuPokeByte (a, x, f)
  //  ポークバイト
  public static void mmuPokeByte (int a, int x, int f) {
    f = f == -1 ? XEiJ.regSRS != 0 ? 5 : 1 : f & 7;
    MemoryMappedDevice[] mm = (DataBreakPoint.DBP_ON ?
                               (f & 4) != 0 ? DataBreakPoint.dbpSuperMap : DataBreakPoint.dbpUserMap :
                               (f & 4) != 0 ? XEiJ.busSuperMap : XEiJ.busUserMap);
    //    01234567
    if (0b01100110 << 24 << f < 0) {  //DFC=1,2,5,6。アドレス変換あり
      int a0 = mmuTranslatePeek (a, f & 4, f & 2);
      if ((a ^ a0) != 1) {
        mm[a0 >>> XEiJ.BUS_PAGE_BITS].mmdVb (a0, x);
      }
    } else if (f != 7) {  //DFC=0,3,4。アドレス変換なし
      mm[a >>> XEiJ.BUS_PAGE_BITS].mmdVb (a, x);
    }
  }  //mmuPokeByte(int,int,int)

  //mmuPokeByteData (a, d, supervisor)
  //  ポークバイト(データ)
  public static void mmuPokeByteData (int a, int d, int supervisor) {
    MemoryMappedDevice[] mm = supervisor != 0 ? DataBreakPoint.DBP_ON ? DataBreakPoint.dbpSuperMap : XEiJ.busSuperMap : DataBreakPoint.DBP_ON ? DataBreakPoint.dbpUserMap : XEiJ.busUserMap;
    int a0 = mmuTranslatePeek (a, supervisor, 0);
    if ((a ^ a0) != 1) {
      //mm[a >>> XEiJ.BUS_PAGE_BITS].mmdVb (a0, d);
      XEiJ.busVb (a0, d);
    }
  }  //mmuPokeByteData(int,int,int)

  //mmuPokeWord (a, x, f)
  //  ポークワード
  public static void mmuPokeWord (int a, int x, int f) {
    f = f == -1 ? XEiJ.regSRS != 0 ? 5 : 1 : f & 7;
    MemoryMappedDevice[] mm = (DataBreakPoint.DBP_ON ?
                               (f & 4) != 0 ? DataBreakPoint.dbpSuperMap : DataBreakPoint.dbpUserMap :
                               (f & 4) != 0 ? XEiJ.busSuperMap : XEiJ.busUserMap);
    //    01234567
    if (0b01100110 << 24 << f < 0) {  //DFC=1,2,5,6。アドレス変換あり
      int a0 = mmuTranslatePeek (a, f & 4, f & 2);
      if ((a & 1) == 0) {  //偶数
        if ((a ^ a0) != 1) {
          mm[a0 >>> XEiJ.BUS_PAGE_BITS].mmdVw (a0, x);
        }
      } else {  //奇数
        int a1 = mmuTranslatePeek (a + 1, f & 4, f & 2);
        if ((a     ^ a0) != 1) {
          mm[a0 >>> XEiJ.BUS_PAGE_BITS].mmdVb (a0, x >> 8);
        }
        if ((a + 1 ^ a1) != 1) {
          mm[a1 >>> XEiJ.BUS_PAGE_BITS].mmdVb (a1, x     );
        }
      }
    } else if (f != 7) {  //DFC=0,3,4。アドレス変換なし
      if ((a & 1) == 0) {  //偶数
        mm[a >>> XEiJ.BUS_PAGE_BITS].mmdVw (a, x);
      } else {  //奇数
        mm[a     >>> XEiJ.BUS_PAGE_BITS].mmdVb (a    , x >> 8);
        mm[a + 1 >>> XEiJ.BUS_PAGE_BITS].mmdVb (a + 1, x     );
      }
    }
  }  //mmuPokeWord(int,int,int)

  //mmuPokeWordData (a, d, supervisor)
  //  ポークワード(データ)
  public static void mmuPokeWordData (int a, int d, int supervisor) {
    mmuPokeByteData (a, d >> 8, supervisor);
    mmuPokeByteData (a + 1, d, supervisor);
  }  //mmuPokeWordData(int,int,int)

  //mmuPokeLong (a, x, f)
  //  ポークロング
  public static void mmuPokeLong (int a, int x, int f) {
    f = f == -1 ? XEiJ.regSRS != 0 ? 5 : 1 : f & 7;
    MemoryMappedDevice[] mm = (DataBreakPoint.DBP_ON ?
                               (f & 4) != 0 ? DataBreakPoint.dbpSuperMap : DataBreakPoint.dbpUserMap :
                               (f & 4) != 0 ? XEiJ.busSuperMap : XEiJ.busUserMap);
    //    01234567
    if (0b01100110 << 24 << f < 0) {  //DFC=1,2,5,6。アドレス変換あり
      int a0 = mmuTranslatePeek (a, f & 4, f & 2);
      if ((a & 3) == 0) {  //4の倍数
        if ((a ^ a0) != 1) {
          mm[a0 >>> XEiJ.BUS_PAGE_BITS].mmdVl (a0, x);
        }
      } else if ((a & 1) == 0) {  //4の倍数ではない偶数
        int a2 = mmuTranslatePeek (a + 2, f & 4, f & 2);
        if ((a     ^ a0) != 1) {
          mm[a0 >>> XEiJ.BUS_PAGE_BITS].mmdVw (a0, x >> 16);
        }
        if ((a + 2 ^ a2) != 1) {
          mm[a2 >>> XEiJ.BUS_PAGE_BITS].mmdVw (a2, x);
        }
      } else {  //奇数
        int a1 = mmuTranslatePeek (a + 1, f & 4, f & 2);
        int a3 = mmuTranslatePeek (a + 3, f & 4, f & 2);
        if ((a     ^ a0) != 1) {
          mm[a0 >>> XEiJ.BUS_PAGE_BITS].mmdVb (a0, x >> 24);
        }
        if ((a + 1 ^ a1) != 1) {
          mm[a1 >>> XEiJ.BUS_PAGE_BITS].mmdVw (a1, x >>  8);
        }
        if ((a + 3 ^ a3) != 1) {
          mm[a3 >>> XEiJ.BUS_PAGE_BITS].mmdVb (a3, x);
        }
      }
    } else if (f != 7) {  //DFC=0,3,4。アドレス変換なし
      if ((a & 3) == 0) {  //4の倍数
        mm[a >>> XEiJ.BUS_PAGE_BITS].mmdVl (a, x);
      } else if ((a & 1) == 0) {  //4の倍数ではない偶数
        mm[a     >>> XEiJ.BUS_PAGE_BITS].mmdVw (a    , x >> 16);
        mm[a + 2 >>> XEiJ.BUS_PAGE_BITS].mmdVw (a + 2, x      );
      } else {  //奇数
        mm[a     >>> XEiJ.BUS_PAGE_BITS].mmdVb (a,     x >> 24);
        mm[a + 1 >>> XEiJ.BUS_PAGE_BITS].mmdVw (a + 1, x >>  8);
        mm[a + 3 >>> XEiJ.BUS_PAGE_BITS].mmdVb (a + 3, x      );
      }
    }
  }  //mmuPokeLong(int,int,int)

  //mmuPokeLongData (a, d, supervisor)
  //  ポークロング(データ)
  public static void mmuPokeLongData (int a, int d, int supervisor) {
    mmuPokeByteData (a, d >> 24, supervisor);
    mmuPokeByteData (a + 1, d >> 16, supervisor);
    mmuPokeByteData (a + 2, d >> 8, supervisor);
    mmuPokeByteData (a + 3, d, supervisor);
  }  //mmuPokeLongData(int,int,int)

  //mmuPokeQuad (a, x, f)
  //  ポーククワッド
  public static void mmuPokeQuad (int a, long x, int f) {
    mmuPokeLong (a    , (int) (x >> 32), f);
    mmuPokeLong (a + 4, (int)  x       , f);
  }  //mmuPokeQuad(int,long,int)

  //mmuPokeExtended (a, b, f)
  public static void mmuPokeExtended (int a, byte[] b, int f) {
    for (int i = 0; i < 12; i++) {
      mmuPokeByte (a + i, b[i], f);
    }
  }  //mmuPokeQuad(int,long,int)

  //a = mmuPokeStringZ (a, str, f)
  //  ポークストリング
  //  文字列をUTF-16からSJISに変換しながらメモリに書き込む
  //  文字列に'\0'が含まれるときはその手前まで書き込む
  //  SJISに変換できない文字は'※'になる
  //  最後に'\0'を書き込む
  //  '\0'を含まない書き込んだ文字列を返す
  public static String mmuPokeStringZ (int a, String str, int f) {
    StringBuilder sb = new StringBuilder ();
    int l = str.length ();
    for (int i = 0; i < l; i++) {
      int u = str.charAt (i);
      if (u == '\0') {
        break;
      }
      int s = CharacterCode.chrCharToSJIS[u];  //SJISに変換する
      if (s == 0) {  //変換できない
        s = 0x81a6;  //'※'
      }
      if (s >> 8 != 0) {
        mmuPokeByte (a++, s >> 8, f);
      }
      mmuPokeByte (a++, s, f);
      u = CharacterCode.chrSJISToChar[s];  //UTF-16に変換する
      if (u == 0) {  //変換できない
        u = 0xfffd;
      }
      sb.append ((char) u);
    }
    mmuPokeByte (a, 0, f);  //'\0'
    return sb.toString ();
  }  //mmuPokeStringZ(int,String,int)

  //--------------------------------------------------------------------------------
  //ライト
  //  アドレス変換はライト
  //  FSLWのRead and WriteはWrite

  //mmuWriteByteData (a, d, supervisor)
  //  ライトバイト符号拡張(データ)
  public static void mmuWriteByteData (int a, int d, int supervisor) throws M68kException {
    if (supervisor != 0) {  //スーパーバイザモード
      m60FSLW = M60_FSLW_IOMA_FIRST | M60_FSLW_RW_WRITE | M60_FSLW_SIZE_BYTE | M60_FSLW_TM_SUPER_DATA;
      int t = mmuTranslateWriteSuperData (a);
      (DataBreakPoint.DBP_ON ? DataBreakPoint.dbpSuperMap : XEiJ.busSuperMap)[t >>> XEiJ.BUS_PAGE_BITS].mmdWb (t, d);
    } else {  //ユーザモード
      m60FSLW = M60_FSLW_IOMA_FIRST | M60_FSLW_RW_WRITE | M60_FSLW_SIZE_BYTE | M60_FSLW_TM_USER_DATA;
      int t = mmuTranslateWriteUserData (a);
      (DataBreakPoint.DBP_ON ? DataBreakPoint.dbpUserMap : XEiJ.busUserMap)[t >>> XEiJ.BUS_PAGE_BITS].mmdWb (t, d);
    }
  }  //mmuWriteByteData(int,int,int)

  //mmuWriteWordData (a, d, supervisor)
  //  ライトワード符号拡張(データ)
  public static void mmuWriteWordData (int a, int d, int supervisor) throws M68kException {
    if (supervisor != 0) {  //スーパーバイザモード
      m60FSLW = M60_FSLW_IOMA_FIRST | M60_FSLW_RW_WRITE | M60_FSLW_SIZE_WORD | M60_FSLW_TM_SUPER_DATA;
      int t = mmuTranslateWriteSuperData (a);  //a+1が必要なので上書き不可
      if ((a & 1) == 0) {  //偶数
        (DataBreakPoint.DBP_ON ? DataBreakPoint.dbpSuperMap : XEiJ.busSuperMap)[t >>> XEiJ.BUS_PAGE_BITS].mmdWw (t, d);
      } else {  //奇数
        (DataBreakPoint.DBP_ON ? DataBreakPoint.dbpSuperMap : XEiJ.busSuperMap)[t >>> XEiJ.BUS_PAGE_BITS].mmdWb (t, d >> 8);
        m60FSLW ^= M60_FSLW_IOMA_FIRST ^ M60_FSLW_IOMA_SECOND;
        t = mmuTranslateWriteSuperData (a + 1);  //偶数
        (DataBreakPoint.DBP_ON ? DataBreakPoint.dbpSuperMap : XEiJ.busSuperMap)[t >>> XEiJ.BUS_PAGE_BITS].mmdWb (t, d);
      }
    } else {  //ユーザモード
      m60FSLW = M60_FSLW_IOMA_FIRST | M60_FSLW_RW_WRITE | M60_FSLW_SIZE_WORD | M60_FSLW_TM_USER_DATA;
      int t = mmuTranslateWriteUserData (a);  //a+1が必要なので上書き不可
      if ((a & 1) == 0) {  //偶数
        (DataBreakPoint.DBP_ON ? DataBreakPoint.dbpUserMap : XEiJ.busUserMap)[t >>> XEiJ.BUS_PAGE_BITS].mmdWw (t, d);
      } else {  //奇数
        (DataBreakPoint.DBP_ON ? DataBreakPoint.dbpUserMap : XEiJ.busUserMap)[t >>> XEiJ.BUS_PAGE_BITS].mmdWb (t, d >> 8);
        m60FSLW ^= M60_FSLW_IOMA_FIRST ^ M60_FSLW_IOMA_SECOND;
        t = mmuTranslateWriteUserData (a + 1);  //偶数
        (DataBreakPoint.DBP_ON ? DataBreakPoint.dbpUserMap : XEiJ.busUserMap)[t >>> XEiJ.BUS_PAGE_BITS].mmdWb (t, d);
      }
    }
  }  //mmuWriteWordData(int,int,int)

  //mmuWriteWordEven (a, d, supervisor)
  //  ライトワード符号拡張(偶数)
  public static void mmuWriteWordEven (int a, int d, int supervisor) throws M68kException {
    if (supervisor != 0) {  //スーパーバイザモード
      m60FSLW = M60_FSLW_IOMA_FIRST | M60_FSLW_RW_WRITE | M60_FSLW_SIZE_WORD | M60_FSLW_TM_SUPER_DATA;
      a = mmuTranslateWriteSuperData (a);
      (DataBreakPoint.DBP_ON ? DataBreakPoint.dbpSuperMap : XEiJ.busSuperMap)[a >>> XEiJ.BUS_PAGE_BITS].mmdWw (a, d);
    } else {  //ユーザモード
      m60FSLW = M60_FSLW_IOMA_FIRST | M60_FSLW_RW_WRITE | M60_FSLW_SIZE_WORD | M60_FSLW_TM_USER_DATA;
      a = mmuTranslateWriteUserData (a);
      (DataBreakPoint.DBP_ON ? DataBreakPoint.dbpUserMap : XEiJ.busUserMap)[a >>> XEiJ.BUS_PAGE_BITS].mmdWw (a, d);
    }
  }  //mmuWriteWordEven(int,int,int)

  //mmuWriteLongData (a, d, supervisor)
  //  ライトロング(データ)
  public static void mmuWriteLongData (int a, int d, int supervisor) throws M68kException {
    if (supervisor != 0) {  //スーパーバイザモード
      m60FSLW = M60_FSLW_IOMA_FIRST | M60_FSLW_RW_WRITE | M60_FSLW_SIZE_LONG | M60_FSLW_TM_SUPER_DATA;
      int t = mmuTranslateWriteSuperData (a);  //a+1,a+2,a+3が必要なので上書き不可
      if ((a & 3) == 0) {  //4の倍数
        (DataBreakPoint.DBP_ON ? DataBreakPoint.dbpSuperMap : XEiJ.busSuperMap)[t >>> XEiJ.BUS_PAGE_BITS].mmdWl (t, d);
      } else if ((a & 1) == 0) {  //4の倍数+2
        (DataBreakPoint.DBP_ON ? DataBreakPoint.dbpSuperMap : XEiJ.busSuperMap)[t >>> XEiJ.BUS_PAGE_BITS].mmdWw (t, d >> 16);
        m60FSLW ^= M60_FSLW_IOMA_FIRST ^ M60_FSLW_IOMA_SECOND;
        t = mmuTranslateWriteSuperData (a + 2);  //偶数
        (DataBreakPoint.DBP_ON ? DataBreakPoint.dbpSuperMap : XEiJ.busSuperMap)[t >>> XEiJ.BUS_PAGE_BITS].mmdWw (t, d);
      } else {  //奇数
        (DataBreakPoint.DBP_ON ? DataBreakPoint.dbpSuperMap : XEiJ.busSuperMap)[t >>> XEiJ.BUS_PAGE_BITS].mmdWb (t, d >> 24);
        m60FSLW ^= M60_FSLW_IOMA_FIRST ^ M60_FSLW_IOMA_SECOND;
        t = mmuTranslateWriteSuperData (a + 1);  //偶数
        (DataBreakPoint.DBP_ON ? DataBreakPoint.dbpSuperMap : XEiJ.busSuperMap)[t >>> XEiJ.BUS_PAGE_BITS].mmdWw (t, d >> 8);
        t = mmuTranslateWriteSuperData (a + 3);  //偶数
        (DataBreakPoint.DBP_ON ? DataBreakPoint.dbpSuperMap : XEiJ.busSuperMap)[t >>> XEiJ.BUS_PAGE_BITS].mmdWb (t, d);
      }
    } else {  //ユーザモード
      m60FSLW = M60_FSLW_IOMA_FIRST | M60_FSLW_RW_WRITE | M60_FSLW_SIZE_LONG | M60_FSLW_TM_USER_DATA;
      int t = mmuTranslateWriteUserData (a);  //a+1,a+2,a+3が必要なので上書き不可
      if ((a & 3) == 0) {  //4の倍数
        (DataBreakPoint.DBP_ON ? DataBreakPoint.dbpUserMap : XEiJ.busUserMap)[t >>> XEiJ.BUS_PAGE_BITS].mmdWl (t, d);
      } else if ((a & 1) == 0) {  //4の倍数+2
        (DataBreakPoint.DBP_ON ? DataBreakPoint.dbpUserMap : XEiJ.busUserMap)[t >>> XEiJ.BUS_PAGE_BITS].mmdWw (t, d >> 16);
        m60FSLW ^= M60_FSLW_IOMA_FIRST ^ M60_FSLW_IOMA_SECOND;
        t = mmuTranslateWriteUserData (a + 2);  //偶数
        (DataBreakPoint.DBP_ON ? DataBreakPoint.dbpUserMap : XEiJ.busUserMap)[t >>> XEiJ.BUS_PAGE_BITS].mmdWw (t, d);
      } else {  //奇数
        (DataBreakPoint.DBP_ON ? DataBreakPoint.dbpUserMap : XEiJ.busUserMap)[t >>> XEiJ.BUS_PAGE_BITS].mmdWb (t, d >> 24);
        m60FSLW ^= M60_FSLW_IOMA_FIRST ^ M60_FSLW_IOMA_SECOND;
        t = mmuTranslateWriteUserData (a + 1);  //偶数
        (DataBreakPoint.DBP_ON ? DataBreakPoint.dbpUserMap : XEiJ.busUserMap)[t >>> XEiJ.BUS_PAGE_BITS].mmdWw (t, d >> 8);
        t = mmuTranslateWriteUserData (a + 3);  //偶数
        (DataBreakPoint.DBP_ON ? DataBreakPoint.dbpUserMap : XEiJ.busUserMap)[t >>> XEiJ.BUS_PAGE_BITS].mmdWb (t, d);
      }
    }
  }  //mmuWriteLongData(int,int,int)

  //mmuWriteLongEven (a, d, supervisor)
  //  ライトロング(偶数)
  public static void mmuWriteLongEven (int a, int d, int supervisor) throws M68kException {
    if (supervisor != 0) {  //スーパーバイザモード
      m60FSLW = M60_FSLW_IOMA_FIRST | M60_FSLW_RW_WRITE | M60_FSLW_SIZE_LONG | M60_FSLW_TM_SUPER_DATA;
      int t = mmuTranslateWriteSuperData (a);  //a+2が必要なので上書き不可
      if ((a & 2) == 0) {  //4の倍数
        (DataBreakPoint.DBP_ON ? DataBreakPoint.dbpSuperMap : XEiJ.busSuperMap)[t >>> XEiJ.BUS_PAGE_BITS].mmdWl (t, d);
      } else {  //4の倍数+2
        (DataBreakPoint.DBP_ON ? DataBreakPoint.dbpSuperMap : XEiJ.busSuperMap)[t >>> XEiJ.BUS_PAGE_BITS].mmdWw (t, d >> 16);
        m60FSLW ^= M60_FSLW_IOMA_FIRST ^ M60_FSLW_IOMA_SECOND;
        t = mmuTranslateWriteSuperData (a + 2);  //偶数
        (DataBreakPoint.DBP_ON ? DataBreakPoint.dbpSuperMap : XEiJ.busSuperMap)[t >>> XEiJ.BUS_PAGE_BITS].mmdWw (t, d);
      }
    } else {  //ユーザモード
      m60FSLW = M60_FSLW_IOMA_FIRST | M60_FSLW_RW_WRITE | M60_FSLW_SIZE_LONG | M60_FSLW_TM_USER_DATA;
      int t = mmuTranslateWriteUserData (a);  //a+2が必要なので上書き不可
      if ((a & 2) == 0) {  //4の倍数
        (DataBreakPoint.DBP_ON ? DataBreakPoint.dbpUserMap : XEiJ.busUserMap)[t >>> XEiJ.BUS_PAGE_BITS].mmdWl (t, d);
      } else {  //4の倍数+2
        (DataBreakPoint.DBP_ON ? DataBreakPoint.dbpUserMap : XEiJ.busUserMap)[t >>> XEiJ.BUS_PAGE_BITS].mmdWw (t, d >> 16);
        m60FSLW ^= M60_FSLW_IOMA_FIRST ^ M60_FSLW_IOMA_SECOND;
        t = mmuTranslateWriteUserData (a + 2);  //偶数
        (DataBreakPoint.DBP_ON ? DataBreakPoint.dbpUserMap : XEiJ.busUserMap)[t >>> XEiJ.BUS_PAGE_BITS].mmdWw (t, d);
      }
    }
  }  //mmuWriteLongEven(int,int,int)

  //mmuWriteLongFour (a, d, supervisor)
  //  ライトロング(4の倍数)
  public static void mmuWriteLongFour (int a, int d, int supervisor) throws M68kException {
    if (supervisor != 0) {  //スーパーバイザモード
      m60FSLW = M60_FSLW_IOMA_FIRST | M60_FSLW_RW_WRITE | M60_FSLW_SIZE_LONG | M60_FSLW_TM_SUPER_DATA;
      a = mmuTranslateWriteSuperData (a);
      (DataBreakPoint.DBP_ON ? DataBreakPoint.dbpSuperMap : XEiJ.busSuperMap)[a >>> XEiJ.BUS_PAGE_BITS].mmdWl (a, d);
    } else {  //ユーザモード
      m60FSLW = M60_FSLW_IOMA_FIRST | M60_FSLW_RW_WRITE | M60_FSLW_SIZE_LONG | M60_FSLW_TM_USER_DATA;
      a = mmuTranslateWriteUserData (a);
      (DataBreakPoint.DBP_ON ? DataBreakPoint.dbpUserMap : XEiJ.busUserMap)[a >>> XEiJ.BUS_PAGE_BITS].mmdWl (a, d);
    }
  }  //mmuWriteLongFour(int,int,int)

  //mmuWriteQuadData (a, d, supervisor)
  //  ライトクワッド(データ)
  public static void mmuWriteQuadData (int a, long d, int supervisor) throws M68kException {
    if (supervisor != 0) {  //スーパーバイザモード
      final MemoryMappedDevice[] map = DataBreakPoint.DBP_ON ? DataBreakPoint.dbpSuperMap : XEiJ.busSuperMap;
      m60FSLW = M60_FSLW_IOMA_FIRST | M60_FSLW_RW_WRITE | M60_FSLW_SIZE_QUAD | M60_FSLW_TM_SUPER_DATA;
      int t = mmuTranslateWriteSuperData (a);
      if ((a & 3) == 0) {  //4n
        map[t >>> XEiJ.BUS_PAGE_BITS].mmdWl (t, (int) (d >> 32));
        m60FSLW = M60_FSLW_IOMA_SECOND | M60_FSLW_RW_WRITE | M60_FSLW_SIZE_QUAD | M60_FSLW_TM_SUPER_DATA;
        t = mmuTranslateWriteSuperData (a + 4);
        map[t >>> XEiJ.BUS_PAGE_BITS].mmdWl (t, (int) d);
      } else if ((a & 1) == 0) {  //4n+2
        map[t >>> XEiJ.BUS_PAGE_BITS].mmdWw (t, (int) (d >> 48));
        m60FSLW = M60_FSLW_IOMA_SECOND | M60_FSLW_RW_WRITE | M60_FSLW_SIZE_QUAD | M60_FSLW_TM_SUPER_DATA;
        t = mmuTranslateWriteSuperData (a + 2);
        map[t >>> XEiJ.BUS_PAGE_BITS].mmdWl (t, (int) (d >> 16));
        m60FSLW = M60_FSLW_IOMA_SECOND | M60_FSLW_RW_WRITE | M60_FSLW_SIZE_QUAD | M60_FSLW_TM_SUPER_DATA;
        t = mmuTranslateWriteSuperData (a + 6);
        map[t >>> XEiJ.BUS_PAGE_BITS].mmdWw (t, (int) d);
      } else if ((a & 3) == 1) {  //4n+1
        map[t >>> XEiJ.BUS_PAGE_BITS].mmdWb (t, (int) (d >> 56));
        m60FSLW = M60_FSLW_IOMA_SECOND | M60_FSLW_RW_WRITE | M60_FSLW_SIZE_QUAD | M60_FSLW_TM_SUPER_DATA;
        t = mmuTranslateWriteSuperData (a + 1);
        map[t >>> XEiJ.BUS_PAGE_BITS].mmdWw (t, (int) (d >> 40));
        m60FSLW = M60_FSLW_IOMA_SECOND | M60_FSLW_RW_WRITE | M60_FSLW_SIZE_QUAD | M60_FSLW_TM_SUPER_DATA;
        t = mmuTranslateWriteSuperData (a + 3);
        map[t >>> XEiJ.BUS_PAGE_BITS].mmdWl (t, (int) (d >> 8));
        m60FSLW = M60_FSLW_IOMA_SECOND | M60_FSLW_RW_WRITE | M60_FSLW_SIZE_QUAD | M60_FSLW_TM_SUPER_DATA;
        t = mmuTranslateWriteSuperData (a + 7);
        map[t >>> XEiJ.BUS_PAGE_BITS].mmdWb (t, (int) d);
      } else {  //4n+3
        map[t >>> XEiJ.BUS_PAGE_BITS].mmdWb (t, (int) (d >> 56));
        m60FSLW = M60_FSLW_IOMA_SECOND | M60_FSLW_RW_WRITE | M60_FSLW_SIZE_QUAD | M60_FSLW_TM_SUPER_DATA;
        t = mmuTranslateWriteSuperData (a + 1);
        map[t >>> XEiJ.BUS_PAGE_BITS].mmdWl (t, (int) (d >> 24));
        m60FSLW = M60_FSLW_IOMA_SECOND | M60_FSLW_RW_WRITE | M60_FSLW_SIZE_QUAD | M60_FSLW_TM_SUPER_DATA;
        t = mmuTranslateWriteSuperData (a + 5);
        map[t >>> XEiJ.BUS_PAGE_BITS].mmdWw (t, (int) (d >> 8));
        m60FSLW = M60_FSLW_IOMA_SECOND | M60_FSLW_RW_WRITE | M60_FSLW_SIZE_QUAD | M60_FSLW_TM_SUPER_DATA;
        t = mmuTranslateWriteSuperData (a + 7);
        map[t >>> XEiJ.BUS_PAGE_BITS].mmdWb (t, (int) d);
      }
    } else {  //ユーザモード
      final MemoryMappedDevice[] map = DataBreakPoint.DBP_ON ? DataBreakPoint.dbpUserMap : XEiJ.busUserMap;
      m60FSLW = M60_FSLW_IOMA_FIRST | M60_FSLW_RW_WRITE | M60_FSLW_SIZE_QUAD | M60_FSLW_TM_USER_DATA;
      int t = mmuTranslateWriteUserData (a);
      if ((a & 3) == 0) {  //4n
        map[t >>> XEiJ.BUS_PAGE_BITS].mmdWl (t, (int) (d >> 32));
        m60FSLW = M60_FSLW_IOMA_SECOND | M60_FSLW_RW_WRITE | M60_FSLW_SIZE_QUAD | M60_FSLW_TM_USER_DATA;
        t = mmuTranslateWriteUserData (a + 4);
        map[t >>> XEiJ.BUS_PAGE_BITS].mmdWl (t, (int) d);
      } else if ((a & 1) == 0) {  //4n+2
        map[t >>> XEiJ.BUS_PAGE_BITS].mmdWw (t, (int) (d >> 48));
        m60FSLW = M60_FSLW_IOMA_SECOND | M60_FSLW_RW_WRITE | M60_FSLW_SIZE_QUAD | M60_FSLW_TM_USER_DATA;
        t = mmuTranslateWriteUserData (a + 2);
        map[t >>> XEiJ.BUS_PAGE_BITS].mmdWl (t, (int) (d >> 16));
        m60FSLW = M60_FSLW_IOMA_SECOND | M60_FSLW_RW_WRITE | M60_FSLW_SIZE_QUAD | M60_FSLW_TM_USER_DATA;
        t = mmuTranslateWriteUserData (a + 6);
        map[t >>> XEiJ.BUS_PAGE_BITS].mmdWw (t, (int) d);
      } else if ((a & 3) == 1) {  //4n+1
        map[t >>> XEiJ.BUS_PAGE_BITS].mmdWb (t, (int) (d >> 56));
        m60FSLW = M60_FSLW_IOMA_SECOND | M60_FSLW_RW_WRITE | M60_FSLW_SIZE_QUAD | M60_FSLW_TM_USER_DATA;
        t = mmuTranslateWriteUserData (a + 1);
        map[t >>> XEiJ.BUS_PAGE_BITS].mmdWw (t, (int) (d >> 40));
        m60FSLW = M60_FSLW_IOMA_SECOND | M60_FSLW_RW_WRITE | M60_FSLW_SIZE_QUAD | M60_FSLW_TM_USER_DATA;
        t = mmuTranslateWriteUserData (a + 3);
        map[t >>> XEiJ.BUS_PAGE_BITS].mmdWl (t, (int) (d >> 8));
        m60FSLW = M60_FSLW_IOMA_SECOND | M60_FSLW_RW_WRITE | M60_FSLW_SIZE_QUAD | M60_FSLW_TM_USER_DATA;
        t = mmuTranslateWriteUserData (a + 7);
        map[t >>> XEiJ.BUS_PAGE_BITS].mmdWb (t, (int) d);
      } else {  //4n+3
        map[t >>> XEiJ.BUS_PAGE_BITS].mmdWb (t, (int) (d >> 56));
        m60FSLW = M60_FSLW_IOMA_SECOND | M60_FSLW_RW_WRITE | M60_FSLW_SIZE_QUAD | M60_FSLW_TM_USER_DATA;
        t = mmuTranslateWriteUserData (a + 1);
        map[t >>> XEiJ.BUS_PAGE_BITS].mmdWl (t, (int) (d >> 24));
        m60FSLW = M60_FSLW_IOMA_SECOND | M60_FSLW_RW_WRITE | M60_FSLW_SIZE_QUAD | M60_FSLW_TM_USER_DATA;
        t = mmuTranslateWriteUserData (a + 5);
        map[t >>> XEiJ.BUS_PAGE_BITS].mmdWw (t, (int) (d >> 8));
        m60FSLW = M60_FSLW_IOMA_SECOND | M60_FSLW_RW_WRITE | M60_FSLW_SIZE_QUAD | M60_FSLW_TM_USER_DATA;
        t = mmuTranslateWriteUserData (a + 7);
        map[t >>> XEiJ.BUS_PAGE_BITS].mmdWb (t, (int) d);
      }
    }
  }  //mmuWriteQuadData(int,long,int)

  //mmuWriteQuadSecond (a, d, supervisor)
  //  ライトクワッド(2番目)
  //  エクステンデッドとラインの2番目で使う
  public static void mmuWriteQuadSecond (int a, long d, int supervisor) throws M68kException {
    if (supervisor != 0) {  //スーパーバイザモード
      final MemoryMappedDevice[] map = DataBreakPoint.DBP_ON ? DataBreakPoint.dbpSuperMap : XEiJ.busSuperMap;
      m60FSLW = M60_FSLW_IOMA_SECOND | M60_FSLW_RW_WRITE | M60_FSLW_SIZE_QUAD | M60_FSLW_TM_SUPER_DATA;
      int t = mmuTranslateWriteSuperData (a);
      if ((a & 3) == 0) {  //4n
        map[t >>> XEiJ.BUS_PAGE_BITS].mmdWl (t, (int) (d >> 32));
        m60FSLW = M60_FSLW_IOMA_SECOND | M60_FSLW_RW_WRITE | M60_FSLW_SIZE_QUAD | M60_FSLW_TM_SUPER_DATA;
        t = mmuTranslateWriteSuperData (a + 4);
        map[t >>> XEiJ.BUS_PAGE_BITS].mmdWl (t, (int) d);
      } else if ((a & 1) == 0) {  //4n+2
        map[t >>> XEiJ.BUS_PAGE_BITS].mmdWw (t, (int) (d >> 48));
        m60FSLW = M60_FSLW_IOMA_SECOND | M60_FSLW_RW_WRITE | M60_FSLW_SIZE_QUAD | M60_FSLW_TM_SUPER_DATA;
        t = mmuTranslateWriteSuperData (a + 2);
        map[t >>> XEiJ.BUS_PAGE_BITS].mmdWl (t, (int) (d >> 16));
        m60FSLW = M60_FSLW_IOMA_SECOND | M60_FSLW_RW_WRITE | M60_FSLW_SIZE_QUAD | M60_FSLW_TM_SUPER_DATA;
        t = mmuTranslateWriteSuperData (a + 6);
        map[t >>> XEiJ.BUS_PAGE_BITS].mmdWw (t, (int) d);
      } else if ((a & 3) == 1) {  //4n+1
        map[t >>> XEiJ.BUS_PAGE_BITS].mmdWb (t, (int) (d >> 56));
        m60FSLW = M60_FSLW_IOMA_SECOND | M60_FSLW_RW_WRITE | M60_FSLW_SIZE_QUAD | M60_FSLW_TM_SUPER_DATA;
        t = mmuTranslateWriteSuperData (a + 1);
        map[t >>> XEiJ.BUS_PAGE_BITS].mmdWw (t, (int) (d >> 40));
        m60FSLW = M60_FSLW_IOMA_SECOND | M60_FSLW_RW_WRITE | M60_FSLW_SIZE_QUAD | M60_FSLW_TM_SUPER_DATA;
        t = mmuTranslateWriteSuperData (a + 3);
        map[t >>> XEiJ.BUS_PAGE_BITS].mmdWl (t, (int) (d >> 8));
        m60FSLW = M60_FSLW_IOMA_SECOND | M60_FSLW_RW_WRITE | M60_FSLW_SIZE_QUAD | M60_FSLW_TM_SUPER_DATA;
        t = mmuTranslateWriteSuperData (a + 7);
        map[t >>> XEiJ.BUS_PAGE_BITS].mmdWb (t, (int) d);
      } else {  //4n+3
        map[t >>> XEiJ.BUS_PAGE_BITS].mmdWb (t, (int) (d >> 56));
        m60FSLW = M60_FSLW_IOMA_SECOND | M60_FSLW_RW_WRITE | M60_FSLW_SIZE_QUAD | M60_FSLW_TM_SUPER_DATA;
        t = mmuTranslateWriteSuperData (a + 1);
        map[t >>> XEiJ.BUS_PAGE_BITS].mmdWl (t, (int) (d >> 24));
        m60FSLW = M60_FSLW_IOMA_SECOND | M60_FSLW_RW_WRITE | M60_FSLW_SIZE_QUAD | M60_FSLW_TM_SUPER_DATA;
        t = mmuTranslateWriteSuperData (a + 5);
        map[t >>> XEiJ.BUS_PAGE_BITS].mmdWw (t, (int) (d >> 8));
        m60FSLW = M60_FSLW_IOMA_SECOND | M60_FSLW_RW_WRITE | M60_FSLW_SIZE_QUAD | M60_FSLW_TM_SUPER_DATA;
        t = mmuTranslateWriteSuperData (a + 7);
        map[t >>> XEiJ.BUS_PAGE_BITS].mmdWb (t, (int) d);
      }
    } else {  //ユーザモード
      final MemoryMappedDevice[] map = DataBreakPoint.DBP_ON ? DataBreakPoint.dbpUserMap : XEiJ.busUserMap;
      m60FSLW = M60_FSLW_IOMA_SECOND | M60_FSLW_RW_WRITE | M60_FSLW_SIZE_QUAD | M60_FSLW_TM_USER_DATA;
      int t = mmuTranslateWriteUserData (a);
      if ((a & 3) == 0) {  //4n
        map[t >>> XEiJ.BUS_PAGE_BITS].mmdWl (t, (int) (d >> 32));
        m60FSLW = M60_FSLW_IOMA_SECOND | M60_FSLW_RW_WRITE | M60_FSLW_SIZE_QUAD | M60_FSLW_TM_USER_DATA;
        t = mmuTranslateWriteUserData (a + 4);
        map[t >>> XEiJ.BUS_PAGE_BITS].mmdWl (t, (int) d);
      } else if ((a & 1) == 0) {  //4n+2
        map[t >>> XEiJ.BUS_PAGE_BITS].mmdWw (t, (int) (d >> 48));
        m60FSLW = M60_FSLW_IOMA_SECOND | M60_FSLW_RW_WRITE | M60_FSLW_SIZE_QUAD | M60_FSLW_TM_USER_DATA;
        t = mmuTranslateWriteUserData (a + 2);
        map[t >>> XEiJ.BUS_PAGE_BITS].mmdWl (t, (int) (d >> 16));
        m60FSLW = M60_FSLW_IOMA_SECOND | M60_FSLW_RW_WRITE | M60_FSLW_SIZE_QUAD | M60_FSLW_TM_USER_DATA;
        t = mmuTranslateWriteUserData (a + 6);
        map[t >>> XEiJ.BUS_PAGE_BITS].mmdWw (t, (int) d);
      } else if ((a & 3) == 1) {  //4n+1
        map[t >>> XEiJ.BUS_PAGE_BITS].mmdWb (t, (int) (d >> 56));
        m60FSLW = M60_FSLW_IOMA_SECOND | M60_FSLW_RW_WRITE | M60_FSLW_SIZE_QUAD | M60_FSLW_TM_USER_DATA;
        t = mmuTranslateWriteUserData (a + 1);
        map[t >>> XEiJ.BUS_PAGE_BITS].mmdWw (t, (int) (d >> 40));
        m60FSLW = M60_FSLW_IOMA_SECOND | M60_FSLW_RW_WRITE | M60_FSLW_SIZE_QUAD | M60_FSLW_TM_USER_DATA;
        t = mmuTranslateWriteUserData (a + 3);
        map[t >>> XEiJ.BUS_PAGE_BITS].mmdWl (t, (int) (d >> 8));
        m60FSLW = M60_FSLW_IOMA_SECOND | M60_FSLW_RW_WRITE | M60_FSLW_SIZE_QUAD | M60_FSLW_TM_USER_DATA;
        t = mmuTranslateWriteUserData (a + 7);
        map[t >>> XEiJ.BUS_PAGE_BITS].mmdWb (t, (int) d);
      } else {  //4n+3
        map[t >>> XEiJ.BUS_PAGE_BITS].mmdWb (t, (int) (d >> 56));
        m60FSLW = M60_FSLW_IOMA_SECOND | M60_FSLW_RW_WRITE | M60_FSLW_SIZE_QUAD | M60_FSLW_TM_USER_DATA;
        t = mmuTranslateWriteUserData (a + 1);
        map[t >>> XEiJ.BUS_PAGE_BITS].mmdWl (t, (int) (d >> 24));
        m60FSLW = M60_FSLW_IOMA_SECOND | M60_FSLW_RW_WRITE | M60_FSLW_SIZE_QUAD | M60_FSLW_TM_USER_DATA;
        t = mmuTranslateWriteUserData (a + 5);
        map[t >>> XEiJ.BUS_PAGE_BITS].mmdWw (t, (int) (d >> 8));
        m60FSLW = M60_FSLW_IOMA_SECOND | M60_FSLW_RW_WRITE | M60_FSLW_SIZE_QUAD | M60_FSLW_TM_USER_DATA;
        t = mmuTranslateWriteUserData (a + 7);
        map[t >>> XEiJ.BUS_PAGE_BITS].mmdWb (t, (int) d);
      }
    }
  }  //mmuWriteQuadSecond(int,int,int)



  //mmuReadByteArray (address, array, offset, length, supervisor)
  //  リードバイト配列。先頭から読み出す
  //  address  先頭アドレス
  //  array    バイト配列
  //  offset   先頭オフセット
  //  length   バイト数
  public static void mmuReadByteArray (int address, byte[] array, int offset, int length, int supervisor) throws M68kException {
    if (false) {  //1バイトずつmmuReadByteSignDataを呼び出す
      for (int index = 0; index < length; index++) {
        array[offset + index] = mmuReadByteSignData (address + index, supervisor);
      }
    } else {
      //  変換後アドレスは0
      //  デバイスはnull
      //  while 残りが1バイト以上
      //    if ページの先頭
      //      デバイスはnull
      //    if アドレスが4nかつ残りが4バイト以上
      //      FSLWはリードロング
      //      if デバイスがnull
      //        変換後アドレスを求める
      //        デバイスを求める
      //      リードロング
      //    elif アドレスが2nかつ残りが2バイト以上
      //      FSLWはリードワード
      //      if デバイスがnull
      //        変換後アドレスを求める
      //        デバイスを求める
      //      リードワード
      //    else
      //      FSLWはリードバイト
      //      if デバイスがnull
      //        変換後アドレスを求める
      //        デバイスを求める
      //      リードバイト
      //  endwhile
      length += offset;  //lengthはoffsetの上限
      final int mask = Math.min (XEiJ.BUS_PAGE_SIZE, mmuPageSize) - 1;
      if (supervisor != 0) {  //スーパーバイザモード
        final MemoryMappedDevice[] map = DataBreakPoint.DBP_ON ? DataBreakPoint.dbpSuperMap : XEiJ.busSuperMap;
        int translated = 0;  //変換後アドレスは0
        MemoryMappedDevice device = null;  //デバイスはnull
        while (offset < length) {  //残りが1バイト以上
          if ((address & mask) == 0) {  //ページの先頭
            device = null;  //デバイスはnull
          }
          if ((address & 3) == 0 && offset + 4 <= length) {  //アドレスが4nかつ残りが4バイト以上
            m60FSLW = (M60_FSLW_IOMA_FIRST |
                                     M60_FSLW_RW_READ |
                                     M60_FSLW_SIZE_LONG |
                                     M60_FSLW_TM_SUPER_DATA);  //FSLWはリードロング
            if (device == null) {  //デバイスがnull
              translated = mmuTranslateReadSuperData (address);  //変換後アドレスを求める
              device = map[translated >>> XEiJ.BUS_PAGE_BITS];  //デバイスを求める
            }
            int data = device.mmdRls (translated);  //リードロング
            array[offset] = (byte) (data >> 24);
            array[offset + 1] = (byte) (data >> 16);
            array[offset + 2] = (byte) (data >> 8);
            array[offset + 3] = (byte) data;
            address += 4;
            translated += 4;
            offset += 4;
          } else if ((address & 1) == 0 && offset + 2 <= length) {  //アドレスが2nかつ残りが2バイト以上
            m60FSLW = (M60_FSLW_IOMA_FIRST |
                                     M60_FSLW_RW_READ |
                                     M60_FSLW_SIZE_WORD |
                                     M60_FSLW_TM_SUPER_DATA);  //FSLWはリードワード
            if (device == null) {  //デバイスがnull
              translated = mmuTranslateReadSuperData (address);  //変換後アドレスを求める
              device = map[translated >>> XEiJ.BUS_PAGE_BITS];  //デバイスを求める
            }
            int data = device.mmdRws (translated);  //リードワード
            array[offset] = (byte) (data >> 8);
            array[offset + 1] = (byte) data;
            address += 2;
            translated += 2;
            offset += 2;
          } else {
            m60FSLW = (M60_FSLW_IOMA_FIRST |
                                     M60_FSLW_RW_READ |
                                     M60_FSLW_SIZE_BYTE |
                                     M60_FSLW_TM_SUPER_DATA);  //FSLWはリードバイト
            if (device == null) {  //デバイスがnull
              translated = mmuTranslateReadSuperData (address);  //変換後アドレスを求める
              device = map[translated >>> XEiJ.BUS_PAGE_BITS];  //デバイスを求める
            }
            array[offset] = device.mmdRbs (translated);  //リードバイト
            address++;
            translated++;
            offset++;
          }
        }  //while
      } else {  //ユーザモード
        final MemoryMappedDevice[] map = DataBreakPoint.DBP_ON ? DataBreakPoint.dbpUserMap : XEiJ.busUserMap;
        int translated = 0;  //変換後アドレスは0
        MemoryMappedDevice device = null;  //デバイスはnull
        while (offset < length) {  //残りが1バイト以上
          if ((address & mask) == 0) {  //ページの先頭
            device = null;  //デバイスはnull
          }
          if ((address & 3) == 0 && offset + 4 <= length) {  //アドレスが4nかつ残りが4バイト以上
            m60FSLW = (M60_FSLW_IOMA_FIRST |
                                     M60_FSLW_RW_READ |
                                     M60_FSLW_SIZE_LONG |
                                     M60_FSLW_TM_USER_DATA);  //FSLWはリードロング
            if (device == null) {  //デバイスがnull
              translated = mmuTranslateReadUserData (address);  //変換後アドレスを求める
              device = map[translated >>> XEiJ.BUS_PAGE_BITS];  //デバイスを求める
            }
            int data = device.mmdRls (translated);  //リードロング
            array[offset] = (byte) (data >> 24);
            array[offset + 1] = (byte) (data >> 16);
            array[offset + 2] = (byte) (data >> 8);
            array[offset + 3] = (byte) data;
            address += 4;
            translated += 4;
            offset += 4;
          } else if ((address & 1) == 0 && offset + 2 <= length) {  //アドレスが2nかつ残りが2バイト以上
            m60FSLW = (M60_FSLW_IOMA_FIRST |
                                     M60_FSLW_RW_READ |
                                     M60_FSLW_SIZE_WORD |
                                     M60_FSLW_TM_USER_DATA);  //FSLWはリードワード
            if (device == null) {  //デバイスがnull
              translated = mmuTranslateReadUserData (address);  //変換後アドレスを求める
              device = map[translated >>> XEiJ.BUS_PAGE_BITS];  //デバイスを求める
            }
            int data = device.mmdRws (translated);  //リードワード
            array[offset] = (byte) (data >> 8);
            array[offset + 1] = (byte) data;
            address += 2;
            translated += 2;
            offset += 2;
          } else {
            m60FSLW = (M60_FSLW_IOMA_FIRST |
                                     M60_FSLW_RW_READ |
                                     M60_FSLW_SIZE_BYTE |
                                     M60_FSLW_TM_USER_DATA);  //FSLWはリードバイト
            if (device == null) {  //デバイスがnull
              translated = mmuTranslateReadUserData (address);  //変換後アドレスを求める
              device = map[translated >>> XEiJ.BUS_PAGE_BITS];  //デバイスを求める
            }
            array[offset] = device.mmdRbs (translated);  //リードバイト
            address++;
            translated++;
            offset++;
          }
        }  //while
      }
    }
  }  //mmuReadByteArray

  //mmuWriteByteArray (address, array, offset, length, supervisor)
  //  ライトバイト配列。先頭から書き込む
  //  address  先頭アドレス
  //  array    バイト配列
  //  offset   先頭オフセット
  //  length   バイト数
  public static void mmuWriteByteArray (int address, byte[] array, int offset, int length, int supervisor) throws M68kException {
    if (false) {  //1バイトずつmmuWriteByteDataを呼び出す
      for (int index = 0; index < length; index++) {
        mmuWriteByteData (address + index, array[offset + index], supervisor);
      }
    } else {
      //  変換後アドレスは0
      //  デバイスはnull
      //  while 残りが1バイト以上
      //    if ページの先頭
      //      デバイスはnull
      //    if アドレスが4nかつ残りが4バイト以上
      //      FSLWはライトロング
      //      if デバイスがnull
      //        変換後アドレスを求める
      //        デバイスを求める
      //      ライトロング
      //    elif アドレスが2nかつ残りが2バイト以上
      //      FSLWはライトワード
      //      if デバイスがnull
      //        変換後アドレスを求める
      //        デバイスを求める
      //      ライトワード
      //    else
      //      FSLWはライトバイト
      //      if デバイスがnull
      //        変換後アドレスを求める
      //        デバイスを求める
      //      ライトバイト
      //  endwhile
      length += offset;  //lengthはoffsetの上限
      final int mask = Math.min (XEiJ.BUS_PAGE_SIZE, mmuPageSize) - 1;
      if (supervisor != 0) {  //スーパーバイザモード
        final MemoryMappedDevice[] map = DataBreakPoint.DBP_ON ? DataBreakPoint.dbpSuperMap : XEiJ.busSuperMap;
        int translated = 0;  //変換後アドレスは0
        MemoryMappedDevice device = null;  //デバイスはnull
        while (offset < length) {  //残りが1バイト以上
          if ((address & mask) == 0) {  //ページの先頭
            device = null;  //デバイスはnull
          }
          if ((address & 3) == 0 && offset + 4 <= length) {  //アドレスが4nかつ残りが4バイト以上
            m60FSLW = (M60_FSLW_IOMA_FIRST |
                                     M60_FSLW_RW_WRITE |
                                     M60_FSLW_SIZE_LONG |
                                     M60_FSLW_TM_SUPER_DATA);  //FSLWはライトロング
            if (device == null) {  //デバイスがnull
              translated = mmuTranslateWriteSuperData (address);  //変換後アドレスを求める
              device = map[translated >>> XEiJ.BUS_PAGE_BITS];  //デバイスを求める
            }
            device.mmdWl (translated,
                          array[offset] << 24 |
                          (0xff & array[offset + 1]) << 16 |
                          (0xff & array[offset + 2]) << 8 |
                          (0xff & array[offset + 3]));  //ライトロング
            address += 4;
            translated += 4;
            offset += 4;
          } else if ((address & 1) == 0 && offset + 2 <= length) {  //アドレスが2nかつ残りが2バイト以上
            m60FSLW = (M60_FSLW_IOMA_FIRST |
                                     M60_FSLW_RW_WRITE |
                                     M60_FSLW_SIZE_WORD |
                                     M60_FSLW_TM_SUPER_DATA);  //FSLWはライトワード
            if (device == null) {  //デバイスがnull
              translated = mmuTranslateWriteSuperData (address);  //変換後アドレスを求める
              device = map[translated >>> XEiJ.BUS_PAGE_BITS];  //デバイスを求める
            }
            device.mmdWw (translated,
                          array[offset] << 8 |
                          (0xff & array[offset + 1]));  //ライトワード
            address += 2;
            translated += 2;
            offset += 2;
          } else {
            m60FSLW = (M60_FSLW_IOMA_FIRST |
                                     M60_FSLW_RW_WRITE |
                                     M60_FSLW_SIZE_BYTE |
                                     M60_FSLW_TM_SUPER_DATA);  //FSLWはライトバイト
            if (device == null) {  //デバイスがnull
              translated = mmuTranslateWriteSuperData (address);  //変換後アドレスを求める
              device = map[translated >>> XEiJ.BUS_PAGE_BITS];  //デバイスを求める
            }
            device.mmdWb (translated, array[offset]);  //ライトバイト
            address++;
            translated++;
            offset++;
          }
        }  //while
      } else {  //ユーザモード
        final MemoryMappedDevice[] map = DataBreakPoint.DBP_ON ? DataBreakPoint.dbpUserMap : XEiJ.busUserMap;
        int translated = 0;  //変換後アドレスは0
        MemoryMappedDevice device = null;  //デバイスはnull
        while (offset < length) {  //残りが1バイト以上
          if ((address & mask) == 0) {  //ページの先頭
            device = null;  //デバイスはnull
          }
          if ((address & 3) == 0 && offset + 4 <= length) {  //アドレスが4nかつ残りが4バイト以上
            m60FSLW = (M60_FSLW_IOMA_FIRST |
                                     M60_FSLW_RW_WRITE |
                                     M60_FSLW_SIZE_LONG |
                                     M60_FSLW_TM_USER_DATA);  //FSLWはライトロング
            if (device == null) {  //デバイスがnull
              translated = mmuTranslateWriteUserData (address);  //変換後アドレスを求める
              device = map[translated >>> XEiJ.BUS_PAGE_BITS];  //デバイスを求める
            }
            device.mmdWl (translated,
                          array[offset] << 24 |
                          (0xff & array[offset + 1]) << 16 |
                          (0xff & array[offset + 2]) << 8 |
                          (0xff & array[offset + 3]));  //ライトロング
            address += 4;
            translated += 4;
            offset += 4;
          } else if ((address & 1) == 0 && offset + 2 <= length) {  //アドレスが2nかつ残りが2バイト以上
            m60FSLW = (M60_FSLW_IOMA_FIRST |
                                     M60_FSLW_RW_WRITE |
                                     M60_FSLW_SIZE_WORD |
                                     M60_FSLW_TM_USER_DATA);  //FSLWはライトワード
            if (device == null) {  //デバイスがnull
              translated = mmuTranslateWriteUserData (address);  //変換後アドレスを求める
              device = map[translated >>> XEiJ.BUS_PAGE_BITS];  //デバイスを求める
            }
            device.mmdWw (translated,
                          array[offset] << 8 |
                          (0xff & array[offset + 1]));  //ライトワード
            address += 2;
            translated += 2;
            offset += 2;
          } else {
            m60FSLW = (M60_FSLW_IOMA_FIRST |
                                     M60_FSLW_RW_WRITE |
                                     M60_FSLW_SIZE_BYTE |
                                     M60_FSLW_TM_USER_DATA);  //FSLWはライトバイト
            if (device == null) {  //デバイスがnull
              translated = mmuTranslateWriteUserData (address);  //変換後アドレスを求める
              device = map[translated >>> XEiJ.BUS_PAGE_BITS];  //デバイスを求める
            }
            device.mmdWb (translated, array[offset]);  //ライトバイト
            address++;
            translated++;
            offset++;
          }
        }  //while
      }
    }
  }  //mmuWriteByteArray

  //mmuWriteByteArrayDecrement (address, array, offset, length, supervisor)
  //  ライトバイト配列デクリメント。末尾から書き込む
  //  address  先頭アドレス
  //  array    バイト配列
  //  offset   先頭オフセット
  //  length   バイト数
  public static void mmuWriteByteArrayDecrement (int address, byte[] array, int offset, int length, int supervisor) throws M68kException {
    if (false) {  //1バイトずつmmuWriteByteDataを呼び出す
      for (int index = length - 1; 0 <= index; index--) {
        mmuWriteByteData (address + index, array[offset + index], supervisor);
      }
    } else {
      //  変換後アドレスは0
      //  デバイスはnull
      //  while 残りが1バイト以上
      //    if ページの先頭
      //      デバイスはnull
      //    if アドレスが4nかつ残りが4バイト以上
      //      FSLWはライトロング
      //      if デバイスがnull
      //        変換後アドレスを求める
      //        デバイスを求める
      //      ライトロング
      //    elif アドレスが2nかつ残りが2バイト以上
      //      FSLWはライトワード
      //      if デバイスがnull
      //        変換後アドレスを求める
      //        デバイスを求める
      //      ライトワード
      //    else
      //      FSLWはライトバイト
      //      if デバイスがnull
      //        変換後アドレスを求める
      //        デバイスを求める
      //      ライトバイト
      //  endwhile
      address += length;  //addressはaddressの上限
      offset += length;  //offsetはoffsetの上限
      length = offset - length;  //lengthはoffsetの下限
      final int mask = Math.min (XEiJ.BUS_PAGE_SIZE, mmuPageSize) - 1;
      if (supervisor != 0) {  //スーパーバイザモード
        final MemoryMappedDevice[] map = DataBreakPoint.DBP_ON ? DataBreakPoint.dbpSuperMap : XEiJ.busSuperMap;
        int translated = 0;  //変換後アドレスは0
        MemoryMappedDevice device = null;  //デバイスはnull
        while (length < offset) {  //残りが1バイト以上
          if ((address & mask) == 0) {  //ページの先頭
            device = null;  //デバイスはnull
          }
          if ((address & 3) == 0 && length <= offset - 4) {  //アドレスが4nかつ残りが4バイト以上
            m60FSLW = (M60_FSLW_IOMA_FIRST |
                                     M60_FSLW_RW_WRITE |
                                     M60_FSLW_SIZE_LONG |
                                     M60_FSLW_TM_SUPER_DATA);  //FSLWはライトロング
            address -= 4;
            translated -= 4;
            offset -= 4;
            if (device == null) {  //デバイスがnull
              translated = mmuTranslateWriteSuperData (address);  //変換後アドレスを求める
              device = map[translated >>> XEiJ.BUS_PAGE_BITS];  //デバイスを求める
            }
            device.mmdWl (translated,
                          array[offset] << 24 |
                          (0xff & array[offset + 1]) << 16 |
                          (0xff & array[offset + 2]) << 8 |
                          (0xff & array[offset + 3]));  //ライトロング
          } else if ((address & 1) == 0 && length <= offset - 2) {  //アドレスが2nかつ残りが2バイト以上
            m60FSLW = (M60_FSLW_IOMA_FIRST |
                                     M60_FSLW_RW_WRITE |
                                     M60_FSLW_SIZE_WORD |
                                     M60_FSLW_TM_SUPER_DATA);  //FSLWはライトワード
            address -= 2;
            translated -= 2;
            offset -= 2;
            if (device == null) {  //デバイスがnull
              translated = mmuTranslateWriteSuperData (address);  //変換後アドレスを求める
              device = map[translated >>> XEiJ.BUS_PAGE_BITS];  //デバイスを求める
            }
            device.mmdWw (translated,
                          array[offset] << 8 |
                          (0xff & array[offset + 1]));  //ライトワード
          } else {
            m60FSLW = (M60_FSLW_IOMA_FIRST |
                                     M60_FSLW_RW_WRITE |
                                     M60_FSLW_SIZE_BYTE |
                                     M60_FSLW_TM_SUPER_DATA);  //FSLWはライトバイト
            address--;
            translated--;
            offset--;
            if (device == null) {  //デバイスがnull
              translated = mmuTranslateWriteSuperData (address);  //変換後アドレスを求める
              device = map[translated >>> XEiJ.BUS_PAGE_BITS];  //デバイスを求める
            }
            device.mmdWb (translated, array[offset]);  //ライトバイト
          }
        }  //while
      } else {  //ユーザモード
        final MemoryMappedDevice[] map = DataBreakPoint.DBP_ON ? DataBreakPoint.dbpUserMap : XEiJ.busUserMap;
        int translated = 0;  //変換後アドレスは0
        MemoryMappedDevice device = null;  //デバイスはnull
        while (length < offset) {  //残りが1バイト以上
          if ((address & mask) == 0) {  //ページの先頭
            device = null;  //デバイスはnull
          }
          if ((address & 3) == 0 && length <= offset - 4) {  //アドレスが4nかつ残りが4バイト以上
            m60FSLW = (M60_FSLW_IOMA_FIRST |
                                     M60_FSLW_RW_WRITE |
                                     M60_FSLW_SIZE_LONG |
                                     M60_FSLW_TM_USER_DATA);  //FSLWはライトロング
            address -= 4;
            translated -= 4;
            offset -= 4;
            if (device == null) {  //デバイスがnull
              translated = mmuTranslateWriteUserData (address);  //変換後アドレスを求める
              device = map[translated >>> XEiJ.BUS_PAGE_BITS];  //デバイスを求める
            }
            device.mmdWl (translated,
                          array[offset] << 24 |
                          (0xff & array[offset + 1]) << 16 |
                          (0xff & array[offset + 2]) << 8 |
                          (0xff & array[offset + 3]));  //ライトロング
          } else if ((address & 1) == 0 && length <= offset - 2) {  //アドレスが2nかつ残りが2バイト以上
            m60FSLW = (M60_FSLW_IOMA_FIRST |
                                     M60_FSLW_RW_WRITE |
                                     M60_FSLW_SIZE_WORD |
                                     M60_FSLW_TM_USER_DATA);  //FSLWはライトワード
            address -= 2;
            translated -= 2;
            offset -= 2;
            if (device == null) {  //デバイスがnull
              translated = mmuTranslateWriteUserData (address);  //変換後アドレスを求める
              device = map[translated >>> XEiJ.BUS_PAGE_BITS];  //デバイスを求める
            }
            device.mmdWw (translated,
                          array[offset] << 8 |
                          (0xff & array[offset + 1]));  //ライトワード
          } else {
            m60FSLW = (M60_FSLW_IOMA_FIRST |
                                     M60_FSLW_RW_WRITE |
                                     M60_FSLW_SIZE_BYTE |
                                     M60_FSLW_TM_USER_DATA);  //FSLWはライトバイト
            address--;
            translated--;
            offset--;
            if (device == null) {  //デバイスがnull
              translated = mmuTranslateWriteUserData (address);  //変換後アドレスを求める
              device = map[translated >>> XEiJ.BUS_PAGE_BITS];  //デバイスを求める
            }
            device.mmdWb (translated, array[offset]);  //ライトバイト
          }
        }  //while
      }
    }
  }  //mmuWriteByteArrayDecrement



  //--------------------------------------------------------------------------------
  //アドレス変換

  //pa = mmuLoadPhysicalAddressRead (a)
  //  PLPAR (An)
  //  DFCに従って論理アドレスを物理アドレスに変換する(リードアクセス)
  //    DFC  1=ユーザデータ,2=ユーザ命令,5=スーパーバイザデータ,6=スーパーバイザ命令
  //    pa   物理アドレス
  //    a    論理アドレス
  public static int mmuLoadPhysicalAddressRead (int a) throws M68kException {
    m60FSLW = M60_FSLW_IOMA_FIRST | M60_FSLW_RW_READ | M60_FSLW_SIZE_BYTE | XEiJ.mpuDFC << 16;
    return ((0b10011111 << 24 << XEiJ.mpuDFC) < 0 ?
            (0b00101010 << 24 << XEiJ.mpuDFC) < 0 ? mmuTranslateReadSuperCode (a) : mmuTranslateReadSuperData (a) :
            (0b00101010 << 24 << XEiJ.mpuDFC) < 0 ? mmuTranslateReadUserCode (a) : mmuTranslateReadUserData (a));
  }  //mmuLoadPhysicalAddressRead(int)

  //pa = mmuLoadPhysicalAddressWrite (a)
  //  PLPAW (An)
  //  DFCに従って論理アドレスを物理アドレスに変換する(ライトアクセス)
  //    DFC  1=ユーザデータ,2=ユーザ命令,5=スーパーバイザデータ,6=スーパーバイザ命令
  //    pa   物理アドレス
  //    a    論理アドレス
  public static int mmuLoadPhysicalAddressWrite (int a) throws M68kException {
    m60FSLW = M60_FSLW_IOMA_FIRST | M60_FSLW_RW_WRITE | M60_FSLW_SIZE_BYTE | XEiJ.mpuDFC << 16;
    return ((0b10011111 << 24 << XEiJ.mpuDFC) < 0 ?
            (0b00101010 << 24 << XEiJ.mpuDFC) < 0 ? mmuTranslateWriteSuperCode (a) : mmuTranslateWriteSuperData (a) :
            (0b00101010 << 24 << XEiJ.mpuDFC) < 0 ? mmuTranslateWriteUserCode (a) : mmuTranslateWriteUserData (a));
  }  //mmuLoadPhysicalAddressWrite(int)

  //pa = mmuTranslateReadUserData (a)
  //  アドレス変換を行う(リードユーザデータ)
  //    pa  物理アドレス
  //    a   論理アドレス
  //  m60FSLWのMA,RW,SIZE,TM,IOをセットしてから呼び出すこと
  public static int mmuTranslateReadUserData (int a) throws M68kException {
    int logicalPage = a & mmuPageAddressMask;  //論理ページアドレス
    int head = (logicalPage * MMU_HASH_COEFF >>> -MMU_HASH_BITS) * (4 * MMU_CACHE_WAYS);  //先頭のエントリ
    if (mmuUserDataCache[head] == logicalPage) {  //リード用の論理ページアドレスと一致した
      if (CAT_ON) {
        catCM = (mmuUserDataCache[head + 3] >> 5) & 3;  //キャッシュモード
      }
      return mmuUserDataCache[head + 2] | (a & mmuPageOffsetMask);  //物理ページアドレスとページオフセットを連結する
    }
    if (MMU_CACHE_WAYS >= 2) {  //2ways以上
      int tail = head + (4 * MMU_CACHE_WAYS - 4);  //末尾のエントリ
      for (int i = head + 4; i <= tail; i += 4) {
        if (mmuUserDataCache[i] == logicalPage) {  //リード用の論理ページアドレスと一致した
          //int logicalRead  = mmuUserDataCache[i    ];
          int logicalWrite = mmuUserDataCache[i + 1];
          int physicalPage = mmuUserDataCache[i + 2];
          int flag = mmuUserDataCache[i + 3];
          for (; i > head; i -= 4) {
            mmuUserDataCache[i    ] = mmuUserDataCache[i - 4];
            mmuUserDataCache[i + 1] = mmuUserDataCache[i - 3];
            mmuUserDataCache[i + 2] = mmuUserDataCache[i - 2];
            mmuUserDataCache[i + 3] = mmuUserDataCache[i - 1];
          }
          mmuUserDataCache[i    ] = logicalPage;  //logicalRead
          mmuUserDataCache[i + 1] = logicalWrite;
          mmuUserDataCache[i + 2] = physicalPage;
          mmuUserDataCache[i + 3] = flag;
          return physicalPage | (a & mmuPageOffsetMask);  //物理ページアドレスとページオフセットを連結する
        }
      }  //for i
    }
    return mmuTranslateCommon (a, false, false, false);
  }  //mmuTranslateReadUserData(int)

  //pa = mmuTranslateReadUserCode (a)
  //  アドレス変換を行う(リードユーザコード)
  //    pa  物理アドレス
  //    a   論理アドレス
  //  m60FSLWのMA,RW,SIZE,TM,IOをセットしてから呼び出すこと
  public static int mmuTranslateReadUserCode (int a) throws M68kException {
    int logicalPage = a & mmuPageAddressMask;  //論理ページアドレス
    int head = (logicalPage * MMU_HASH_COEFF >>> -MMU_HASH_BITS) * (4 * MMU_CACHE_WAYS);  //先頭のエントリ
    if (mmuUserCodeCache[head] == logicalPage) {  //リード用の論理ページアドレスと一致した
      if (CAT_ON) {
        catCM = (mmuUserCodeCache[head + 3] >> 5) & 3;  //キャッシュモード
      }
      return mmuUserCodeCache[head + 2] | (a & mmuPageOffsetMask);  //物理ページアドレスとページオフセットを連結する
    }
    if (MMU_CACHE_WAYS >= 2) {  //2ways以上
      int tail = head + (4 * MMU_CACHE_WAYS - 4);  //末尾のエントリ
      for (int i = head + 4; i <= tail; i += 4) {
        if (mmuUserCodeCache[i] == logicalPage) {  //リード用の論理ページアドレスと一致した
          //int logicalRead  = mmuUserCodeCache[i    ];
          int logicalWrite = mmuUserCodeCache[i + 1];
          int physicalPage = mmuUserCodeCache[i + 2];
          int flag = mmuUserCodeCache[i + 3];
          for (; i > head; i -= 4) {
            mmuUserCodeCache[i    ] = mmuUserCodeCache[i - 4];
            mmuUserCodeCache[i + 1] = mmuUserCodeCache[i - 3];
            mmuUserCodeCache[i + 2] = mmuUserCodeCache[i - 2];
            mmuUserCodeCache[i + 3] = mmuUserCodeCache[i - 1];
          }
          mmuUserCodeCache[head    ] = logicalPage;  //logicalRead
          mmuUserCodeCache[head + 1] = logicalWrite;
          mmuUserCodeCache[head + 2] = physicalPage;
          mmuUserCodeCache[head + 3] = flag;
          return physicalPage | (a & mmuPageOffsetMask);  //物理ページアドレスとページオフセットを連結する
        }
      }  //for i
    }
    return mmuTranslateCommon (a, false, false, true);
  }  //mmuTranslateReadUserCode(int)

  //pa = mmuTranslateReadSuperData (a)
  //  アドレス変換を行う(リードスーパーバイザデータ)
  //    pa  物理アドレス
  //    a   論理アドレス
  //  m60FSLWのMA,RW,SIZE,TM,IOをセットしてから呼び出すこと
  public static int mmuTranslateReadSuperData (int a) throws M68kException {
    int logicalPage = a & mmuPageAddressMask;  //論理ページアドレス
    int head = (logicalPage * MMU_HASH_COEFF >>> -MMU_HASH_BITS) * (4 * MMU_CACHE_WAYS);  //先頭のエントリ
    if (mmuSuperDataCache[head] == logicalPage) {  //リード用の論理ページアドレスと一致した
      if (CAT_ON) {
        catCM = (mmuSuperDataCache[head + 3] >> 5) & 3;  //キャッシュモード
      }
      return mmuSuperDataCache[head + 2] | (a & mmuPageOffsetMask);  //物理ページアドレスとページオフセットを連結する
    }
    if (MMU_CACHE_WAYS >= 2) {  //2ways以上
      int tail = head + (4 * MMU_CACHE_WAYS - 4);  //末尾のエントリ
      for (int i = head + 4; i <= tail; i += 4) {
        if (mmuSuperDataCache[i] == logicalPage) {  //リード用の論理ページアドレスと一致した
          //int logicalRead  = mmuSuperDataCache[i    ];
          int logicalWrite = mmuSuperDataCache[i + 1];
          int physicalPage = mmuSuperDataCache[i + 2];
          int flag = mmuSuperDataCache[i + 3];
          for (; i > head; i -= 4) {
            mmuSuperDataCache[i    ] = mmuSuperDataCache[i - 4];
            mmuSuperDataCache[i + 1] = mmuSuperDataCache[i - 3];
            mmuSuperDataCache[i + 2] = mmuSuperDataCache[i - 2];
            mmuSuperDataCache[i + 3] = mmuSuperDataCache[i - 1];
          }
          mmuSuperDataCache[i    ] = logicalPage;  //logicalRead
          mmuSuperDataCache[i + 1] = logicalWrite;
          mmuSuperDataCache[i + 2] = physicalPage;
          mmuSuperDataCache[i + 3] = flag;
          return physicalPage | (a & mmuPageOffsetMask);  //物理ページアドレスとページオフセットを連結する
        }
      }  //for i
    }
    return mmuTranslateCommon (a, false, true, false);
  }  //mmuTranslateReadSuperData(int)

  //pa = mmuTranslateReadSuperCode (a)
  //  アドレス変換を行う(リードスーパーバイザコード)
  //    pa  物理アドレス
  //    a   論理アドレス
  //  m60FSLWのMA,RW,SIZE,TM,IOをセットしてから呼び出すこと
  public static int mmuTranslateReadSuperCode (int a) throws M68kException {
    int logicalPage = a & mmuPageAddressMask;  //論理ページアドレス
    int head = (logicalPage * MMU_HASH_COEFF >>> -MMU_HASH_BITS) * (4 * MMU_CACHE_WAYS);  //先頭のエントリ
    if (mmuSuperCodeCache[head] == logicalPage) {  //リード用の論理ページアドレスと一致した
      if (CAT_ON) {
        catCM = (mmuSuperCodeCache[head + 3] >> 5) & 3;  //キャッシュモード
      }
      return mmuSuperCodeCache[head + 2] | (a & mmuPageOffsetMask);  //物理ページアドレスとページオフセットを連結する
    }
    if (MMU_CACHE_WAYS >= 2) {  //2ways以上
      int tail = head + (4 * MMU_CACHE_WAYS - 4);  //末尾のエントリ
      for (int i = head + 4; i <= tail; i += 4) {
        if (mmuSuperCodeCache[i] == logicalPage) {  //リード用の論理ページアドレスと一致した
          //int logicalRead  = mmuSuperCodeCache[i    ];
          int logicalWrite = mmuSuperCodeCache[i + 1];
          int physicalPage = mmuSuperCodeCache[i + 2];
          int flag = mmuSuperCodeCache[i + 3];
          for (; i > head; i -= 4) {
            mmuSuperCodeCache[i    ] = mmuSuperCodeCache[i - 4];
            mmuSuperCodeCache[i + 1] = mmuSuperCodeCache[i - 3];
            mmuSuperCodeCache[i + 2] = mmuSuperCodeCache[i - 2];
            mmuSuperCodeCache[i + 3] = mmuSuperCodeCache[i - 1];
          }
          mmuSuperCodeCache[head    ] = logicalPage;  //logicalRead
          mmuSuperCodeCache[head + 1] = logicalWrite;
          mmuSuperCodeCache[head + 2] = physicalPage;
          mmuSuperCodeCache[head + 3] = flag;
          return physicalPage | (a & mmuPageOffsetMask);  //物理ページアドレスとページオフセットを連結する
        }
      }  //for i
    }
    return mmuTranslateCommon (a, false, true, true);
  }  //mmuTranslateReadSuperCode(int)

  //pa = mmuTranslateWriteUserData (a)
  //  アドレス変換を行う(ライトユーザデータ)
  //    pa  物理アドレス
  //    a   論理アドレス
  //  m60FSLWのMA,RW,SIZE,TM,IOをセットしてから呼び出すこと
  public static int mmuTranslateWriteUserData (int a) throws M68kException {
    int logicalPage = a & mmuPageAddressMask;  //論理ページアドレス
    int head = (logicalPage * MMU_HASH_COEFF >>> -MMU_HASH_BITS) * (4 * MMU_CACHE_WAYS);  //先頭のエントリ
    if (mmuUserDataCache[head + 1] == logicalPage) {  //ライト用の論理ページアドレスと一致した
      if (CAT_ON) {
        catCM = (mmuUserDataCache[head + 3] >> 5) & 3;  //キャッシュモード
      }
      return mmuUserDataCache[head + 2] | (a & mmuPageOffsetMask);  //物理ページアドレスとページオフセットを連結する
    }
    if (MMU_CACHE_WAYS >= 2) {  //2ways以上
      int tail = head + (4 * MMU_CACHE_WAYS - 4);  //末尾のエントリ
      for (int i = head + 4; i <= tail; i += 4) {
        if (mmuUserDataCache[i + 1] == logicalPage) {  //ライト用の論理ページアドレスと一致した
          int logicalRead  = mmuUserDataCache[i    ];
          //int logicalWrite = mmuUserDataCache[i + 1];
          int physicalPage = mmuUserDataCache[i + 2];
          int flag = mmuUserDataCache[i + 3];
          for (; i > head; i -= 4) {
            mmuUserDataCache[i    ] = mmuUserDataCache[i - 4];
            mmuUserDataCache[i + 1] = mmuUserDataCache[i - 3];
            mmuUserDataCache[i + 2] = mmuUserDataCache[i - 2];
            mmuUserDataCache[i + 3] = mmuUserDataCache[i - 1];
          }
          mmuUserDataCache[i    ] = logicalRead;
          mmuUserDataCache[i + 1] = logicalPage;  //logicalWrite
          mmuUserDataCache[i + 2] = physicalPage;
          mmuUserDataCache[i + 3] = flag;
          return physicalPage | (a & mmuPageOffsetMask);  //物理ページアドレスとページオフセットを連結する
        }
      }  //for i
    }
    return mmuTranslateCommon (a, true, false, false);
  }  //mmuTranslateWriteUserData(int)

  //pa = mmuTranslateWriteUserCode (a)
  //  アドレス変換を行う(ライトユーザコード)
  //    pa  物理アドレス
  //    a   論理アドレス
  //  m60FSLWのMA,RW,SIZE,TM,IOをセットしてから呼び出すこと
  public static int mmuTranslateWriteUserCode (int a) throws M68kException {
    int logicalPage = a & mmuPageAddressMask;  //論理ページアドレス
    int head = (logicalPage * MMU_HASH_COEFF >>> -MMU_HASH_BITS) * (4 * MMU_CACHE_WAYS);  //先頭のエントリ
    if (mmuUserCodeCache[head + 1] == logicalPage) {  //ライト用の論理ページアドレスと一致した
      if (CAT_ON) {
        catCM = (mmuUserCodeCache[head + 3] >> 5) & 3;  //キャッシュモード
      }
      return mmuUserCodeCache[head + 2] | (a & mmuPageOffsetMask);  //物理ページアドレスとページオフセットを連結する
    }
    if (MMU_CACHE_WAYS >= 2) {  //2ways以上
      int tail = head + (4 * MMU_CACHE_WAYS - 4);  //末尾のエントリ
      for (int i = head + 4; i <= tail; i += 4) {
        if (mmuUserCodeCache[i + 1] == logicalPage) {  //ライト用の論理ページアドレスと一致した
          int logicalRead  = mmuUserCodeCache[i    ];
          //int logicalWrite = mmuUserCodeCache[i + 1];
          int physicalPage = mmuUserCodeCache[i + 2];
          int flag = mmuUserCodeCache[i + 3];
          for (; i > head; i -= 4) {
            mmuUserCodeCache[i    ] = mmuUserCodeCache[i - 4];
            mmuUserCodeCache[i + 1] = mmuUserCodeCache[i - 3];
            mmuUserCodeCache[i + 2] = mmuUserCodeCache[i - 2];
            mmuUserCodeCache[i + 3] = mmuUserCodeCache[i - 1];
          }
          mmuUserCodeCache[head    ] = logicalRead;
          mmuUserCodeCache[head + 1] = logicalPage;  //logicalWrite
          mmuUserCodeCache[head + 2] = physicalPage;
          mmuUserCodeCache[head + 3] = flag;
          return physicalPage | (a & mmuPageOffsetMask);  //物理ページアドレスとページオフセットを連結する
        }
      }  //for i
    }
    return mmuTranslateCommon (a, true, false, true);
  }  //mmuTranslateWriteUserCode(int)

  //pa = mmuTranslateWriteSuperData (a)
  //  アドレス変換を行う(ライトスーパーバイザデータ)
  //    pa  物理アドレス
  //    a   論理アドレス
  //  m60FSLWのMA,RW,SIZE,TM,IOをセットしてから呼び出すこと
  public static int mmuTranslateWriteSuperData (int a) throws M68kException {
    int logicalPage = a & mmuPageAddressMask;  //論理ページアドレス
    int head = (logicalPage * MMU_HASH_COEFF >>> -MMU_HASH_BITS) * (4 * MMU_CACHE_WAYS);  //先頭のエントリ
    if (mmuSuperDataCache[head + 1] == logicalPage) {  //ライト用の論理ページアドレスと一致した
      if (CAT_ON) {
        catCM = (mmuSuperDataCache[head + 3] >> 5) & 3;  //キャッシュモード
      }
      return mmuSuperDataCache[head + 2] | (a & mmuPageOffsetMask);  //物理ページアドレスとページオフセットを連結する
    }
    if (MMU_CACHE_WAYS >= 2) {  //2ways以上
      int tail = head + (4 * MMU_CACHE_WAYS - 4);  //末尾のエントリ
      for (int i = head + 4; i <= tail; i += 4) {
        if (mmuSuperDataCache[i + 1] == logicalPage) {  //ライト用の論理ページアドレスと一致した
          int logicalRead  = mmuSuperDataCache[i    ];
          //int logicalWrite = mmuSuperDataCache[i + 1];
          int physicalPage = mmuSuperDataCache[i + 2];
          int flag = mmuSuperDataCache[i + 3];
          for (; i > head; i -= 4) {
            mmuSuperDataCache[i    ] = mmuSuperDataCache[i - 4];
            mmuSuperDataCache[i + 1] = mmuSuperDataCache[i - 3];
            mmuSuperDataCache[i + 2] = mmuSuperDataCache[i - 2];
            mmuSuperDataCache[i + 3] = mmuSuperDataCache[i - 1];
          }
          mmuSuperDataCache[i    ] = logicalRead;
          mmuSuperDataCache[i + 1] = logicalPage;  //logicalWrite
          mmuSuperDataCache[i + 2] = physicalPage;
          mmuSuperDataCache[i + 3] = flag;
          return physicalPage | (a & mmuPageOffsetMask);  //物理ページアドレスとページオフセットを連結する
        }
      }  //for i
    }
    return mmuTranslateCommon (a, true, true, false);
  }  //mmuTranslateWriteSuperData(int)

  //pa = mmuTranslateWriteSuperCode (a)
  //  アドレス変換を行う(ライトスーパーバイザコード)
  //    pa  物理アドレス
  //    a   論理アドレス
  //  m60FSLWのMA,RW,SIZE,TM,IOをセットしてから呼び出すこと
  public static int mmuTranslateWriteSuperCode (int a) throws M68kException {
    int logicalPage = a & mmuPageAddressMask;  //論理ページアドレス
    int head = (logicalPage * MMU_HASH_COEFF >>> -MMU_HASH_BITS) * (4 * MMU_CACHE_WAYS);  //先頭のエントリ
    if (mmuSuperCodeCache[head + 1] == logicalPage) {  //ライト用の論理ページアドレスと一致した
      if (CAT_ON) {
        catCM = (mmuSuperCodeCache[head + 3] >> 5) & 3;  //キャッシュモード
      }
      return mmuSuperCodeCache[head + 2] | (a & mmuPageOffsetMask);  //物理ページアドレスとページオフセットを連結する
    }
    if (MMU_CACHE_WAYS >= 2) {  //2ways以上
      int tail = head + (4 * MMU_CACHE_WAYS - 4);  //末尾のエントリ
      for (int i = head + 4; i <= tail; i += 4) {
        if (mmuSuperCodeCache[i + 1] == logicalPage) {  //ライト用の論理ページアドレスと一致した
          int logicalRead  = mmuSuperCodeCache[i    ];
          //int logicalWrite = mmuSuperCodeCache[i + 1];
          int physicalPage = mmuSuperCodeCache[i + 2];
          int flag = mmuSuperCodeCache[i + 3];
          for (; i > head; i -= 4) {
            mmuSuperCodeCache[i    ] = mmuSuperCodeCache[i - 4];
            mmuSuperCodeCache[i + 1] = mmuSuperCodeCache[i - 3];
            mmuSuperCodeCache[i + 2] = mmuSuperCodeCache[i - 2];
            mmuSuperCodeCache[i + 3] = mmuSuperCodeCache[i - 1];
          }
          mmuSuperCodeCache[head    ] = logicalRead;
          mmuSuperCodeCache[head + 1] = logicalPage;  //logicalWrite
          mmuSuperCodeCache[head + 2] = physicalPage;
          mmuSuperCodeCache[head + 3] = flag;
          return physicalPage | (a & mmuPageOffsetMask);  //物理ページアドレスとページオフセットを連結する
        }
      }  //for i
    }
    return mmuTranslateCommon (a, true, true, true);
  }  //mmuTranslateWriteSuperCode(int)

  //pa = mmuTranslateCommon (a, write, supervisor, instruction)
  //  透過変換とテーブルサーチを行い、アドレス変換キャッシュ更新する
  //  アドレス変換キャッシュがミスしたときに呼び出す
  //    pa           物理アドレス
  //    a            論理アドレス
  //    write        true=ライト,false=リード
  //    supervisor   true=スーパーバイザ,false=ユーザ。通常はXEiJ.regSRS!=0、PLPAR/PLPAWでは(XEiJ.mpuDFC&4)!=0
  //    instruction  true=命令,false=データ。通常は命令フェッチまたは拡張ワードのときtrue、PLPAR/PLPAWでは(XEiJ.mpuDFC&2)!=0
  //  m60FSLWのMA,RW,SIZE,TM,IOをセットしてから呼び出すこと
  public static int mmuTranslateCommon (int a, boolean write, boolean supervisor, boolean instruction) throws M68kException {
    if (MMU_DEBUG_TRANSLATION) {
      System.out.printf ("%08x mmuTranslateCommon(0x%08x,%b,%b,%b)", XEiJ.regPC0, a, write, supervisor, instruction);
    }
    int logicalPage = a & mmuPageAddressMask;  //リード用の論理ページアドレス
    int logicalWrite;  //ライト用の論理ページアドレス
    int physicalPage;  //物理ページアドレス
    int flag;  //フラグ。bit10:グローバル,bit6-5:キャッシュモード
    int pa;  //物理アドレス
    //透過変換
    //  透過変換はスーパーバイザモードかどうかを条件にすることができる(しないこともできる)
    //    条件が合わなければヒットしないだけで、スーパーバイザプロテクトのアクセスフォルトになならない
    //  透過変換をアドレス変換キャッシュに乗せる場合
    //    アドレス変換キャッシュがヒットしてバスエラーが発生したとき
    //      透過変換かどうかを再確認してFSLWのTTRをセットしなければならない
    //    透過変換レジスタが操作されたとき
    //      OFF→ONの領域だけでなくON→OFFの領域もフラッシュしなければならない
    //      透過変換レジスタを頻繁に操作されると重くなるかも知れない
    int tt = (supervisor ?
              instruction ? mmuTTSuperCode1 : mmuTTSuperData1 :
              instruction ? mmuTTUserCode1 : mmuTTUserData1)[a >>> 24];
    if (tt != 0) {  //透過変換あり
      m60FSLW |= M60_FSLW_TRANSPARENT;
      if (write &&  //ライトで
          tt < 0) {  //透過変換によるライトプロテクト
        if (MMU_DEBUG_TRANSLATION) {
          System.out.printf (" write protected by transparent translation\n", a);
        }
        m60FSLW |= M60_FSLW_WRITE_PROTECT;
        M68kException.m6eNumber = M68kException.M6E_ACCESS_FAULT;
        //m60Address = a;
        throw M68kException.m6eSignal;
      }
      logicalWrite = logicalPage;  //ライト用の論理ページアドレス
      physicalPage = logicalPage;  //物理ページアドレス
      flag = MMU_DESCRIPTOR_GLOBAL | (tt & MMU_TTR_CACHE_MODE);  //グローバル、キャッシュモード
      pa = a;
      if (MMU_DEBUG_TRANSLATION) {
        System.out.printf ("=0x%08x (transparent translation)\n", pa);
      }
    } else if (mmuEnabled) {  //透過変換なし、アドレス変換あり
      //テーブルサーチ
      //  スーパーバイザプロテクトまたはライトプロテクトで停止したときデスクリプタの使用済みフラグはセットされない
      //  リードモディファイライトはライトでアロケートするのでリードする前にライトプロテクトに引っかかる
      //    例えばROMの内容をインクリメントしようとしたときライトだけでなくリードも行われない
      m60FSLW |= M60_FSLW_TABLE_SEARCH;  //これはbus error on table searchなのでそれ以外は消すこと
      //TMを保存して書き換える
      int xorTM = ((m60FSLW & M60_FSLW_TRANSFER_MODIFIER) ^
                   (instruction ? M60_FSLW_TM_MMU_CODE : M60_FSLW_TM_MMU_DATA));
      m60FSLW ^= xorTM;
      //ルートテーブル
      int rootDescriptorAddress = (supervisor ? mmuSRP : mmuURP) + ((a & MMU_ROOT_INDEX_MASK) >>> MMU_ROOT_INDEX_BIT0 - 2);  //ルートテーブルデスクリプタのアドレス
      MemoryMappedDevice rootDescriptorDevice = (DataBreakPoint.DBP_ON ? DataBreakPoint.dbpSuperMap : XEiJ.busSuperMap)[rootDescriptorAddress >>> XEiJ.BUS_PAGE_BITS];
      int rootDescriptor = rootDescriptorDevice.mmdRls (rootDescriptorAddress);  //ルートテーブルデスクリプタ
      if ((rootDescriptor & MMU_DESCRIPTOR_UDT) == MMU_DESCRIPTOR_TYPE_INVALID) {  //デスクリプタが無効のとき
        if (MMU_DEBUG_TRANSLATION) {
          System.out.printf (" invalid root descriptor 0x%08x at 0x%08x\n", rootDescriptor, rootDescriptorAddress);
        }
        m60FSLW ^= M60_FSLW_TABLE_SEARCH ^ M60_FSLW_ROOT_DESCRIPTOR;
        M68kException.m6eNumber = M68kException.M6E_ACCESS_FAULT;
        //m60Address = a;
        throw M68kException.m6eSignal;
      }
      if (write &&  //ライトで
          (rootDescriptor & MMU_DESCRIPTOR_WRITE_PROTECTED) != 0) {  //ライトプロテクトされているとき
        if (MMU_DEBUG_TRANSLATION) {
          System.out.printf (" write protected by root descriptor 0x%08x at 0x%08x\n", rootDescriptor, rootDescriptorAddress);
        }
        m60FSLW ^= M60_FSLW_TABLE_SEARCH ^ M60_FSLW_WRITE_PROTECT;
        M68kException.m6eNumber = M68kException.M6E_ACCESS_FAULT;
        //m60Address = a;
        throw M68kException.m6eSignal;
      }
      if ((rootDescriptor & MMU_DESCRIPTOR_USED) == 0) {  //デスクリプタが未使用のとき
        rootDescriptor |= MMU_DESCRIPTOR_USED;  //使用済み
        rootDescriptorDevice.mmdWl (rootDescriptorAddress, rootDescriptor);
      }
      //ポインタテーブル
      int pointerDescriptorAddress = (rootDescriptor & MMU_DESCRIPTOR_POINTER_TABLE_ADDRESS) + ((a & MMU_POINTER_INDEX_MASK) >>> MMU_POINTER_INDEX_BIT0 - 2);  //ポインタテーブルデスクリプタのアドレス
      MemoryMappedDevice pointerDescriptorDevice = (DataBreakPoint.DBP_ON ? DataBreakPoint.dbpSuperMap : XEiJ.busSuperMap)[pointerDescriptorAddress >>> XEiJ.BUS_PAGE_BITS];
      int pointerDescriptor = pointerDescriptorDevice.mmdRls (pointerDescriptorAddress);  //ポインタテーブルデスクリプタ
      if ((pointerDescriptor & MMU_DESCRIPTOR_UDT) == MMU_DESCRIPTOR_TYPE_INVALID) {  //デスクリプタが無効のとき
        if (MMU_DEBUG_TRANSLATION) {
          System.out.printf (" invalid pointer descriptor 0x%08x at 0x%08x\n", pointerDescriptor, pointerDescriptorAddress);
        }
        m60FSLW ^= M60_FSLW_TABLE_SEARCH ^ M60_FSLW_POINTER_DESCRIPTOR;
        M68kException.m6eNumber = M68kException.M6E_ACCESS_FAULT;
        //m60Address = a;
        throw M68kException.m6eSignal;
      }
      if (write &&  //ライトで
          (pointerDescriptor & MMU_DESCRIPTOR_WRITE_PROTECTED) != 0) {  //ライトプロテクトされているとき
        if (MMU_DEBUG_TRANSLATION) {
          System.out.printf (" write protected by pointer descriptor 0x%08x at 0x%08x\n", pointerDescriptor, pointerDescriptorAddress);
        }
        m60FSLW ^= M60_FSLW_TABLE_SEARCH ^ M60_FSLW_WRITE_PROTECT;
        M68kException.m6eNumber = M68kException.M6E_ACCESS_FAULT;
        //m60Address = a;
        throw M68kException.m6eSignal;
      }
      if ((pointerDescriptor & MMU_DESCRIPTOR_USED) == 0) {  //デスクリプタが未使用のとき
        pointerDescriptor |= MMU_DESCRIPTOR_USED;  //使用済み
        pointerDescriptorDevice.mmdWl (pointerDescriptorAddress, pointerDescriptor);
      }
      //ページテーブル
      int pageDescriptorAddress = (pointerDescriptor & mmuPageTableMask) + ((a & mmuPageIndexMask) >>> mmuPageIndexBit2);  //ページテーブルデスクリプタのアドレス
      MemoryMappedDevice pageDescriptorDevice = (DataBreakPoint.DBP_ON ? DataBreakPoint.dbpSuperMap : XEiJ.busSuperMap)[pageDescriptorAddress >>> XEiJ.BUS_PAGE_BITS];
      int pageDescriptor = pageDescriptorDevice.mmdRls (pageDescriptorAddress);  //ページテーブルデスクリプタ
      if ((pageDescriptor & MMU_DESCRIPTOR_PDT) == MMU_DESCRIPTOR_TYPE_INVALID) {  //デスクリプタが無効のとき
        if (MMU_DEBUG_TRANSLATION) {
          System.out.printf (" invalid page descriptor 0x%08x at 0x%08x\n", pageDescriptor, pageDescriptorAddress);
        }
        m60FSLW ^= M60_FSLW_TABLE_SEARCH ^ M60_FSLW_PAGE_FAULT;
        M68kException.m6eNumber = M68kException.M6E_ACCESS_FAULT;
        //m60Address = a;
        throw M68kException.m6eSignal;
      }
      if ((pageDescriptor & MMU_DESCRIPTOR_PDT) == MMU_DESCRIPTOR_TYPE_INDIRECT) {  //デスクリプタが間接のとき
        pageDescriptorAddress = pageDescriptor & MMU_DESCRIPTOR_INDIRECT_ADDRESS;  //ページテーブルデスクリプタのアドレス
        pageDescriptorDevice = (DataBreakPoint.DBP_ON ? DataBreakPoint.dbpSuperMap : XEiJ.busSuperMap)[pageDescriptorAddress >>> XEiJ.BUS_PAGE_BITS];
        pageDescriptor = pageDescriptorDevice.mmdRls (pageDescriptorAddress);  //ページテーブルデスクリプタ
        if ((pageDescriptor & MMU_DESCRIPTOR_PDT) == MMU_DESCRIPTOR_TYPE_INVALID) {  //デスクリプタが無効のとき
          if (MMU_DEBUG_TRANSLATION) {
            System.out.printf (" invalid page descriptor 0x%08x at 0x%08x\n", pageDescriptor, pageDescriptorAddress);
          }
          m60FSLW ^= M60_FSLW_TABLE_SEARCH ^ M60_FSLW_PAGE_FAULT;
          M68kException.m6eNumber = M68kException.M6E_ACCESS_FAULT;
          //m60Address = a;
          throw M68kException.m6eSignal;
        }
        if ((pageDescriptor & MMU_DESCRIPTOR_PDT) == MMU_DESCRIPTOR_TYPE_INDIRECT) {  //デスクリプタが二重間接のとき
          if (MMU_DEBUG_TRANSLATION) {
            System.out.printf (" indirect page descriptor 0x%08x at 0x%08x\n", pageDescriptor, pageDescriptorAddress);
          }
          m60FSLW ^= M60_FSLW_TABLE_SEARCH ^ M60_FSLW_INDIRECT_LEVEL;
          M68kException.m6eNumber = M68kException.M6E_ACCESS_FAULT;
          //m60Address = a;
          throw M68kException.m6eSignal;
        }
      }
      if (!supervisor &&  //ユーザモードで
          (pageDescriptor & MMU_DESCRIPTOR_SUPERVISOR_PROTECTED) != 0) {  //スーパーバイザプロテクトされているとき
        if (MMU_DEBUG_TRANSLATION) {
          System.out.printf (" supervisor protected by page descriptor 0x%08x at 0x%08x\n", pageDescriptor, pageDescriptorAddress);
        }
        m60FSLW ^= M60_FSLW_TABLE_SEARCH ^ M60_FSLW_SUPERVISOR_PROTECT;
        M68kException.m6eNumber = M68kException.M6E_ACCESS_FAULT;
        //m60Address = a;
        throw M68kException.m6eSignal;
      }
      if (write &&  //ライトで
          (pageDescriptor & MMU_DESCRIPTOR_WRITE_PROTECTED) != 0) {  //ライトプロテクトされているとき
        if (MMU_DEBUG_TRANSLATION) {
          System.out.printf (" write protected by page descriptor 0x%08x at 0x%08x\n", pageDescriptor, pageDescriptorAddress);
        }
        m60FSLW ^= M60_FSLW_TABLE_SEARCH ^ M60_FSLW_WRITE_PROTECT;
        M68kException.m6eNumber = M68kException.M6E_ACCESS_FAULT;
        //m60Address = a;
        throw M68kException.m6eSignal;
      }
      {
        int t = pageDescriptor;
        if ((pageDescriptor & MMU_DESCRIPTOR_USED) == 0) {  //デスクリプタが未使用のとき
          pageDescriptor |= MMU_DESCRIPTOR_USED;  //使用済みにする
        }
        if (write &&  //ライトで
            (pageDescriptor & MMU_DESCRIPTOR_MODIFIED) == 0) {  //修正済みでないとき
          pageDescriptor |= MMU_DESCRIPTOR_MODIFIED;  //修正済みにする
        }
        if (t != pageDescriptor) {
          pageDescriptorDevice.mmdWl (pageDescriptorAddress, pageDescriptor);
        }
      }
      //テーブルサーチ終了
      m60FSLW &= ~M60_FSLW_TABLE_SEARCH;
      //TMを復元する
      m60FSLW ^= xorTM;
      //logicalWrite = (pageDescriptor & (MMU_DESCRIPTOR_MODIFIED | MMU_DESCRIPTOR_WRITE_PROTECTED)) == MMU_DESCRIPTOR_MODIFIED ? logicalPage : 1;  //ライト用の論理ページアドレス。修正済みかつライトプロテクトされていないときだけ有効
      logicalWrite = (pageDescriptor & MMU_DESCRIPTOR_WRITE_PROTECTED) == 0 ? logicalPage : 1;  //ライト用の論理ページアドレス。ライトプロテクトされていないときだけ有効
      physicalPage = pageDescriptor & mmuPageAddressMask;  //物理ページアドレス
      flag = pageDescriptor & (MMU_DESCRIPTOR_GLOBAL |  //グローバル
                               MMU_DESCRIPTOR_CACHE_MODE);  //キャッシュモード
      pa = physicalPage | a & mmuPageOffsetMask;  //物理ページアドレスとページオフセットを連結する
      if (MMU_DEBUG_TRANSLATION) {
        System.out.printf ("=0x%08x (table search)\n", pa);
        System.out.printf ("  rootTable=0x%08x\n", supervisor ? mmuSRP : mmuURP);
        System.out.printf ("  rootIndex=0x%08x\n", (a & MMU_ROOT_INDEX_MASK) >>> MMU_ROOT_INDEX_BIT0);
        System.out.printf ("  rootDescriptorAddress=0x%08x\n", rootDescriptorAddress);
        System.out.printf ("  rootDescriptor=0x%08x\n", rootDescriptor);
        System.out.printf ("  pointerTable=0x%08x\n", rootDescriptor & MMU_DESCRIPTOR_POINTER_TABLE_ADDRESS);
        System.out.printf ("  pointerIndex=0x%08x\n", (a & MMU_POINTER_INDEX_MASK) >>> MMU_POINTER_INDEX_BIT0);
        System.out.printf ("  pointerDescriptorAddress=0x%08x\n", pointerDescriptorAddress);
        System.out.printf ("  pointerDescriptor=0x%08x\n", pointerDescriptor);
        System.out.printf ("  pageTable=0x%08x\n", pointerDescriptor & mmuPageTableMask);
        System.out.printf ("  pageIndex=0x%08x\n", (a & mmuPageIndexMask) >>> mmuPageIndexBit2 + 2);
        System.out.printf ("  pageDescriptorAddress=0x%08x\n", pageDescriptorAddress);
        System.out.printf ("  pageDescriptor=0x%08x\n", pageDescriptor);
      }
    } else {  //透過変換なし、アドレス変換なし
      logicalWrite = logicalPage;  //ライト用の論理ページアドレス
      physicalPage = logicalPage;  //物理ページアドレス
      flag = MMU_DESCRIPTOR_GLOBAL | ((mmuTCR >> (instruction ? 4 : 8)) & 3);  //グローバル、デフォルトキャッシュモード。DCOまたはDCI
      pa = a;
      if (MMU_DEBUG_TRANSLATION) {
        System.out.printf ("=0x%08x (no translation)\n", pa);
      }
    }
    if (!(MMU_NOT_ALLOCATE_CACHE ||
          (instruction ? mmuNotAllocateCode : mmuNotAllocateData))) {
      //アドレス変換キャッシュを更新する
      //  同じ論理ページアドレスのエントリが存在する場合
      //    (リードでアロケートしたとき修正済みでなかったためライトでアロケートしなかった場合)
      //    同じ論理ページアドレスのエントリよりも前にあるエントリを後ろにずらす
      //    空いた先頭のエントリに上書きする
      //  同じ論理ページアドレスのエントリが存在しない場合
      //    末尾以外のエントリを後ろにずらす
      //    空いた先頭のエントリに上書きする
      int[] cache = (supervisor ?
                     instruction ? mmuSuperCodeCache : mmuSuperDataCache :
                     instruction ? mmuUserCodeCache : mmuUserDataCache);
      int head = (logicalPage * MMU_HASH_COEFF >>> -MMU_HASH_BITS) * (4 * MMU_CACHE_WAYS);  //先頭のエントリ
      if (MMU_CACHE_WAYS >= 2) {  //2ways以上のとき
        int tail = head + (4 * MMU_CACHE_WAYS - 4);  //末尾のエントリ→捨てるエントリ
        if (write) {  //ライトのとき
          for (int i = head; i < tail; i += 4) {
            if (cache[i] == logicalPage) {  //リードでアロケートされていた
              tail = i;
              break;
            }
          }
        }
        //  捨てるエントリよりも前にあるエントリを後ろにずらす
        for (; tail > head; tail -= 4) {
          cache[tail    ] = cache[tail - 4];
          cache[tail + 1] = cache[tail - 3];
          cache[tail + 2] = cache[tail - 2];
          cache[tail + 3] = cache[tail - 1];
        }
      }
      //  先頭のエントリに上書きする
      cache[head    ] = logicalPage;  //リード用の論理ページアドレス
      cache[head + 1] = logicalWrite;  //ライト用の論理ページアドレス
      cache[head + 2] = physicalPage;  //物理ページアドレス
      cache[head + 3] = flag;  //フラグ
      if (MMU_DEBUG_TRANSLATION) {
        System.out.printf ("  ATC[%d]={0x%08x,0x%08x,0x%08x,0x%08x}\n",
                           head / (4 * MMU_CACHE_WAYS), logicalPage, logicalWrite, physicalPage, flag);
      }
    }
    if (CAT_ON) {
      catCM = (flag >> 5) & 3;  //キャッシュモード
    }
    return pa;
  }  //mmuTranslateCommon(int,boolean,boolean,boolean)

  public static int mmuPeekFlags;

  //pa = mmuTranslatePeek (a, supervisor, instruction) {
  //  アドレス変換を行う(デバッガ用、例外なし、テーブル更新なし)
  //    pa           物理アドレス。a^1=エラー
  //    a            論理アドレス
  //    supervisor   0=ユーザ,0以外=スーパーバイザ。通常はXEiJ.regSRS、PLPAR/PLPAWではXEiJ.mpuDFC&4
  //    instruction  0=データ,0以外=命令。通常は命令フェッチまたは拡張ワードのとき1、PLPAR/PLPAWではXEiJ.mpuDFC&2
  public static int mmuTranslatePeek (int a, int supervisor, int instruction) {
    //透過変換の確認
    //  透過変換はスーパーバイザモードかどうかを条件にすることができる(しないこともできる)
    //  透過変換にスーパーバイザプロテクトの機能はない
    {
      int[] tta = new int[2];
      if (instruction != 0) {
        tta[0] = mmuITT0;
        tta[1] = mmuITT1;
      } else {
        tta[0] = mmuDTT0;
        tta[1] = mmuDTT1;
      }
      for (int i = 0; i < 2; i++) {
        int ttr = tta[i];
        if ((ttr & 0x8000) != 0 &&  //Enable
            ((ttr & 0x4000) != 0 || ((ttr & 0x2000) != 0) == (supervisor != 0)) &&
            ((a ^ ttr) & ~ttr << 8) >>> 24 == 0) {
          mmuPeekFlags = ttr & MMU_TTR_WRITE_PROTECT;
          return a;
        }
      }
    }
    //透過変換なし
    if (!mmuEnabled) {  //アドレス変換なし
      mmuPeekFlags = 0;
      return a;
    }
    //アドレス変換あり
    int logicalPage = a & mmuPageAddressMask;  //論理ページアドレス
    //テーブルサーチ開始
    //  スーパーバイザプロテクトまたはライトプロテクトで停止したときデスクリプタの使用済みフラグはセットされない
    //  リードモディファイライトはライトでアロケートするのでリードする前にライトプロテクトに引っかかる
    //    例えばROMの内容をインクリメントしようとしたときライトだけでなくリードも行われない
    //ルートテーブル
    int rootDescriptorAddress = (supervisor != 0 ? mmuSRP : mmuURP) + ((a & MMU_ROOT_INDEX_MASK) >>> MMU_ROOT_INDEX_BIT0 - 2);  //ルートテーブルデスクリプタのアドレス
    int rootDescriptor = XEiJ.busPlsf (rootDescriptorAddress);  //ルートテーブルデスクリプタ
    if ((rootDescriptor & MMU_DESCRIPTOR_UDT) == MMU_DESCRIPTOR_TYPE_INVALID) {  //デスクリプタが無効のとき
      return a ^ 1;
    }
    //ポインタテーブル
    int pointerDescriptorAddress = (rootDescriptor & MMU_DESCRIPTOR_POINTER_TABLE_ADDRESS) + ((a & MMU_POINTER_INDEX_MASK) >>> MMU_POINTER_INDEX_BIT0 - 2);  //ポインタテーブルデスクリプタのアドレス
    int pointerDescriptor = XEiJ.busPlsf (pointerDescriptorAddress);  //ポインタテーブルデスクリプタ
    if ((pointerDescriptor & MMU_DESCRIPTOR_UDT) == MMU_DESCRIPTOR_TYPE_INVALID) {  //デスクリプタが無効のとき
      return a ^ 1;
    }
    //ページテーブル
    int pageDescriptorAddress = (pointerDescriptor & mmuPageTableMask) + ((a & mmuPageIndexMask) >>> mmuPageIndexBit2);  //ページテーブルデスクリプタのアドレス
    int pageDescriptor = XEiJ.busPlsf (pageDescriptorAddress);  //ページテーブルデスクリプタ
    if ((pageDescriptor & MMU_DESCRIPTOR_PDT) == MMU_DESCRIPTOR_TYPE_INVALID) {  //デスクリプタが無効のとき
      return a ^ 1;
    }
    if ((pageDescriptor & MMU_DESCRIPTOR_PDT) == MMU_DESCRIPTOR_TYPE_INDIRECT) {  //デスクリプタが間接のとき
      pageDescriptorAddress = pageDescriptor & MMU_DESCRIPTOR_INDIRECT_ADDRESS;  //ページテーブルデスクリプタのアドレス
      pageDescriptor = XEiJ.busPlsf (pageDescriptorAddress);  //ページテーブルデスクリプタ
      if ((pageDescriptor & MMU_DESCRIPTOR_PDT) == MMU_DESCRIPTOR_TYPE_INVALID) {  //デスクリプタが無効のとき
        return a ^ 1;
      }
      if ((pageDescriptor & MMU_DESCRIPTOR_PDT) == MMU_DESCRIPTOR_TYPE_INDIRECT) {  //デスクリプタが二重間接のとき
        return a ^ 1;
      }
    }
    if (supervisor == 0 &&  //ユーザモードで
        (pageDescriptor & MMU_DESCRIPTOR_SUPERVISOR_PROTECTED) != 0) {  //スーパーバイザプロテクトされているとき
      return a ^ 1;
    }
    int physicalPage = pageDescriptor & mmuPageAddressMask;  //物理ページアドレス
    //テーブルサーチ終了
    mmuPeekFlags = pageDescriptor & (MMU_DESCRIPTOR_SUPERVISOR_PROTECTED |
                                     MMU_DESCRIPTOR_MODIFIED |
                                     MMU_DESCRIPTOR_USED |
                                     MMU_DESCRIPTOR_WRITE_PROTECTED);
    return physicalPage | a & mmuPageOffsetMask;  //物理ページアドレスとページオフセットを連結する
  }  //mmuTranslatePeek(int,int,int)



  //実効アドレス
  //  FIRSTのアドレス
  //  SECONDでアクセスフォルトが発生した場合でも、FORMAT $4の例外スタックフレームにはFIRSTのアドレスが書き込まれる
  //  M68kException.m6eAddressは実際にバスエラーが発生したアドレスを示しており、これはSECONDの場合がある
  private static int m60Address;

  //  MC68060のページフォルトに関する考察
  //    ページフォルトが発生すると、プレデクリメントとポストインクリメントによるアドレスレジスタの変化がすべてキャンセルされる
  //      MOVE.B (A0)+,(A0)+またはMOVE.B -(A0),-(A0)でソースまたはデスティネーションでページフォルトが発生したとき、
  //      どの組み合わせでもA0は命令開始時の値のままアクセスフォルトハンドラに移行する
  //    RTEでページフォルトを発生させた命令に復帰すると、ソースをリードするところからやり直す
  //      MOVE.B <mem>,<mem>のデスティネーションのライトでページフォルトが発生したとき、ソースのリードが2回行われる
  //      これはMC68060ユーザーズマニュアルの7.10 BUS SYNCHRONIZATIONに書かれており、
  //      060turboでも、ページフォルトのハンドラでソースを書き換えると結果に反映されることから、リードが再実行されていることを確認できる
  //      リードすると値が変化する可能性のあるデバイスから非常駐の可能性のあるページに転送するとき、MOVE.B <mem>,<mem>を使ってはいけない

  //アドレスレジスタの増分
  //  実効アドレスの計算でポストインクリメントまたはプレデクリメントのとき、
  //  アドレスレジスタを更新してそのままにするとページフォルトを起こした命令を再実行することができない
  //  MOVE.L (A0)+,(d16,A0)などでデスティネーションの実効アドレスの計算にソースの結果を反映させる必要があるので、
  //  アドレスレジスタは更新しておいてページフォルトのときだけ命令開始時の値に巻き戻す
  //  CMPM.L (A0)+,(A1)+やSUBX.L -(A0),-(A1)などでは複数の増分を並べるかまたは積まなければならない
  //    m60Incremented += (long) offset << (r << 3);
  //  で積むことにする
  //  巻き戻すとき負数に注意する
  private static long m60Incremented;

  //  FSLW  Fault Status Long Word
  //      31  30  29  28  27  26  25  24  23  22  21  20  19  18  17  16  15  14  13  12  11  10   9   8   7   6   5   4   3   2   1   0
  //    ┏━━━━━━━┯━┯━┯━┯━━━┯━━━┯━━━┯━━━━━┯━┯━┯━┯━┯━┯━┯━┯━┯━┯━┯━┯━┯━┯━┯━┯━┓
  //    ┃              │MA│  │LK│  RW  │ SIZE │  TT  │    TM    │IO│PBE SBE PTA PTB IL│PF│SP│WP│TWE RE│WE│TTR BPE    SEE┃
  //    ┗━━━━━━━┷━┷━┷━┷━━━┷━━━┷━━━┷━━━━━┷━┷━┷━┷━┷━┷━┷━┷━┷━┷━┷━┷━┷━┷━┷━┷━┛
  private static final int M60_FSLW_MISALIGNED         = 1 << 27;  //MA    Misaligned Access
  private static final int M60_FSLW_LOCKED             = 1 << 25;  //LK    Locked Transfer
  private static final int M60_FSLW_READ_AND_WRITE     = 3 << 23;  //RW    Read and Write
  private static final int M60_FSLW_RW_WRITE           = 1 << 23;  //        Write
  private static final int M60_FSLW_RW_READ            = 2 << 23;  //        Read
  private static final int M60_FSLW_RW_MODIFY          = 3 << 23;  //        Read-Modify-Write
  private static final int M60_FSLW_TRANSFER_SIZE      = 3 << 21;  //SIZE  Transfer Size
  private static final int M60_FSLW_SIZE_LONG          = 0 << 21;  //        Long    マニュアルが間違っているので注意
  private static final int M60_FSLW_SIZE_BYTE          = 1 << 21;  //        Byte    マニュアルが間違っているので注意
  private static final int M60_FSLW_SIZE_WORD          = 2 << 21;  //        Word    マニュアルが間違っているので注意
  private static final int M60_FSLW_SIZE_QUAD          = 3 << 21;  //        Double Precision or MOVE16
  private static final int M60_FSLW_TRANSFER_TYPE      = 3 << 19;  //TT    Transfer Type
  private static final int M60_FSLW_TT_NORMAL          = 0 << 19;  //        Normal Access
  private static final int M60_FSLW_TT_MOVE16          = 1 << 19;  //        MOVE16 Access
  private static final int M60_FSLW_TT_ALTERNATE       = 2 << 19;  //        Alternate Logical Function Code Access, Debug Access
  private static final int M60_FSLW_TT_ACKNOWLEDGE     = 3 << 19;  //        Acknowledge Access, Low-Power Stop Broadcast
  private static final int M60_FSLW_TRANSFER_MODIFIER  = 7 << 16;  //TM    Transfer Modifier
  private static final int M60_FSLW_TM_CACHE_PUSH      = 0 << 16;  //        Data Cache Push Access
  private static final int M60_FSLW_TM_USER_DATA       = 1 << 16;  //        User Data Access
  private static final int M60_FSLW_TM_USER_CODE       = 2 << 16;  //        User Code Access
  private static final int M60_FSLW_TM_MMU_DATA        = 3 << 16;  //        MMU Table Search Data Access
  private static final int M60_FSLW_TM_MMU_CODE        = 4 << 16;  //        MMU Table Search Code Access
  private static final int M60_FSLW_TM_SUPER_DATA      = 5 << 16;  //        Supervisor Data Access
  private static final int M60_FSLW_TM_SUPER_CODE      = 6 << 16;  //        Supervisor Code Access
  private static final int M60_FSLW_TM_DATA            = 1 << 16;  //        Data Access
  private static final int M60_FSLW_TM_CODE            = 2 << 16;  //        Code Access
  private static final int M60_FSLW_TM_SUPERVISOR      = 4 << 16;  //        Supervisor Access
  private static final int M60_FSLW_INSTRUCTION        = 1 << 15;  //IO    Instruction or Operand
  private static final int M60_FSLW_IOMA_FIRST         = 0 << 15 | 0 << 27;  //Fault occurred on the first access of a misaligned transfer, or to the only access of an aligned transfer
  private static final int M60_FSLW_IOMA_SECOND        = 0 << 15 | 1 << 27;  //Fault occurred on the second or later access of a misaligned transfer
  private static final int M60_FSLW_IOMA_OPWORD        = 1 << 15 | 0 << 27;  //Fault occurred on an instruction opword fetch
  private static final int M60_FSLW_IOMA_EXWORD        = 1 << 15 | 1 << 27;  //Fault occurred on a fetch of an extension word
  private static final int M60_FSLW_PUSH_BUFFER        = 1 << 14;  //PBE   Push Buffer Bus Error
  private static final int M60_FSLW_STORE_BUFFER       = 1 << 13;  //SBE   Store Buffer Bus Error
  private static final int M60_FSLW_ROOT_DESCRIPTOR    = 1 << 12;  //PTA   Pointer A Fault
  private static final int M60_FSLW_POINTER_DESCRIPTOR = 1 << 11;  //PTB   Pointer B Fault
  private static final int M60_FSLW_INDIRECT_LEVEL     = 1 << 10;  //IL    Indirect Level Fault
  private static final int M60_FSLW_PAGE_FAULT         = 1 <<  9;  //PF    Page Fault
  private static final int M60_FSLW_SUPERVISOR_PROTECT = 1 <<  8;  //SP    Supervisor Protect
  private static final int M60_FSLW_WRITE_PROTECT      = 1 <<  7;  //WP    Write Protect
  private static final int M60_FSLW_TABLE_SEARCH       = 1 <<  6;  //TWE   Bus Error on Table Search
  private static final int M60_FSLW_BUS_ERROR_ON_READ  = 1 <<  5;  //RE    Bus Error on Read
  private static final int M60_FSLW_BUS_ERROR_ON_WRITE = 1 <<  4;  //WE    Bus Error on Write
  private static final int M60_FSLW_TRANSPARENT        = 1 <<  3;  //TTR   TTR Hit
  private static final int M60_FSLW_BRANCH_PREDICTION  = 1 <<  2;  //BPE   Branch Prediction Error
  private static final int M60_FSLW_SOFTWARE_EMULATION = 1 <<  0;  //SEE   Software Emulation Error

  private static int m60FSLW;

  public static void m60BusErrorOnRead () {
    m60FSLW |= M60_FSLW_BUS_ERROR_ON_READ;
  }
  public static void m60BusErrorOnWrite () {
    m60FSLW |= M60_FSLW_BUS_ERROR_ON_WRITE;
  }

  private static final String[] M60_FSLW_TEXT_IOMA = {
    "IO=0,MA=0  First access of a misaligned transfer or only access of an aligned transfer",
    "IO=0,MA=1  Second or later access of a misaligned transfer",
    "IO=1,MA=0  Instruction opword fetch",
    "IO=1,MA=1  Fetch of an extension word",
  };
  private static final String[] M60_FSLW_TEXT_LK = {
    "LK=0       Not locked",
    "LK=1       Locked",
  };
  private static final String[] M60_FSLW_TEXT_RW = {
    "RW=0       Undefined, reserved",
    "RW=1       Write",
    "RW=2       Read",
    "RW=3       Read-Modify-Write",
  };
  private static final String[] M60_FSLW_TEXT_SIZE = {
    "SIZE=0     Byte",
    "SIZE=1     Word",
    "SIZE=2     Long",
    "SIZE=3     Double precision or MOVE16",
  };
  private static final String[] M60_FSLW_TEXT_TT = {
    "TT=0       Normal access",
    "TT=1       MOVE16 access",
    "TT=2       Alternate or debug access",
    "TT=3       Acknowledge or LPSTOP broadcast",
  };
  private static final String[] M60_FSLW_TEXT_TM = {
    "TM=0       Data cache push access",
    "TM=1       User data or MOVE16 access",
    "TM=2       User code access",
    "TM=3       MMU table search data access",
    "TM=4       MMU table search code access",
    "TM=5       Supervisor data access",
    "TM=6       Supervisor code access",
    "TM=7       Reserved",
    //"TM=0       Logical function code 0",
    //"TM=1       Debug access",
    //"TM=2       Reserved",
    //"TM=3       Logical function code 3",
    //"TM=4       Logical function code 4",
    //"TM=5       Debug pipe control mode access",
    //"TM=6       Debug pipe control mode access",
    //"TM=7       Logical function code 7",
  };
  private static final String[] M60_FSLW_TEXT_CAUSE = {
    "SEE=1      Software emulation error",  //0
    "",  //1
    "BPE=1      Branch prediction error",  //2
    "TTR=1      TTR hit",  //3
    "WE=1       Bus error on write",  //4
    "RE=1       Bus error on read",  //5
    "TWE=1      Bus error on table search",  //6
    "WP=1       Write protect",  //7
    "SP=1       Supervisor protect",  //8
    "PF=1       Page fault",  //9
    "IL=1       Indirect level fault",  //10
    "PTB=1      Pointer B fault",  //11
    "PTA=1      Pointer A fault",  //12
    "SBE=1      Store buffer bus error",  //13
    "PBE=1      Push buffer bus error",  //14
  };

  private static String m60ErrorToString () {
    StringBuilder sb = new StringBuilder ();
    int supervisor = m60FSLW & M60_FSLW_TM_SUPERVISOR;
    int instruction = m60FSLW & M60_FSLW_TM_CODE;
    if (0 <= M68kException.m6eNumber && M68kException.m6eNumber < M68kException.M6E_ERROR_NAME.length) {
      sb.append (M68kException.M6E_ERROR_NAME[M68kException.m6eNumber]);
    } else {
      sb.append ("undefined exception #").append (M68kException.m6eNumber);
    }
    XEiJ.fmtHex8 (sb.append (" at PC=$"), XEiJ.regPC0).append ("($");
    int pa = mmuTranslatePeek (XEiJ.regPC0, supervisor, 1);
    if ((XEiJ.regPC0 ^ pa) == 1) {
      sb.append ("????????");
    } else {
      XEiJ.fmtHex8 (sb, pa);
    }
    XEiJ.fmtHex4 (sb.append ("), SR=$"), XEiJ.regSRT1 | XEiJ.regSRS | XEiJ.regSRI | XEiJ.regCCR);
    //              111111111122222222223333333333444444444455555555556666
    //    0123456789012345678901234567890123456789012345678901234567890123
    if (0b0011011101000000000000000000000000000000000000000000000000000000L << M68kException.m6eNumber < 0L) {  //FORMAT $2,$4
      XEiJ.fmtHex8 (sb.append ("\n  Fault or effective address is EA=$"), m60Address).append ("($");
      pa = mmuTranslatePeek (m60Address, supervisor, instruction);
      if ((m60Address ^ pa) == 1) {
        sb.append ("????????");
      } else {
        XEiJ.fmtHex8 (sb, pa);
      }
      sb.append (')');
    }
    if (M68kException.m6eNumber == M68kException.M6E_ACCESS_FAULT) {  //FORMAT $4
      XEiJ.fmtHex8 (sb.append ("\n  Fault status long word is FSLW=$"), m60FSLW);
      sb.append ("\n  Fault was caused by:");
      for (int i = 14; i >= 0; i--) {
        if ((m60FSLW & (1 << i)) != 0) {
          sb.append ("\n    ").append (M60_FSLW_TEXT_CAUSE[i]);
        }
      }
      sb.append ("\n  Fault occured on:\n    ")
        .append (M60_FSLW_TEXT_IOMA[(m60FSLW & M60_FSLW_INSTRUCTION) >>> 15 - 1 | (m60FSLW & M60_FSLW_MISALIGNED) >>> 27])
          .append ("\n    ").append (M60_FSLW_TEXT_LK[(m60FSLW & M60_FSLW_LOCKED) >>> 25])
            .append ("\n    ").append (M60_FSLW_TEXT_RW[(m60FSLW & M60_FSLW_READ_AND_WRITE) >>> 23])
              .append ("\n    ").append (M60_FSLW_TEXT_SIZE[(m60FSLW & M60_FSLW_TRANSFER_SIZE) >>> 21])
                .append ("\n    ").append (M60_FSLW_TEXT_TT[(m60FSLW & M60_FSLW_TRANSFER_TYPE) >>> 19])
                  .append ("\n    ").append (M60_FSLW_TEXT_TM[(m60FSLW & M60_FSLW_TRANSFER_MODIFIER) >>> 16]);
    }
    return sb.toString ();
  }  //m60ErrorToString()



  //キャッシュアクセス時間
  //  キャッシュONのとき、全領域でキャッシュがヒットしたことにすると速くなりすぎる
  //  キャッシュの実体は設けないが、キャッシュミスペナルティの時間を加算する
  //  メインメモリ、ROM、ハイメモリのリードまたはライトに以下の処理を追加する
  //    (TMは通常のアクセス、MOVESのアクセス、MMUのテーブルサーチでFSLWに設定する)
  //    TMが1,2,5,6(キャッシュあり)
  //    TMが1,5(データ)
  //      CACRのEDCが1(データキャッシュ有効)
  //    TMが2,6(命令)
  //      CACRのEICが1(命令キャッシュ有効)
  //    (CMはアドレス変換時にTTR、PD、TCRから取得しATCに保存したものをアクセス時にコピーする)
  //    CMが0,1(キャッシュ許可)
  //      キャッシュミスペナルティを加算する
  //      ライト
  //        CMが0(ライトスルー)
  //          キャッシュがヒットしたかどうかに関係なくロング時間を加算する
  //    その他
  //      リード、ライトともにロング時間を加算する

  public static final boolean CAT_ON = true;

  //キャッシュの配列
  //  bit31-11  アドレス
  //      bit1  有効
  //      bit0  ダーティ(データのみ)
  private static final int[] catData = new int[4 * 128];  //データ
  private static final int[] catInst = new int[4 * 128];  //命令
  private static int catLine = 0;  //ラウンドロビンで使うライン

  //ウェイト時間
  //  mpuSetWaitが設定する
  public static long catMainLongTime = 0;  //メインメモリとROM、ロング
  public static long catMainLineTime = 0;  //メインメモリとROM、ライン
  public static long catHighLongTime = 0;  //ハイメモリ、ロング
  public static long catHighLineTime = 0;  //ハイメモリ、ライン

  //キャッシュモード
  public static int catCM;  //キャッシュモード

  //catReset ()
  //  リセット
  public static void catReset () {
    Arrays.fill (catData, 0);  //無効
    Arrays.fill (catInst, 0);  //無効
    catLine = 0;
  }  //catReset

  //catReadMainROM (a)
  //  リードメインメモリ、リードROM
  public static void catReadMainROM (int a) {
    if (!XEiJ.busWaitCycles) {  //ウェイトサイクルなし
      return;
    }
    int tm = m60FSLW & M60_FSLW_TRANSFER_MODIFIER;
    if (tm == M60_FSLW_TM_USER_DATA ||
        tm == M60_FSLW_TM_SUPER_DATA) {  //データ
      if (0 <= XEiJ.mpuCACR ||  //データキャッシュ禁止
          2 <= catCM) {  //プリサイズまたはインプリサイズ
        XEiJ.mpuClockTime += catMainLongTime;
        return;
      }
      int t = (a & -0x800) | 2;  //タグ、有効
      int i = (a & 0x7f0) >>> 2;  //4*(0~127)
      if ((catData[i    ] & -2) == t ||
          (catData[i + 1] & -2) == t ||
          (catData[i + 2] & -2) == t ||
          (catData[i + 3] & -2) == t) {  //ヒット
        return;
      }
      for (int l = 0; l < 4; l++) {
        if ((catData[i + l] & 2) == 0) {  //無効
          catData[i + l] = t;  //アロケート
          XEiJ.mpuClockTime += catMainLineTime;  //充填
          return;
        }
      }
      if ((catData[i + catLine] & 1) != 0) {  //ダーティ
        XEiJ.mpuClockTime += catMainLineTime;  //排出
      }
      catData[i + catLine] = t;  //アロケート
      XEiJ.mpuClockTime += catMainLineTime;  //充填
      catLine = (catLine + 1) & 3;  //ラウンドロビン
    } else if (tm == M60_FSLW_TM_USER_CODE ||
               tm == M60_FSLW_TM_SUPER_CODE) {  //命令
      if (0 <= (short) XEiJ.mpuCACR ||  //命令キャッシュ禁止
          2 <= catCM) {  //プリサイズまたはインプリサイズ
        XEiJ.mpuClockTime += catMainLongTime;
        return;
      }
      int t = (a & -0x800) | 2;  //タグ、有効
      int i = (a & 0x7f0) >>> 2;  //4*(0~127)
      if ((catInst[i    ] & -2) == t ||
          (catInst[i + 1] & -2) == t ||
          (catInst[i + 2] & -2) == t ||
          (catInst[i + 3] & -2) == t) {  //ヒット
        return;
      }
      for (int l = 0; l < 4; l++) {
        if ((catInst[i + l] & 2) == 0) {  //無効
          catInst[i + l] = t;  //アロケート
          XEiJ.mpuClockTime += catMainLineTime;  //充填
          return;
        }
      }
      catInst[i + catLine] = t;  //アロケート
      XEiJ.mpuClockTime += catMainLineTime;  //充填
      catLine = (catLine + 1) & 3;  //ラウンドロビン
    } else {  //データでも命令でもない
      XEiJ.mpuClockTime += catMainLongTime;
    }
  }  //catReadMainROM

  //catReadHigh (a)
  //  リードハイメモリ
  public static void catReadHigh (int a) {
    if (!XEiJ.busWaitCycles) {  //ウェイトサイクルなし
      return;
    }
    int tm = m60FSLW & M60_FSLW_TRANSFER_MODIFIER;
    if (tm == M60_FSLW_TM_USER_DATA ||
        tm == M60_FSLW_TM_SUPER_DATA) {  //データ
      if (0 <= XEiJ.mpuCACR ||  //データキャッシュ禁止
          2 <= catCM) {  //プリサイズまたはインプリサイズ
        XEiJ.mpuClockTime += catHighLongTime;
        return;
      }
      int t = (a & -0x800) | 2;  //タグ、有効
      int i = (a & 0x7f0) >>> 2;  //4*(0~127)
      if ((catData[i    ] & -2) == t ||
          (catData[i + 1] & -2) == t ||
          (catData[i + 2] & -2) == t ||
          (catData[i + 3] & -2) == t) {  //ヒット
        return;
      }
      for (int l = 0; l < 4; l++) {
        if ((catData[i + l] & 2) == 0) {  //無効
          catData[i + l] = t;  //アロケート
          XEiJ.mpuClockTime += catHighLineTime;  //充填
          return;
        }
      }
      if ((catData[i + catLine] & 1) != 0) {  //ダーティ
        XEiJ.mpuClockTime += catHighLineTime;  //排出
      }
      catData[i + catLine] = t;  //アロケート
      XEiJ.mpuClockTime += catHighLineTime;  //充填
      catLine = (catLine + 1) & 3;  //ラウンドロビン
    } else if (tm == M60_FSLW_TM_USER_CODE ||
               tm == M60_FSLW_TM_SUPER_CODE) {  //命令
      if (0 <= (short) XEiJ.mpuCACR ||  //命令キャッシュ禁止
          2 <= catCM) {  //プリサイズまたはインプリサイズ
        XEiJ.mpuClockTime += catHighLineTime;
        return;
      }
      int t = (a & -0x800) | 2;  //タグ、有効
      int i = (a & 0x7f0) >>> 2;  //4*(0~127)
      if ((catInst[i    ] & -2) == t ||
          (catInst[i + 1] & -2) == t ||
          (catInst[i + 2] & -2) == t ||
          (catInst[i + 3] & -2) == t) {  //ヒット
        return;
      }
      for (int l = 0; l < 4; l++) {
        if ((catInst[i + l] & 2) == 0) {  //無効
          catInst[i + l] = t;  //アロケート
          XEiJ.mpuClockTime += catHighLineTime;  //充填
          return;
        }
      }
      catInst[i + catLine] = t;  //アロケート
      XEiJ.mpuClockTime += catHighLineTime;  //充填
      catLine = (catLine + 1) & 3;  //ラウンドロビン
    } else {  //データでも命令でもない
      XEiJ.mpuClockTime += catHighLongTime;
    }
  }  //catReadHigh

  //catWriteMain (a)
  //  ライトメインメモリ
  public static void catWriteMain (int a) {
    if (!XEiJ.busWaitCycles) {  //ウェイトサイクルなし
      return;
    }
    int tm = m60FSLW & M60_FSLW_TRANSFER_MODIFIER;
    if (tm == M60_FSLW_TM_USER_DATA ||
        tm == M60_FSLW_TM_SUPER_DATA) {  //データ
      if (0 <= XEiJ.mpuCACR ||  //データキャッシュ禁止
          2 <= catCM) {  //プリサイズまたはインプリサイズ
        XEiJ.mpuClockTime += catMainLongTime;
        return;
      }
      if (catCM == 2) {  //ライトスルー
        XEiJ.mpuClockTime += catMainLongTime;
      }
      int t = (a & -0x800) | 2;  //タグ、有効
      int i = (a & 0x7f0) >>> 2;  //4*(0~127)
      for (int l = 0; l < 4; l++) {
        if ((catData[i + l] & -2) == t) {  //ヒット
          catData[i + l] |= 1;  //ダーティ
          return;
        }
      }
      for (int l = 0; l < 4; l++) {
        if ((catData[i + l] & 2) == 0) {  //無効
          catData[i + l] = t | 1;  //アロケート、ダーティ
          XEiJ.mpuClockTime += catMainLineTime;  //充填
          return;
        }
      }
      if ((catData[i + catLine] & 1) != 0) {  //ダーティ
        XEiJ.mpuClockTime += catMainLineTime;  //排出
      }
      catData[i + catLine] = t | 1;  //アロケート、ダーティ
      XEiJ.mpuClockTime += catMainLineTime;  //充填
      catLine = (catLine + 1) & 3;  //ラウンドロビン
    } else {  //データでない
      XEiJ.mpuClockTime += catMainLongTime;
    }
  }  //catWriteMain

  //catWriteHigh (a)
  //  ライトハイメモリ
  public static void catWriteHigh (int a) {
    if (!XEiJ.busWaitCycles) {  //ウェイトサイクルなし
      return;
    }
    int tm = m60FSLW & M60_FSLW_TRANSFER_MODIFIER;
    if (tm == M60_FSLW_TM_USER_DATA ||
        tm == M60_FSLW_TM_SUPER_DATA) {  //データ
      if (0 <= XEiJ.mpuCACR ||  //データキャッシュ禁止
          2 <= catCM) {  //プリサイズまたはインプリサイズ
        XEiJ.mpuClockTime += catHighLongTime;
        return;
      }
      if (catCM == 2) {  //ライトスルー
        XEiJ.mpuClockTime += catHighLongTime;
      }
      int t = (a & -0x800) | 2;  //タグ、有効
      int i = (a & 0x7f0) >>> 2;  //4*(0~127)
      for (int l = 0; l < 4; l++) {
        if ((catData[i + l] & -2) == t) {  //ヒット
          catData[i + l] |= 1;  //ダーティ
          return;
        }
      }
      for (int l = 0; l < 4; l++) {
        if ((catData[i + l] & 2) == 0) {  //無効
          catData[i + l] = t | 1;  //アロケート、ダーティ
          XEiJ.mpuClockTime += catHighLineTime;  //充填
          return;
        }
      }
      if ((catData[i + catLine] & 1) != 0) {  //ダーティ
        XEiJ.mpuClockTime += catHighLineTime;  //排出
      }
      catData[i + catLine] = t | 1;  //アロケート、ダーティ
      XEiJ.mpuClockTime += catHighLineTime;  //充填
      catLine = (catLine + 1) & 3;  //ラウンドロビン
    } else {  //データでない
      XEiJ.mpuClockTime += catHighLongTime;
    }
  }  //catWriteHigh

  private static boolean catMove16InProgress;  //MOVE16実行中
  private static int catSavedEDC;  //保存されたEDC
  private static long catSavedMainLongTime;  //保存されたメインメモリのロング時間
  private static long catSavedHighLongTime;  //保存されたハイメモリのロング時間

  //catMove16Start ()
  //  MOVE16開始
  //    EDCを保存
  //    EDCをクリア
  //    ロングの時間を保存
  //    ロングの時間をラインの時間の1/4に変更
  //  MOVE16はEDCに関係なく常にラインの時間がかかる
  private static void catMove16Start () {
    if (!XEiJ.busWaitCycles) {  //ウェイトサイクルなし
      return;
    }
    XEiJ.mpuCycleCount += 11;
    catMove16InProgress = true;
    //EDCを保存
    catSavedEDC = XEiJ.mpuCACR & 0x80000000;
    //EDCをクリア
    XEiJ.mpuCACR &= 0x7FFFFFFF;
    //ロングの時間を保存
    catSavedMainLongTime = catMainLongTime;
    catSavedHighLongTime = catHighLongTime;
    //ロングの時間をラインの時間の1/4に変更
    catMainLongTime = catMainLineTime >> 2;
    catHighLongTime = catHighLineTime >> 2;
  }  //catMove16Start

  //catMove16End ()
  //  MOVE16終了
  //    EDCを復元
  //    ロングの時間を復元
  private static void catMove16End () {
    if (!catMove16InProgress) {
      return;
    }
    catMove16InProgress = false;
    //EDCを復元
    XEiJ.mpuCACR |= catSavedEDC;
    //ロングの時間を復元
    catMainLongTime = catSavedMainLongTime;
    catHighLongTime = catSavedHighLongTime;
  }  //catMove16End

  //catInvL (id, a)
  //  ライン無効
  private static void catInvL (int id, int a) {
    int t = (a & -0x800) | 2;  //タグ、有効
    int i = (a & 0x7f0) >>> 2;  //4*(0~127)
    if ((id & 1) != 0) {  //データ
      for (int l = 0; l < 4; l++) {
        if ((catData[i + l] & -2) == t) {  //ヒット
          catData[i + l] = 0;  //無効
          break;
        }
      }
    }
    if ((id & 2) != 0) {  //命令
      for (int l = 0; l < 4; l++) {
        if ((catInst[i + l] & -2) == t) {  //ヒット
          catInst[i + l] = 0;  //無効
          break;
        }
      }
    }
    XEiJ.mpuClockTime += XEiJ.mpuCycleUnit * 18;  //<=18
  }  //catInvL

  //catInvP (id, a)
  //  ページ無効
  private static void catInvP (int id, int a) {
    int t = (a & -0x800) | 2;  //タグ、有効
    if ((id & 1) != 0) {  //データ
      for (int i = 0; i < 512; i++) {
        if ((catData[i] & -2) == t) {  //ヒット
          catData[i] = 0;  //無効
        }
      }
    }
    if ((id & 2) != 0) {  //命令
      for (int i = 0; i < 512; i++) {
        if ((catInst[i] & -2) == t) {  //ヒット
          catInst[i] = 0;  //無効
        }
      }
    }
    XEiJ.mpuClockTime += XEiJ.mpuCycleUnit * (18 + 256);  //<=274
  }  //catInvP

  //catInvA (id)
  //  全無効
  private static void catInvA (int id) {
    if ((id & 1) != 0) {  //データ
      Arrays.fill (catData, 0);  //無効
    }
    if ((id & 2) != 0) {  //命令
      Arrays.fill (catInst, 0);  //無効
    }
    XEiJ.mpuClockTime += XEiJ.mpuCycleUnit * 18;  //<=17
  }  //catInvA

  //catPushL (id, a)
  //  ラインプッシュ
  private static void catPushL (int id, int a) {
    int k = 0;
    int t = (a & -0x800) | 2;  //タグ、有効
    int i = (a & 0x7f0) >>> 2;  //4*(0~127)
    if ((id & 1) != 0) {  //データ
      for (int l = 0; l < 4; l++) {
        if ((catData[i + l] & -2) == t) {  //ヒット
          if ((catData[i + l] & 1) == 1) {  //ダーティ
            k++;  //ライトライン
          }
          catData[i + l] = 0;  //無効
          break;
        }
      }
    }
    if ((id & 2) != 0) {  //命令
      for (int l = 0; l < 4; l++) {
        if ((catInst[i + l] & -2) == t) {  //ヒット
          catInst[i + l] = 0;  //無効
          break;
        }
      }
    }
    long lineTime = (XEiJ.busExMemoryStart <= a && a < XEiJ.busExMemoryStart + XEiJ.busExMemorySize
                     ? catHighLineTime : catMainLineTime);
    XEiJ.mpuClockTime += XEiJ.mpuCycleUnit * 18 + lineTime * k;  //<=26
  }  //catPushL

  //catPushP (id, a)
  //  ページプッシュ
  private static void catPushP (int id, int a) {
    int k = 0;
    int t = (a & -0x800) | 2;  //タグ、有効
    if ((id & 1) != 0) {  //データ
      for (int i = 0; i < 512; i++) {
        if ((catData[i] & -2) == t) {  //ヒット
          if ((catData[i] & 1) == 1) {  //ダーティ
            k++;  //ライトライン
          }
          catData[i] = 0;  //無効
        }
      }
    }
    if ((id & 2) != 0) {  //命令
      for (int i = 0; i < 512; i++) {
        if ((catInst[i] & -2) == t) {  //ヒット
          catInst[i] = 0;  //無効
        }
      }
    }
    long lineTime = (XEiJ.busExMemoryStart <= a && a < XEiJ.busExMemoryStart + XEiJ.busExMemorySize
                     ? catHighLineTime : catMainLineTime);
    XEiJ.mpuClockTime += XEiJ.mpuCycleUnit * (18 + 256) + lineTime * k;  //<=2838
  }  //catPushP

  //catPushA (id)
  //  全プッシュ
  private static void catPushA (int id) {
    int km = 0, kh = 0;
    if ((id & 1) != 0) {  //データ
      for (int i = 0; i < 512; i++) {
        if ((catData[i] & 3) == 3) {  //有効、ダーティ
          int a = catData[i] & -4;
          if (XEiJ.busExMemoryStart <= a && a < XEiJ.busExMemoryStart + XEiJ.busExMemorySize) {
            kh++;
          } else {
            km++;
          }
        }
      }
      Arrays.fill (catData, 0);  //無効
    }
    if ((id & 2) != 0) {  //命令
      Arrays.fill (catInst, 0);  //無効
    }
    XEiJ.mpuClockTime += XEiJ.mpuCycleUnit * (18 + 256) + catMainLineTime * km + catHighLineTime * kh;  //<=5394
  }  //catPushA



}  //class MC68060


1 2 3