MemoryMappedDevice.java
     1: //========================================================================================
     2: //  MemoryMappedDevice.java
     3: //    en:Memory mapped device
     4: //    ja:メモリマップトデバイス
     5: //  Copyright (C) 2003-2026 Makoto Kamada
     6: //
     7: //  This file is part of the XEiJ (X68000 Emulator in Java).
     8: //  You can use, modify and redistribute the XEiJ if the conditions are met.
     9: //  Read the XEiJ License for more details.
    10: //  https://stdkmd.net/xeij/
    11: //========================================================================================
    12: 
    13: //----------------------------------------------------------------------------------------
    14: //  デバイスにアクセスするためのメソッドをenum bodyに記述する
    15: //    mmdPbs,mmdPbz,mmdPws,mmdPwz,mmdPls  ピーク
    16: //    mmdRbs,mmdRbz,mmdRws,mmdRwz,mmdRls  リード
    17: //    mmdWb,mmdWw,mmdWl                   ライト
    18: //  ピーク、リード、ライトの命名規則
    19: //    4文字目  P=ピーク,R=リード,W=ライト
    20: //    5文字目  b=バイト,w=ワード,l=ロング
    21: //    6文字目  s=符号拡張,z=ゼロ拡張
    22: //  ピークとリードの返却値の型はmmdPbsとmmdRbsだけbyte、他はint
    23: //  ピークはSRAMスイッチの読み取りやデバッガなどで使用する
    24: //  ピークはMPUやデバイスの状態を変化させず、例外もスローしない
    25: //  リードとライトはMPUやDMAによる通常のアクセスで使用する
    26: //  リードとライトはバスエラーをスローする場合がある
    27: //  アドレスの未使用ビットはデバイスに渡る前にすべてクリアされていなければならない
    28: //    バスエラーは未使用ビットがクリアされたアドレスで通知されることになる
    29: //  異なるデバイスに跨るアクセスはデバイスに渡る前に分割されていなければならない
    30: //  奇数アドレスに対するワードアクセスはデバイスに渡る前に分割または排除されていなければならない
    31: //  4の倍数でないアドレスに対するロングアクセスはデバイスに渡る前に分割または排除されていなければならない
    32: //  デバイスのメソッドを直接呼び出すときはアドレスのマスクや分割を忘れないこと
    33: //----------------------------------------------------------------------------------------
    34: 
    35: package xeij;
    36: 
    37: import java.lang.*;  //Boolean,Character,Class,Comparable,Double,Exception,Float,IllegalArgumentException,Integer,Long,Math,Number,Object,Runnable,SecurityException,String,StringBuilder,System
    38: import java.util.*;  //ArrayList,Arrays,Calendar,GregorianCalendar,HashMap,Map,Map.Entry,Timer,TimerTask,TreeMap
    39: 
    40: public enum MemoryMappedDevice {
    41: 
    42:   //--------------------------------------------------------------------------------
    43:   //MMD_MMR メインメモリ
    44:   MMD_MMR {
    45:     @Override public String toString () {
    46:       return Multilingual.mlnJapanese ? "メインメモリ" : "Main Memory";
    47:     }
    48:     //ピーク
    49:     @Override protected byte mmdPbs (int a) {
    50:       a &= XEiJ.BUS_MOTHER_MASK;
    51:       return MainMemory.mmrM8[a];
    52:     }
    53:     @Override protected int mmdPbz (int a) {
    54:       a &= XEiJ.BUS_MOTHER_MASK;
    55:       return MainMemory.mmrM8[a] & 0xff;
    56:     }
    57:     @Override protected int mmdPws (int a) {
    58:       a &= XEiJ.BUS_MOTHER_MASK;
    59:       if (MainMemory.MMR_USE_BYTE_BUFFER) {
    60:         return MainMemory.mmrBuffer.getShort (a);
    61:       } else {
    62:         return MainMemory.mmrM8[a] << 8 | (MainMemory.mmrM8[a + 1] & 0xff);
    63:       }
    64:     }
    65:     @Override protected int mmdPwz (int a) {
    66:       a &= XEiJ.BUS_MOTHER_MASK;
    67:       if (MainMemory.MMR_USE_BYTE_BUFFER) {
    68:         return MainMemory.mmrBuffer.getChar (a);
    69:       } else {
    70:         return (char) (MainMemory.mmrM8[a] << 8 | (MainMemory.mmrM8[a + 1] & 0xff));
    71:       }
    72:     }
    73:     @Override protected int mmdPls (int a) {
    74:       a &= XEiJ.BUS_MOTHER_MASK;
    75:       if (MainMemory.MMR_USE_BYTE_BUFFER) {
    76:         return MainMemory.mmrBuffer.getInt (a);
    77:       } else {
    78:         return MainMemory.mmrM8[a] << 24 | (MainMemory.mmrM8[a + 1] & 0xff) << 16 | (char) (MainMemory.mmrM8[a + 2] << 8 | (MainMemory.mmrM8[a + 3] & 0xff));
    79:       }
    80:     }
    81:     //リード
    82:     @Override protected byte mmdRbs (int a) throws M68kException {
    83:        XEiJ.mpuClockTime += XEiJ.busWaitTime.ram;
    84:        a &= XEiJ.BUS_MOTHER_MASK;
    85:        return MainMemory.mmrM8[a];
    86:      }
    87:     @Override protected int mmdRbz (int a) throws M68kException {
    88:        XEiJ.mpuClockTime += XEiJ.busWaitTime.ram;
    89:        a &= XEiJ.BUS_MOTHER_MASK;
    90:        return MainMemory.mmrM8[a] & 0xff;
    91:      }
    92:     @Override protected int mmdRws (int a) throws M68kException {
    93:        XEiJ.mpuClockTime += XEiJ.busWaitTime.ram;
    94:        a &= XEiJ.BUS_MOTHER_MASK;
    95:        if (MainMemory.MMR_USE_BYTE_BUFFER) {
    96:          return MainMemory.mmrBuffer.getShort (a);
    97:        } else {
    98:          return MainMemory.mmrM8[a] << 8 | (MainMemory.mmrM8[a + 1] & 0xff);
    99:        }
   100:      }
   101:     @Override protected int mmdRwz (int a) throws M68kException {
   102:        XEiJ.mpuClockTime += XEiJ.busWaitTime.ram;
   103:        a &= XEiJ.BUS_MOTHER_MASK;
   104:        if (MainMemory.MMR_USE_BYTE_BUFFER) {
   105:          return MainMemory.mmrBuffer.getChar (a);
   106:        } else {
   107:          return (char) (MainMemory.mmrM8[a] << 8 | (MainMemory.mmrM8[a + 1] & 0xff));
   108:        }
   109:      }
   110:     @Override protected int mmdRls (int a) throws M68kException {
   111:        XEiJ.mpuClockTime += XEiJ.busWaitTime.ramlong;
   112:        a &= XEiJ.BUS_MOTHER_MASK;
   113:        if (MainMemory.MMR_USE_BYTE_BUFFER) {
   114:          return MainMemory.mmrBuffer.getInt (a);
   115:        } else {
   116:          return MainMemory.mmrM8[a] << 24 | (MainMemory.mmrM8[a + 1] & 0xff) << 16 | (char) (MainMemory.mmrM8[a + 2] << 8 | (MainMemory.mmrM8[a + 3] & 0xff));
   117:        }
   118:      }
   119:     //ライト
   120:     @Override protected void mmdWb (int a, int d) throws M68kException {
   121:        XEiJ.mpuClockTime += XEiJ.busWaitTime.ram;
   122:        a &= XEiJ.BUS_MOTHER_MASK;
   123:        MainMemory.mmrM8[a    ] = (byte)  d;
   124:      }
   125:     @Override protected void mmdWw (int a, int d) throws M68kException {
   126:        XEiJ.mpuClockTime += XEiJ.busWaitTime.ram;
   127:        a &= XEiJ.BUS_MOTHER_MASK;
   128:        if (MainMemory.MMR_USE_BYTE_BUFFER) {
   129:          MainMemory.mmrBuffer.putShort (a, (short) d);
   130:        } else {
   131:          MainMemory.mmrM8[a    ] = (byte) (d >> 8);
   132:          MainMemory.mmrM8[a + 1] = (byte)  d;
   133:        }
   134:      }
   135:     @Override protected void mmdWl (int a, int d) throws M68kException {
   136:        XEiJ.mpuClockTime += XEiJ.busWaitTime.ramlong;
   137:        a &= XEiJ.BUS_MOTHER_MASK;
   138:        if (MainMemory.MMR_USE_BYTE_BUFFER) {
   139:          MainMemory.mmrBuffer.putInt (a, d);
   140:        } else {
   141:          MainMemory.mmrM8[a    ] = (byte) (d >> 24);
   142:          MainMemory.mmrM8[a + 1] = (byte) (d >> 16);
   143:          MainMemory.mmrM8[a + 2] = (byte) (d >> 8);
   144:          MainMemory.mmrM8[a + 3] = (byte)  d;
   145:        }
   146:      }
   147:   },  //MMD_MMR
   148: 
   149:   MMD_MM6 {
   150:     @Override public String toString () {
   151:       return Multilingual.mlnJapanese ? "メインメモリ (68060)" : "Main Memory (68060)";
   152:     }
   153:     //ピーク
   154:     @Override protected byte mmdPbs (int a) {
   155:       a &= XEiJ.BUS_MOTHER_MASK;
   156:       return MainMemory.mmrM8[a];
   157:     }
   158:     @Override protected int mmdPbz (int a) {
   159:       a &= XEiJ.BUS_MOTHER_MASK;
   160:       return MainMemory.mmrM8[a] & 0xff;
   161:     }
   162:     @Override protected int mmdPws (int a) {
   163:       a &= XEiJ.BUS_MOTHER_MASK;
   164:       if (MainMemory.MMR_USE_BYTE_BUFFER) {
   165:         return MainMemory.mmrBuffer.getShort (a);
   166:       } else {
   167:         return MainMemory.mmrM8[a] << 8 | (MainMemory.mmrM8[a + 1] & 0xff);
   168:       }
   169:     }
   170:     @Override protected int mmdPwz (int a) {
   171:       a &= XEiJ.BUS_MOTHER_MASK;
   172:       if (MainMemory.MMR_USE_BYTE_BUFFER) {
   173:         return MainMemory.mmrBuffer.getChar (a);
   174:       } else {
   175:         return (char) (MainMemory.mmrM8[a] << 8 | (MainMemory.mmrM8[a + 1] & 0xff));
   176:       }
   177:     }
   178:     @Override protected int mmdPls (int a) {
   179:       a &= XEiJ.BUS_MOTHER_MASK;
   180:       if (MainMemory.MMR_USE_BYTE_BUFFER) {
   181:         return MainMemory.mmrBuffer.getInt (a);
   182:       } else {
   183:         return MainMemory.mmrM8[a] << 24 | (MainMemory.mmrM8[a + 1] & 0xff) << 16 | (char) (MainMemory.mmrM8[a + 2] << 8 | (MainMemory.mmrM8[a + 3] & 0xff));
   184:       }
   185:     }
   186:     //リード
   187:     @Override protected byte mmdRbs (int a) throws M68kException {
   188:        if (MC68060.CAT_ON &&
   189:            !XEiJ.busWaitTime.isDma) {
   190:          MC68060.catReadMainROM (a);
   191:        } else {
   192:          XEiJ.mpuClockTime += XEiJ.busWaitTime.ram;
   193:        }
   194:        a &= XEiJ.BUS_MOTHER_MASK;
   195:        return MainMemory.mmrM8[a];
   196:      }
   197:     @Override protected int mmdRbz (int a) throws M68kException {
   198:        if (MC68060.CAT_ON &&
   199:            !XEiJ.busWaitTime.isDma) {
   200:          MC68060.catReadMainROM (a);
   201:        } else {
   202:          XEiJ.mpuClockTime += XEiJ.busWaitTime.ram;
   203:        }
   204:        a &= XEiJ.BUS_MOTHER_MASK;
   205:        return MainMemory.mmrM8[a] & 0xff;
   206:      }
   207:     @Override protected int mmdRws (int a) throws M68kException {
   208:        if (MC68060.CAT_ON &&
   209:            !XEiJ.busWaitTime.isDma) {
   210:          MC68060.catReadMainROM (a);
   211:        } else {
   212:          XEiJ.mpuClockTime += XEiJ.busWaitTime.ram;
   213:        }
   214:        a &= XEiJ.BUS_MOTHER_MASK;
   215:        if (MainMemory.MMR_USE_BYTE_BUFFER) {
   216:          return MainMemory.mmrBuffer.getShort (a);
   217:        } else {
   218:          return MainMemory.mmrM8[a] << 8 | (MainMemory.mmrM8[a + 1] & 0xff);
   219:        }
   220:      }
   221:     @Override protected int mmdRwz (int a) throws M68kException {
   222:        if (MC68060.CAT_ON &&
   223:            !XEiJ.busWaitTime.isDma) {
   224:          MC68060.catReadMainROM (a);
   225:        } else {
   226:          XEiJ.mpuClockTime += XEiJ.busWaitTime.ram;
   227:        }
   228:        a &= XEiJ.BUS_MOTHER_MASK;
   229:        if (MainMemory.MMR_USE_BYTE_BUFFER) {
   230:          return MainMemory.mmrBuffer.getChar (a);
   231:        } else {
   232:          return (char) (MainMemory.mmrM8[a] << 8 | (MainMemory.mmrM8[a + 1] & 0xff));
   233:        }
   234:      }
   235:     @Override protected int mmdRls (int a) throws M68kException {
   236:        if (MC68060.CAT_ON &&
   237:            !XEiJ.busWaitTime.isDma) {
   238:          MC68060.catReadMainROM (a);
   239:        } else {
   240:          XEiJ.mpuClockTime += XEiJ.busWaitTime.ramlong;
   241:        }
   242:        a &= XEiJ.BUS_MOTHER_MASK;
   243:        if (MainMemory.MMR_USE_BYTE_BUFFER) {
   244:          return MainMemory.mmrBuffer.getInt (a);
   245:        } else {
   246:          return MainMemory.mmrM8[a] << 24 | (MainMemory.mmrM8[a + 1] & 0xff) << 16 | (char) (MainMemory.mmrM8[a + 2] << 8 | (MainMemory.mmrM8[a + 3] & 0xff));
   247:        }
   248:      }
   249:     //ライト
   250:     @Override protected void mmdWb (int a, int d) throws M68kException {
   251:        if (MC68060.CAT_ON &&
   252:            !XEiJ.busWaitTime.isDma) {
   253:          MC68060.catWriteMain (a);
   254:        } else {
   255:          XEiJ.mpuClockTime += XEiJ.busWaitTime.ram;
   256:        }
   257:        a &= XEiJ.BUS_MOTHER_MASK;
   258:        MainMemory.mmrM8[a    ] = (byte)  d;
   259:      }
   260:     @Override protected void mmdWw (int a, int d) throws M68kException {
   261:        if (MC68060.CAT_ON &&
   262:            !XEiJ.busWaitTime.isDma) {
   263:          MC68060.catWriteMain (a);
   264:        } else {
   265:          XEiJ.mpuClockTime += XEiJ.busWaitTime.ram;
   266:        }
   267:        a &= XEiJ.BUS_MOTHER_MASK;
   268:        if (MainMemory.MMR_USE_BYTE_BUFFER) {
   269:          MainMemory.mmrBuffer.putShort (a, (short) d);
   270:        } else {
   271:          MainMemory.mmrM8[a    ] = (byte) (d >> 8);
   272:          MainMemory.mmrM8[a + 1] = (byte)  d;
   273:        }
   274:      }
   275:     @Override protected void mmdWl (int a, int d) throws M68kException {
   276:        if (MC68060.CAT_ON &&
   277:            !XEiJ.busWaitTime.isDma) {
   278:          MC68060.catWriteMain (a);
   279:        } else {
   280:          XEiJ.mpuClockTime += XEiJ.busWaitTime.ramlong;
   281:        }
   282:        a &= XEiJ.BUS_MOTHER_MASK;
   283:        if (MainMemory.MMR_USE_BYTE_BUFFER) {
   284:          MainMemory.mmrBuffer.putInt (a, d);
   285:        } else {
   286:          MainMemory.mmrM8[a    ] = (byte) (d >> 24);
   287:          MainMemory.mmrM8[a + 1] = (byte) (d >> 16);
   288:          MainMemory.mmrM8[a + 2] = (byte) (d >> 8);
   289:          MainMemory.mmrM8[a + 3] = (byte)  d;
   290:        }
   291:      }
   292:   },  //MMD_MM6
   293: 
   294:   //--------------------------------------------------------------------------------
   295:   //MMD_MM1 1MB搭載機の2MB目
   296:   //  $00100000~$001FFFFF
   297:   //  リードはShodaiは$6100、ACE/PRO/PROIIは$FFFFの繰り返し
   298:   //  ライトは無視
   299:   MMD_MM1 {
   300:     @Override public String toString () {
   301:       return Multilingual.mlnJapanese ? "1MB 搭載機の 2MB 目" : "2nd MB of machines with 1MB";
   302:     }
   303:     //リード
   304:     @Override protected byte mmdRbs (int a) throws M68kException {
   305:        XEiJ.mpuClockTime += XEiJ.busWaitTime.ram;
   306:       return (byte) ((a & 1) == 0 ? mmdRwz (a) >> 8 : mmdRwz (a));
   307:     }
   308:     @Override protected int mmdRbz (int a) throws M68kException {
   309:        XEiJ.mpuClockTime += XEiJ.busWaitTime.ram;
   310:       return (a & 1) == 0 ? mmdRwz (a) >> 8 : mmdRwz (a) & 0xff;
   311:     }
   312:     @Override protected int mmdRws (int a) throws M68kException {
   313:        XEiJ.mpuClockTime += XEiJ.busWaitTime.ram;
   314:       return (short) mmdRwz (a);
   315:     }
   316:     @Override protected int mmdRwz (int a) throws M68kException {
   317:        XEiJ.mpuClockTime += XEiJ.busWaitTime.ram;
   318:       return XEiJ.currentModel.isShodai () ? 0x6100 : 0xffff;
   319:     }
   320:     @Override protected int mmdRls (int a) throws M68kException {
   321:        XEiJ.mpuClockTime += XEiJ.busWaitTime.ramlong;
   322:       return mmdRwz (a) << 16 | mmdRwz (a + 2);
   323:     }
   324:     //ライト
   325:     @Override protected void mmdWb (int a, int d) throws M68kException {
   326:        XEiJ.mpuClockTime += XEiJ.busWaitTime.ram;
   327:      }
   328:     @Override protected void mmdWw (int a, int d) throws M68kException {
   329:        XEiJ.mpuClockTime += XEiJ.busWaitTime.ram;
   330:      }
   331:     @Override protected void mmdWl (int a, int d) throws M68kException {
   332:        XEiJ.mpuClockTime += XEiJ.busWaitTime.ramlong;
   333:      }
   334:   },
   335: 
   336:   //--------------------------------------------------------------------------------
   337:   //MMD_XMM 拡張メモリ
   338:   MMD_XMM {
   339:     @Override public String toString () {
   340:       return Multilingual.mlnJapanese ? "拡張メモリ" : "Expansion Memory";
   341:     }
   342:     //ピーク
   343:     @Override protected byte mmdPbs (int a) {
   344:       a -= XEiJ.busExMemoryStart;
   345:       return XEiJ.busExMemoryArray[a];
   346:     }
   347:     @Override protected int mmdPbz (int a) {
   348:       a -= XEiJ.busExMemoryStart;
   349:       return XEiJ.busExMemoryArray[a] & 0xff;
   350:     }
   351:     @Override protected int mmdPws (int a) {
   352:       a -= XEiJ.busExMemoryStart;
   353:       return XEiJ.busExMemoryArray[a] << 8 | (XEiJ.busExMemoryArray[a + 1] & 0xff);
   354:     }
   355:     @Override protected int mmdPwz (int a) {
   356:       a -= XEiJ.busExMemoryStart;
   357:       return (char) (XEiJ.busExMemoryArray[a] << 8 | (XEiJ.busExMemoryArray[a + 1] & 0xff));
   358:     }
   359:     @Override protected int mmdPls (int a) {
   360:       a -= XEiJ.busExMemoryStart;
   361:       return XEiJ.busExMemoryArray[a] << 24 | (XEiJ.busExMemoryArray[a + 1] & 0xff) << 16 | (char) (XEiJ.busExMemoryArray[a + 2] << 8 | (XEiJ.busExMemoryArray[a + 3] & 0xff));
   362:     }
   363:     //リード
   364:     @Override protected byte mmdRbs (int a) throws M68kException {
   365:        a -= XEiJ.busExMemoryStart;
   366:        return XEiJ.busExMemoryArray[a];
   367:      }
   368:     @Override protected int mmdRbz (int a) throws M68kException {
   369:        a -= XEiJ.busExMemoryStart;
   370:        return XEiJ.busExMemoryArray[a] & 0xff;
   371:      }
   372:     @Override protected int mmdRws (int a) throws M68kException {
   373:        a -= XEiJ.busExMemoryStart;
   374:        return XEiJ.busExMemoryArray[a] << 8 | (XEiJ.busExMemoryArray[a + 1] & 0xff);
   375:      }
   376:     @Override protected int mmdRwz (int a) throws M68kException {
   377:        a -= XEiJ.busExMemoryStart;
   378:        return (char) (XEiJ.busExMemoryArray[a] << 8 | (XEiJ.busExMemoryArray[a + 1] & 0xff));
   379:      }
   380:     @Override protected int mmdRls (int a) throws M68kException {
   381:        a -= XEiJ.busExMemoryStart;
   382:        return XEiJ.busExMemoryArray[a] << 24 | (XEiJ.busExMemoryArray[a + 1] & 0xff) << 16 | (char) (XEiJ.busExMemoryArray[a + 2] << 8 | (XEiJ.busExMemoryArray[a + 3] & 0xff));
   383:      }
   384:     //ライト
   385:     @Override protected void mmdWb (int a, int d) throws M68kException {
   386:        a -= XEiJ.busExMemoryStart;
   387:        XEiJ.busExMemoryArray[a    ] = (byte)  d;
   388:      }
   389:     @Override protected void mmdWw (int a, int d) throws M68kException {
   390:        a -= XEiJ.busExMemoryStart;
   391:        XEiJ.busExMemoryArray[a    ] = (byte) (d >> 8);
   392:        XEiJ.busExMemoryArray[a + 1] = (byte)  d;
   393:      }
   394:     @Override protected void mmdWl (int a, int d) throws M68kException {
   395:        a -= XEiJ.busExMemoryStart;
   396:        XEiJ.busExMemoryArray[a    ] = (byte) (d >> 24);
   397:        XEiJ.busExMemoryArray[a + 1] = (byte) (d >> 16);
   398:        XEiJ.busExMemoryArray[a + 2] = (byte) (d >> 8);
   399:        XEiJ.busExMemoryArray[a + 3] = (byte)  d;
   400:      }
   401:   },  //MMD_XMM
   402: 
   403:   MMD_XM6 {
   404:     @Override public String toString () {
   405:       return Multilingual.mlnJapanese ? "拡張メモリ (68060)" : "Expansion Memory (68060)";
   406:     }
   407:     //ピーク
   408:     @Override protected byte mmdPbs (int a) {
   409:       a -= XEiJ.busExMemoryStart;
   410:       return XEiJ.busExMemoryArray[a];
   411:     }
   412:     @Override protected int mmdPbz (int a) {
   413:       a -= XEiJ.busExMemoryStart;
   414:       return XEiJ.busExMemoryArray[a] & 0xff;
   415:     }
   416:     @Override protected int mmdPws (int a) {
   417:       a -= XEiJ.busExMemoryStart;
   418:       return XEiJ.busExMemoryArray[a] << 8 | (XEiJ.busExMemoryArray[a + 1] & 0xff);
   419:     }
   420:     @Override protected int mmdPwz (int a) {
   421:       a -= XEiJ.busExMemoryStart;
   422:       return (char) (XEiJ.busExMemoryArray[a] << 8 | (XEiJ.busExMemoryArray[a + 1] & 0xff));
   423:     }
   424:     @Override protected int mmdPls (int a) {
   425:       a -= XEiJ.busExMemoryStart;
   426:       return XEiJ.busExMemoryArray[a] << 24 | (XEiJ.busExMemoryArray[a + 1] & 0xff) << 16 | (char) (XEiJ.busExMemoryArray[a + 2] << 8 | (XEiJ.busExMemoryArray[a + 3] & 0xff));
   427:     }
   428:     //リード
   429:     @Override protected byte mmdRbs (int a) throws M68kException {
   430:        if (MC68060.CAT_ON) {
   431:          MC68060.catReadHigh (a);
   432:        }
   433:        a -= XEiJ.busExMemoryStart;
   434:        return XEiJ.busExMemoryArray[a];
   435:      }
   436:     @Override protected int mmdRbz (int a) throws M68kException {
   437:        if (MC68060.CAT_ON) {
   438:          MC68060.catReadHigh (a);
   439:        }
   440:        a -= XEiJ.busExMemoryStart;
   441:        return XEiJ.busExMemoryArray[a] & 0xff;
   442:      }
   443:     @Override protected int mmdRws (int a) throws M68kException {
   444:        if (MC68060.CAT_ON) {
   445:          MC68060.catReadHigh (a);
   446:        }
   447:        a -= XEiJ.busExMemoryStart;
   448:        return XEiJ.busExMemoryArray[a] << 8 | (XEiJ.busExMemoryArray[a + 1] & 0xff);
   449:      }
   450:     @Override protected int mmdRwz (int a) throws M68kException {
   451:        if (MC68060.CAT_ON) {
   452:          MC68060.catReadHigh (a);
   453:        }
   454:        a -= XEiJ.busExMemoryStart;
   455:        return (char) (XEiJ.busExMemoryArray[a] << 8 | (XEiJ.busExMemoryArray[a + 1] & 0xff));
   456:      }
   457:     @Override protected int mmdRls (int a) throws M68kException {
   458:        if (MC68060.CAT_ON) {
   459:          MC68060.catReadHigh (a);
   460:        }
   461:        a -= XEiJ.busExMemoryStart;
   462:        return XEiJ.busExMemoryArray[a] << 24 | (XEiJ.busExMemoryArray[a + 1] & 0xff) << 16 | (char) (XEiJ.busExMemoryArray[a + 2] << 8 | (XEiJ.busExMemoryArray[a + 3] & 0xff));
   463:      }
   464:     //ライト
   465:     @Override protected void mmdWb (int a, int d) throws M68kException {
   466:        if (MC68060.CAT_ON) {
   467:          MC68060.catWriteHigh (a);
   468:        }
   469:        a -= XEiJ.busExMemoryStart;
   470:        XEiJ.busExMemoryArray[a    ] = (byte)  d;
   471:      }
   472:     @Override protected void mmdWw (int a, int d) throws M68kException {
   473:        if (MC68060.CAT_ON) {
   474:          MC68060.catWriteHigh (a);
   475:        }
   476:        a -= XEiJ.busExMemoryStart;
   477:        XEiJ.busExMemoryArray[a    ] = (byte) (d >> 8);
   478:        XEiJ.busExMemoryArray[a + 1] = (byte)  d;
   479:      }
   480:     @Override protected void mmdWl (int a, int d) throws M68kException {
   481:        if (MC68060.CAT_ON) {
   482:          MC68060.catWriteHigh (a);
   483:        }
   484:        a -= XEiJ.busExMemoryStart;
   485:        XEiJ.busExMemoryArray[a    ] = (byte) (d >> 24);
   486:        XEiJ.busExMemoryArray[a + 1] = (byte) (d >> 16);
   487:        XEiJ.busExMemoryArray[a + 2] = (byte) (d >> 8);
   488:        XEiJ.busExMemoryArray[a + 3] = (byte)  d;
   489:      }
   490:   },  //MMD_XM6
   491: 
   492:   //--------------------------------------------------------------------------------
   493:   //MMD_GE0 グラフィックス画面(512ドット16色ページ0)
   494:   //
   495:   //  512ドット16色
   496:   //         ------------------参照------------------        --------------格納--------------
   497:   //    GE0  0x00c00000~0x00c7ffff  ............3210  ──  0x00000000~0x0003ffff  ....3210
   498:   //    参照  00000000 11000yyy yyyyyyxx xxxxxxx1
   499:   //    格納  00000000 000000yy yyyyyyyx xxxxxxxx  i=0x00000|((a>>1)&0x3ffff)
   500:   //
   501:   MMD_GE0 {
   502:     @Override public String toString () {
   503:       return Multilingual.mlnJapanese ? "グラフィックス画面 (512 ドット 16 色 ページ 0)" : "Graphics Screen (512 dots 16 colors page 0)";
   504:     }
   505:     //ピーク
   506:     @Override protected byte mmdPbs (int a) {
   507:       return ((a & 1) == 0 ? 0 :
   508:               GraphicScreen.graM4[(a >> 1) & 0x3ffff]);
   509:     }
   510:     @Override protected int mmdPbz (int a) {
   511:       return ((a & 1) == 0 ? 0 :
   512:               GraphicScreen.graM4[(a >> 1) & 0x3ffff]);
   513:     }
   514:     @Override protected int mmdPws (int a) {
   515:       return GraphicScreen.graM4[(a >> 1) & 0x3ffff];
   516:     }
   517:     @Override protected int mmdPwz (int a) {
   518:       return GraphicScreen.graM4[(a >> 1) & 0x3ffff];
   519:     }
   520:     @Override protected int mmdPls (int a) {
   521:       return (GraphicScreen.graM4[( a      >> 1) & 0x3ffff] << 16 |
   522:               GraphicScreen.graM4[((a + 2) >> 1) & 0x3ffff]);
   523:     }
   524:     //リード
   525:     @Override protected byte mmdRbs (int a) throws M68kException {
   526:        XEiJ.mpuClockTime += XEiJ.busWaitTime.gvram;
   527:        return ((a & 1) == 0 ? 0 :
   528:                GraphicScreen.graM4[(a >> 1) & 0x3ffff]);
   529:      }
   530:     @Override protected int mmdRbz (int a) throws M68kException {
   531:        XEiJ.mpuClockTime += XEiJ.busWaitTime.gvram;
   532:        return ((a & 1) == 0 ? 0 :
   533:                GraphicScreen.graM4[(a >> 1) & 0x3ffff]);
   534:      }
   535:     @Override protected int mmdRws (int a) throws M68kException {
   536:        XEiJ.mpuClockTime += XEiJ.busWaitTime.gvram;
   537:        return GraphicScreen.graM4[(a >> 1) & 0x3ffff];
   538:      }
   539:     @Override protected int mmdRwz (int a) throws M68kException {
   540:        XEiJ.mpuClockTime += XEiJ.busWaitTime.gvram;
   541:        return GraphicScreen.graM4[(a >> 1) & 0x3ffff];
   542:      }
   543:     @Override protected int mmdRls (int a) throws M68kException {
   544:        XEiJ.mpuClockTime += XEiJ.busWaitTime.gvram * 2;
   545:        return (GraphicScreen.graM4[( a      >> 1) & 0x3ffff] << 16 |
   546:                GraphicScreen.graM4[((a + 2) >> 1) & 0x3ffff]);
   547:      }
   548:     //ライト
   549:     @Override protected void mmdWb (int a, int d) throws M68kException {
   550:        XEiJ.mpuClockTime += XEiJ.busWaitTime.gvram;
   551:        if ((a & 1) != 0) {
   552:          GraphicScreen.graM4[(a >> 1) & 0x3ffff] = (byte) (d & 15);
   553:          int y = (a >> 10) - CRTC.crtR13GrYCurr[0] & 511;
   554:          CRTC.crtRasterStamp[y      ] = 0;
   555:          CRTC.crtRasterStamp[y + 512] = 0;
   556:        }
   557:      }
   558:     @Override protected void mmdWw (int a, int d) throws M68kException {
   559:        XEiJ.mpuClockTime += XEiJ.busWaitTime.gvram;
   560:        GraphicScreen.graM4[(a >> 1) & 0x3ffff] = (byte) (d & 15);
   561:        int y = (a >> 10) - CRTC.crtR13GrYCurr[0] & 511;
   562:        CRTC.crtRasterStamp[y      ] = 0;
   563:        CRTC.crtRasterStamp[y + 512] = 0;
   564:      }
   565:     @Override protected void mmdWl (int a, int d) throws M68kException {
   566:        XEiJ.mpuClockTime += XEiJ.busWaitTime.gvram * 2;
   567:        GraphicScreen.graM4[( a      >> 1) & 0x3ffff] = (byte) ((d >> 16) & 15);
   568:        GraphicScreen.graM4[((a + 2) >> 1) & 0x3ffff] = (byte) ( d        & 15);
   569:        int y = (a >> 10) - CRTC.crtR13GrYCurr[0] & 511;
   570:        CRTC.crtRasterStamp[y      ] = 0;
   571:        CRTC.crtRasterStamp[y + 512] = 0;
   572:        if ((a & 1022) == 1022) {
   573:          y = (y + 1) & 511;
   574:          CRTC.crtRasterStamp[y      ] = 0;
   575:          CRTC.crtRasterStamp[y + 512] = 0;
   576:        }
   577:      }
   578:   },  //MMD_GE0
   579: 
   580:   //--------------------------------------------------------------------------------
   581:   //MMD_GE1 グラフィックス画面(512ドット16色ページ1)
   582:   //
   583:   //  512ドット16色
   584:   //         ------------------参照------------------        --------------格納--------------
   585:   //    GE1  0x00c80000~0x00cfffff  ............7654  ──  0x00040000~0x0007ffff  ....7654
   586:   //    参照  00000000 11001yyy yyyyyyxx xxxxxxx1
   587:   //    格納  00000000 000001yy yyyyyyyx xxxxxxxx  i=0x40000|((a>>1)&0x3ffff)
   588:   //
   589:   MMD_GE1 {
   590:     @Override public String toString () {
   591:       return Multilingual.mlnJapanese ? "グラフィックス画面 (512 ドット 16 色 ページ 1)" : "Graphics Screen (512 dots 16 colors page 1)";
   592:     }
   593:     //ピーク
   594:     @Override protected byte mmdPbs (int a) {
   595:       return ((a & 1) == 0 ? 0 :
   596:               GraphicScreen.graM4[0x40000 + ((a >> 1) & 0x3ffff)]);
   597:     }
   598:     @Override protected int mmdPbz (int a) {
   599:       return ((a & 1) == 0 ? 0 :
   600:               GraphicScreen.graM4[0x40000 + ((a >> 1) & 0x3ffff)]);
   601:     }
   602:     @Override protected int mmdPws (int a) {
   603:       return GraphicScreen.graM4[0x40000 + ((a >> 1) & 0x3ffff)];
   604:     }
   605:     @Override protected int mmdPwz (int a) {
   606:       return GraphicScreen.graM4[0x40000 + ((a >> 1) & 0x3ffff)];
   607:     }
   608:     @Override protected int mmdPls (int a) {
   609:       return (GraphicScreen.graM4[0x40000 + (( a      >> 1) & 0x3ffff)] << 16 |
   610:               GraphicScreen.graM4[0x40000 + (((a + 2) >> 1) & 0x3ffff)]);
   611:     }
   612:     //リード
   613:     @Override protected byte mmdRbs (int a) throws M68kException {
   614:        XEiJ.mpuClockTime += XEiJ.busWaitTime.gvram;
   615:        return ((a & 1) == 0 ? 0 :
   616:                GraphicScreen.graM4[0x40000 + ((a >> 1) & 0x3ffff)]);
   617:      }
   618:     @Override protected int mmdRbz (int a) throws M68kException {
   619:        XEiJ.mpuClockTime += XEiJ.busWaitTime.gvram;
   620:        return ((a & 1) == 0 ? 0 :
   621:                GraphicScreen.graM4[0x40000 + ((a >> 1) & 0x3ffff)]);
   622:      }
   623:     @Override protected int mmdRws (int a) throws M68kException {
   624:        XEiJ.mpuClockTime += XEiJ.busWaitTime.gvram;
   625:        return GraphicScreen.graM4[0x40000 + ((a >> 1) & 0x3ffff)];
   626:      }
   627:     @Override protected int mmdRwz (int a) throws M68kException {
   628:        XEiJ.mpuClockTime += XEiJ.busWaitTime.gvram;
   629:        return GraphicScreen.graM4[0x40000 + ((a >> 1) & 0x3ffff)];
   630:      }
   631:     @Override protected int mmdRls (int a) throws M68kException {
   632:        XEiJ.mpuClockTime += XEiJ.busWaitTime.gvram * 2;
   633:        return (GraphicScreen.graM4[0x40000 + (( a      >> 1) & 0x3ffff)] << 16 |
   634:                GraphicScreen.graM4[0x40000 + (((a + 2) >> 1) & 0x3ffff)]);
   635:      }
   636:     //ライト
   637:     @Override protected void mmdWb (int a, int d) throws M68kException {
   638:        XEiJ.mpuClockTime += XEiJ.busWaitTime.gvram;
   639:        if ((a & 1) != 0) {
   640:          GraphicScreen.graM4[0x40000 + ((a >> 1) & 0x3ffff)] = (byte) (d & 15);
   641:          int y = (a >> 10) - CRTC.crtR13GrYCurr[1] & 511;
   642:          CRTC.crtRasterStamp[y      ] = 0;
   643:          CRTC.crtRasterStamp[y + 512] = 0;
   644:        }
   645:      }
   646:     @Override protected void mmdWw (int a, int d) throws M68kException {
   647:        XEiJ.mpuClockTime += XEiJ.busWaitTime.gvram;
   648:        GraphicScreen.graM4[0x40000 + ((a >> 1) & 0x3ffff)] = (byte) (d & 15);
   649:        int y = (a >> 10) - CRTC.crtR13GrYCurr[1] & 511;
   650:        CRTC.crtRasterStamp[y      ] = 0;
   651:        CRTC.crtRasterStamp[y + 512] = 0;
   652:      }
   653:     @Override protected void mmdWl (int a, int d) throws M68kException {
   654:        XEiJ.mpuClockTime += XEiJ.busWaitTime.gvram * 2;
   655:        GraphicScreen.graM4[0x40000 + (( a      >> 1) & 0x3ffff)] = (byte) ((d >> 16) & 15);
   656:        GraphicScreen.graM4[0x40000 + (((a + 2) >> 1) & 0x3ffff)] = (byte) ( d        & 15);
   657:        int y = (a >> 10) - CRTC.crtR13GrYCurr[1] & 511;
   658:        CRTC.crtRasterStamp[y      ] = 0;
   659:        CRTC.crtRasterStamp[y + 512] = 0;
   660:        if ((a & 1022) == 1022) {
   661:          y = (y + 1) & 511;
   662:          CRTC.crtRasterStamp[y      ] = 0;
   663:          CRTC.crtRasterStamp[y + 512] = 0;
   664:        }
   665:      }
   666:   },  //MMD_GE1
   667: 
   668:   //--------------------------------------------------------------------------------
   669:   //MMD_GE2 グラフィックス画面(512ドット16色ページ2)
   670:   //
   671:   //  512ドット16色
   672:   //         ------------------参照------------------        --------------格納--------------
   673:   //    GE2  0x00d00000~0x00d7ffff  ............ba98  ──  0x00080000~0x000bffff  ....ba98
   674:   //    参照  00000000 11010yyy yyyyyyxx xxxxxxx1
   675:   //    格納  00000000 000010yy yyyyyyyx xxxxxxxx  i=0x80000|((a>>1)&0x3ffff)
   676:   //
   677:   MMD_GE2 {
   678:     @Override public String toString () {
   679:       return Multilingual.mlnJapanese ? "グラフィックス画面 (512 ドット 16 色 ページ 2)" : "Graphics Screen (512 dots 16 colors page 2)";
   680:     }
   681:     //ピーク
   682:     @Override protected byte mmdPbs (int a) {
   683:       return ((a & 1) == 0 ? 0 :
   684:               GraphicScreen.graM4[0x80000 + ((a >> 1) & 0x3ffff)]);
   685:     }
   686:     @Override protected int mmdPbz (int a) {
   687:       return ((a & 1) == 0 ? 0 :
   688:               GraphicScreen.graM4[0x80000 + ((a >> 1) & 0x3ffff)]);
   689:     }
   690:     @Override protected int mmdPws (int a) {
   691:       return GraphicScreen.graM4[0x80000 + ((a >> 1) & 0x3ffff)];
   692:     }
   693:     @Override protected int mmdPwz (int a) {
   694:       return GraphicScreen.graM4[0x80000 + ((a >> 1) & 0x3ffff)];
   695:     }
   696:     @Override protected int mmdPls (int a) {
   697:       return (GraphicScreen.graM4[0x80000 + (( a      >> 1) & 0x3ffff)] << 16 |
   698:               GraphicScreen.graM4[0x80000 + (((a + 2) >> 1) & 0x3ffff)]);
   699:     }
   700:     //リード
   701:     @Override protected byte mmdRbs (int a) throws M68kException {
   702:        XEiJ.mpuClockTime += XEiJ.busWaitTime.gvram;
   703:        return ((a & 1) == 0 ? 0 :
   704:                GraphicScreen.graM4[0x80000 + ((a >> 1) & 0x3ffff)]);
   705:      }
   706:     @Override protected int mmdRbz (int a) throws M68kException {
   707:        XEiJ.mpuClockTime += XEiJ.busWaitTime.gvram;
   708:        return ((a & 1) == 0 ? 0 :
   709:                GraphicScreen.graM4[0x80000 + ((a >> 1) & 0x3ffff)]);
   710:      }
   711:     @Override protected int mmdRws (int a) throws M68kException {
   712:        XEiJ.mpuClockTime += XEiJ.busWaitTime.gvram;
   713:        return GraphicScreen.graM4[0x80000 + ((a >> 1) & 0x3ffff)];
   714:      }
   715:     @Override protected int mmdRwz (int a) throws M68kException {
   716:        XEiJ.mpuClockTime += XEiJ.busWaitTime.gvram;
   717:        return GraphicScreen.graM4[0x80000 + ((a >> 1) & 0x3ffff)];
   718:      }
   719:     @Override protected int mmdRls (int a) throws M68kException {
   720:        XEiJ.mpuClockTime += XEiJ.busWaitTime.gvram * 2;
   721:        return (GraphicScreen.graM4[0x80000 + (( a      >> 1) & 0x3ffff)] << 16 |
   722:                GraphicScreen.graM4[0x80000 + (((a + 2) >> 1) & 0x3ffff)]);
   723:      }
   724:     //ライト
   725:     @Override protected void mmdWb (int a, int d) throws M68kException {
   726:        XEiJ.mpuClockTime += XEiJ.busWaitTime.gvram;
   727:        if ((a & 1) != 0) {
   728:          GraphicScreen.graM4[0x80000 + ((a >> 1) & 0x3ffff)] = (byte) (d & 15);
   729:          int y = (a >> 10) - CRTC.crtR13GrYCurr[2] & 511;
   730:          CRTC.crtRasterStamp[y      ] = 0;
   731:          CRTC.crtRasterStamp[y + 512] = 0;
   732:        }
   733:      }
   734:     @Override protected void mmdWw (int a, int d) throws M68kException {
   735:        XEiJ.mpuClockTime += XEiJ.busWaitTime.gvram;
   736:        GraphicScreen.graM4[0x80000 + ((a >> 1) & 0x3ffff)] = (byte) (d & 15);
   737:        int y = (a >> 10) - CRTC.crtR13GrYCurr[2] & 511;
   738:        CRTC.crtRasterStamp[y      ] = 0;
   739:        CRTC.crtRasterStamp[y + 512] = 0;
   740:      }
   741:     @Override protected void mmdWl (int a, int d) throws M68kException {
   742:        XEiJ.mpuClockTime += XEiJ.busWaitTime.gvram * 2;
   743:        GraphicScreen.graM4[0x80000 + (( a      >> 1) & 0x3ffff)] = (byte) ((d >> 16) & 15);
   744:        GraphicScreen.graM4[0x80000 + (((a + 2) >> 1) & 0x3ffff)] = (byte) ( d        & 15);
   745:        int y = (a >> 10) - CRTC.crtR13GrYCurr[2] & 511;
   746:        CRTC.crtRasterStamp[y      ] = 0;
   747:        CRTC.crtRasterStamp[y + 512] = 0;
   748:        if ((a & 1022) == 1022) {
   749:          y = (y + 1) & 511;
   750:          CRTC.crtRasterStamp[y      ] = 0;
   751:          CRTC.crtRasterStamp[y + 512] = 0;
   752:        }
   753:      }
   754:   },  //MMD_GE2
   755: 
   756:   //--------------------------------------------------------------------------------
   757:   //MMD_GE3 グラフィックス画面(512ドット16色ページ3)
   758:   //
   759:   //  512ドット16色
   760:   //         ------------------参照------------------        --------------格納--------------
   761:   //    GE3  0x00d80000~0x00dfffff  ............fedc  ──  0x000c0000~0x000fffff  ....fedc
   762:   //    参照  00000000 11011yyy yyyyyyxx xxxxxxx1
   763:   //    格納  00000000 000011yy yyyyyyyx xxxxxxxx  i=0xc0000|((a>>1)&0x3ffff)
   764:   //
   765:   MMD_GE3 {
   766:     @Override public String toString () {
   767:       return Multilingual.mlnJapanese ? "グラフィックス画面 (512 ドット 16 色 ページ 3)" : "Graphics Screen (512 dots 16 colors page 3)";
   768:     }
   769:     //ピーク
   770:     @Override protected byte mmdPbs (int a) {
   771:       return ((a & 1) == 0 ? 0 :
   772:               GraphicScreen.graM4[0xc0000 + ((a >> 1) & 0x3ffff)]);
   773:     }
   774:     @Override protected int mmdPbz (int a) {
   775:       return ((a & 1) == 0 ? 0 :
   776:               GraphicScreen.graM4[0xc0000 + ((a >> 1) & 0x3ffff)]);
   777:     }
   778:     @Override protected int mmdPws (int a) {
   779:       return GraphicScreen.graM4[0xc0000 + ((a >> 1) & 0x3ffff)];
   780:     }
   781:     @Override protected int mmdPwz (int a) {
   782:       return GraphicScreen.graM4[0xc0000 + ((a >> 1) & 0x3ffff)];
   783:     }
   784:     @Override protected int mmdPls (int a) {
   785:       return (GraphicScreen.graM4[0xc0000 + (( a      >> 1) & 0x3ffff)] << 16 |
   786:               GraphicScreen.graM4[0xc0000 + (((a + 2) >> 1) & 0x3ffff)]);
   787:     }
   788:     //リード
   789:     @Override protected byte mmdRbs (int a) throws M68kException {
   790:        XEiJ.mpuClockTime += XEiJ.busWaitTime.gvram;
   791:        return ((a & 1) == 0 ? 0 :
   792:                GraphicScreen.graM4[0xc0000 + ((a >> 1) & 0x3ffff)]);
   793:      }
   794:     @Override protected int mmdRbz (int a) throws M68kException {
   795:        XEiJ.mpuClockTime += XEiJ.busWaitTime.gvram;
   796:        return ((a & 1) == 0 ? 0 :
   797:                GraphicScreen.graM4[0xc0000 + ((a >> 1) & 0x3ffff)]);
   798:      }
   799:     @Override protected int mmdRws (int a) throws M68kException {
   800:        XEiJ.mpuClockTime += XEiJ.busWaitTime.gvram;
   801:        return GraphicScreen.graM4[0xc0000 + ((a >> 1) & 0x3ffff)];
   802:      }
   803:     @Override protected int mmdRwz (int a) throws M68kException {
   804:        XEiJ.mpuClockTime += XEiJ.busWaitTime.gvram;
   805:        return GraphicScreen.graM4[0xc0000 + ((a >> 1) & 0x3ffff)];
   806:      }
   807:     @Override protected int mmdRls (int a) throws M68kException {
   808:        XEiJ.mpuClockTime += XEiJ.busWaitTime.gvram * 2;
   809:        return (GraphicScreen.graM4[0xc0000 + (( a      >> 1) & 0x3ffff)] << 16 |
   810:                GraphicScreen.graM4[0xc0000 + (((a + 2) >> 1) & 0x3ffff)]);
   811:      }
   812:     //ライト
   813:     @Override protected void mmdWb (int a, int d) throws M68kException {
   814:        XEiJ.mpuClockTime += XEiJ.busWaitTime.gvram;
   815:        if ((a & 1) != 0) {
   816:          GraphicScreen.graM4[0xc0000 + ((a >> 1) & 0x3ffff)] = (byte) (d & 15);
   817:          int y = (a >> 10) - CRTC.crtR13GrYCurr[3] & 511;
   818:          CRTC.crtRasterStamp[y      ] = 0;
   819:          CRTC.crtRasterStamp[y + 512] = 0;
   820:        }
   821:      }
   822:     @Override protected void mmdWw (int a, int d) throws M68kException {
   823:        XEiJ.mpuClockTime += XEiJ.busWaitTime.gvram;
   824:        GraphicScreen.graM4[0xc0000 + ((a >> 1) & 0x3ffff)] = (byte) (d & 15);
   825:        int y = (a >> 10) - CRTC.crtR13GrYCurr[3] & 511;
   826:        CRTC.crtRasterStamp[y      ] = 0;
   827:        CRTC.crtRasterStamp[y + 512] = 0;
   828:      }
   829:     @Override protected void mmdWl (int a, int d) throws M68kException {
   830:        XEiJ.mpuClockTime += XEiJ.busWaitTime.gvram * 2;
   831:        GraphicScreen.graM4[0xc0000 + (( a      >> 1) & 0x3ffff)] = (byte) ((d >> 16) & 15);
   832:        GraphicScreen.graM4[0xc0000 + (((a + 2) >> 1) & 0x3ffff)] = (byte) ( d        & 15);
   833:        int y = (a >> 10) - CRTC.crtR13GrYCurr[3] & 511;
   834:        CRTC.crtRasterStamp[y      ] = 0;
   835:        CRTC.crtRasterStamp[y + 512] = 0;
   836:        if ((a & 1022) == 1022) {
   837:          y = (y + 1) & 511;
   838:          CRTC.crtRasterStamp[y      ] = 0;
   839:          CRTC.crtRasterStamp[y + 512] = 0;
   840:        }
   841:      }
   842:   },  //MMD_GE3
   843: 
   844:   //--------------------------------------------------------------------------------
   845:   //MMD_GF0 グラフィックス画面(512ドット256色ページ0)
   846:   //
   847:   //  512ドット256色
   848:   //         ------------------参照------------------        --------------格納--------------
   849:   //    GF0  0x00c00000~0x00c7ffff  ........76543210  ─┬  0x00000000~0x0003ffff  ....3210
   850:   //                                                     └  0x00040000~0x0007ffff  ....7654
   851:   //    参照  00000000 11000yyy yyyyyyxx xxxxxxx1
   852:   //    格納  00000000 000000yy yyyyyyyx xxxxxxxx  i=0x00000|((a>>1)&0x3ffff)
   853:   //          00000000 000001yy yyyyyyyx xxxxxxxx  i=0x40000|((a>>1)&0x3ffff)
   854:   //
   855:   MMD_GF0 {
   856:     @Override public String toString () {
   857:       return Multilingual.mlnJapanese ? "グラフィックス画面 (512 ドット 256 色 ページ 0)" : "Graphics Screen (512 dots 256 colors page 0)";
   858:     }
   859:     //ピーク
   860:     @Override protected byte mmdPbs (int a) {
   861:       return (byte) ((a & 1) == 0 ? 0 :
   862:                      GraphicScreen.graM4[0x40000 + ((a >> 1) & 0x3ffff)] << 4 |
   863:                      GraphicScreen.graM4[          ((a >> 1) & 0x3ffff)]);
   864:     }
   865:     @Override protected int mmdPbz (int a) {
   866:       return ((a & 1) == 0 ? 0 :
   867:               GraphicScreen.graM4[0x40000 + ((a >> 1) & 0x3ffff)] << 4 |
   868:               GraphicScreen.graM4[          ((a >> 1) & 0x3ffff)]);
   869:     }
   870:     @Override protected int mmdPws (int a) {
   871:       int i = (a >> 1) & 0x3ffff;
   872:       return (GraphicScreen.graM4[0x40000 + i] << 4 |
   873:               GraphicScreen.graM4[          i]);
   874:     }
   875:     @Override protected int mmdPwz (int a) {
   876:       int i = (a >> 1) & 0x3ffff;
   877:       return (GraphicScreen.graM4[0x40000 + i] << 4 |
   878:               GraphicScreen.graM4[          i]);
   879:     }
   880:     @Override protected int mmdPls (int a) {
   881:       int i0 = ( a      >> 1) & 0x3ffff;
   882:       int i1 = ((a + 2) >> 1) & 0x3ffff;
   883:       return (GraphicScreen.graM4[0x40000 + i0] << 20 |
   884:               GraphicScreen.graM4[          i0] << 16 |
   885:               GraphicScreen.graM4[0x40000 + i1] <<  4 |
   886:               GraphicScreen.graM4[          i1]);
   887:     }
   888:     //リード
   889:     @Override protected byte mmdRbs (int a) throws M68kException {
   890:        XEiJ.mpuClockTime += XEiJ.busWaitTime.gvram;
   891:        return (byte) ((a & 1) == 0 ? 0 :
   892:                       GraphicScreen.graM4[0x40000 + ((a >> 1) & 0x3ffff)] << 4 |
   893:                       GraphicScreen.graM4[          ((a >> 1) & 0x3ffff)]);
   894:      }
   895:     @Override protected int mmdRbz (int a) throws M68kException {
   896:        XEiJ.mpuClockTime += XEiJ.busWaitTime.gvram;
   897:        return ((a & 1) == 0 ? 0 :
   898:                GraphicScreen.graM4[0x40000 + ((a >> 1) & 0x3ffff)] << 4 |
   899:                GraphicScreen.graM4[          ((a >> 1) & 0x3ffff)]);
   900:      }
   901:     @Override protected int mmdRws (int a) throws M68kException {
   902:        XEiJ.mpuClockTime += XEiJ.busWaitTime.gvram;
   903:        int i = (a >> 1) & 0x3ffff;
   904:        return (GraphicScreen.graM4[0x40000 + i] << 4 |
   905:                GraphicScreen.graM4[          i]);
   906:      }
   907:     @Override protected int mmdRwz (int a) throws M68kException {
   908:        XEiJ.mpuClockTime += XEiJ.busWaitTime.gvram;
   909:        int i = (a >> 1) & 0x3ffff;
   910:        return (GraphicScreen.graM4[0x40000 + i] << 4 |
   911:                GraphicScreen.graM4[          i]);
   912:      }
   913:     @Override protected int mmdRls (int a) throws M68kException {
   914:        XEiJ.mpuClockTime += XEiJ.busWaitTime.gvram * 2;
   915:        int i0 = ( a      >> 1) & 0x3ffff;
   916:        int i1 = ((a + 2) >> 1) & 0x3ffff;
   917:        return (GraphicScreen.graM4[0x40000 + i0] << 20 |
   918:                GraphicScreen.graM4[          i0] << 16 |
   919:                GraphicScreen.graM4[0x40000 + i1] << 4 |
   920:                GraphicScreen.graM4[          i1]);
   921:      }
   922:     //ライト
   923:     @Override protected void mmdWb (int a, int d) throws M68kException {
   924:        XEiJ.mpuClockTime += XEiJ.busWaitTime.gvram;
   925:        if ((a & 1) != 0) {
   926:          int i = (a >> 1) & 0x3ffff;
   927:          GraphicScreen.graM4[0x40000 + i] = (byte) ((d >> 4) & 15);
   928:          GraphicScreen.graM4[          i] = (byte) ( d       & 15);
   929:          a >>= 10;
   930:          int y = a - CRTC.crtR13GrYCurr[0] & 511;
   931:          CRTC.crtRasterStamp[y      ] = 0;
   932:          CRTC.crtRasterStamp[y + 512] = 0;
   933:          y = a - CRTC.crtR13GrYCurr[1] & 511;
   934:          CRTC.crtRasterStamp[y      ] = 0;
   935:          CRTC.crtRasterStamp[y + 512] = 0;
   936:        }
   937:      }
   938:     @Override protected void mmdWw (int a, int d) throws M68kException {
   939:        XEiJ.mpuClockTime += XEiJ.busWaitTime.gvram;
   940:        int i = (a >> 1) & 0x3ffff;
   941:        GraphicScreen.graM4[0x40000 + i] = (byte) ((d >> 4) & 15);
   942:        GraphicScreen.graM4[          i] = (byte) ( d       & 15);
   943:        a >>= 10;
   944:        int y = a - CRTC.crtR13GrYCurr[0] & 511;
   945:        CRTC.crtRasterStamp[y      ] = 0;
   946:        CRTC.crtRasterStamp[y + 512] = 0;
   947:        y = a - CRTC.crtR13GrYCurr[1] & 511;
   948:        CRTC.crtRasterStamp[y      ] = 0;
   949:        CRTC.crtRasterStamp[y + 512] = 0;
   950:      }
   951:     @Override protected void mmdWl (int a, int d) throws M68kException {
   952:        XEiJ.mpuClockTime += XEiJ.busWaitTime.gvram * 2;
   953:        int i0 = ( a      >> 1) & 0x3ffff;
   954:        int i1 = ((a + 2) >> 1) & 0x3ffff;
   955:        GraphicScreen.graM4[0x40000 + i0] = (byte) ((d >> 20) & 15);
   956:        GraphicScreen.graM4[          i0] = (byte) ((d >> 16) & 15);
   957:        GraphicScreen.graM4[0x40000 + i1] = (byte) ((d >>  4) & 15);
   958:        GraphicScreen.graM4[          i1] = (byte) ( d        & 15);
   959:        int b = (a + 2) >>> 10;
   960:        int y = b - CRTC.crtR13GrYCurr[0] & 511;
   961:        CRTC.crtRasterStamp[y      ] = 0;
   962:        CRTC.crtRasterStamp[y + 512] = 0;
   963:        y = b - CRTC.crtR13GrYCurr[1] & 511;
   964:        CRTC.crtRasterStamp[y      ] = 0;
   965:        CRTC.crtRasterStamp[y + 512] = 0;
   966:        a >>>= 10;
   967:        if (a != b) {
   968:          y = a - CRTC.crtR13GrYCurr[0] & 511;
   969:          CRTC.crtRasterStamp[y      ] = 0;
   970:          CRTC.crtRasterStamp[y + 512] = 0;
   971:          y = a - CRTC.crtR13GrYCurr[1] & 511;
   972:          CRTC.crtRasterStamp[y      ] = 0;
   973:          CRTC.crtRasterStamp[y + 512] = 0;
   974:        }
   975:      }
   976:   },  //MMD_GF0
   977: 
   978:   //--------------------------------------------------------------------------------
   979:   //MMD_GF1 グラフィックス画面(512ドット256色ページ1)
   980:   //
   981:   //  512ドット256色
   982:   //         ------------------参照------------------        --------------格納--------------
   983:   //    GF1  0x00c80000~0x00cfffff  ........fedcba98  ─┬  0x00080000~0x000bffff  ....ba98
   984:   //                                                     └  0x000c0000~0x000fffff  ....fedc
   985:   //    参照  00000000 11001yyy yyyyyyxx xxxxxxx1
   986:   //    格納  00000000 000010yy yyyyyyyx xxxxxxxx  i=0x80000|((a>>1)&0x3ffff)
   987:   //          00000000 000011yy yyyyyyyx xxxxxxxx  i=0xc0000|((a>>1)&0x3ffff)
   988:   //
   989:   MMD_GF1 {
   990:     @Override public String toString () {
   991:       return Multilingual.mlnJapanese ? "グラフィックス画面 (512 ドット 256 色 ページ 1)" : "Graphics Screen (512 dots 256 colors page 1)";
   992:     }
   993:     //ピーク
   994:     @Override protected byte mmdPbs (int a) {
   995:       return (byte) ((a & 1) == 0 ? 0 :
   996:                      GraphicScreen.graM4[0xc0000 + ((a >> 1) & 0x3ffff)] << 4 |
   997:                      GraphicScreen.graM4[0x80000 + ((a >> 1) & 0x3ffff)]);
   998:     }
   999:     @Override protected int mmdPbz (int a) {
  1000:       return ((a & 1) == 0 ? 0 :
  1001:               GraphicScreen.graM4[0xc0000 + ((a >> 1) & 0x3ffff)] << 4 |
  1002:               GraphicScreen.graM4[0x80000 + ((a >> 1) & 0x3ffff)]);
  1003:     }
  1004:     @Override protected int mmdPws (int a) {
  1005:       int i = (a >> 1) & 0x3ffff;
  1006:       return (GraphicScreen.graM4[0xc0000 + i] << 4 |
  1007:               GraphicScreen.graM4[0x80000 + i]);
  1008:     }
  1009:     @Override protected int mmdPwz (int a) {
  1010:       int i = (a >> 1) & 0x3ffff;
  1011:       return (GraphicScreen.graM4[0xc0000 + i] << 4 |
  1012:               GraphicScreen.graM4[0x80000 + i]);
  1013:     }
  1014:     @Override protected int mmdPls (int a) {
  1015:       int i0 = ( a      >> 1) & 0x3ffff;
  1016:       int i1 = ((a + 2) >> 1) & 0x3ffff;
  1017:       return (GraphicScreen.graM4[0xc0000 + i0] << 20 |
  1018:               GraphicScreen.graM4[0x80000 + i0] << 16 |
  1019:               GraphicScreen.graM4[0xc0000 + i1] <<  4 |
  1020:               GraphicScreen.graM4[0x80000 + i1]);
  1021:     }
  1022:     //リード
  1023:     @Override protected byte mmdRbs (int a) throws M68kException {
  1024:        XEiJ.mpuClockTime += XEiJ.busWaitTime.gvram;
  1025:        return (byte) ((a & 1) == 0 ? 0 :
  1026:                       GraphicScreen.graM4[0xc0000 + ((a >> 1) & 0x3ffff)] << 4 |
  1027:                       GraphicScreen.graM4[0x80000 + ((a >> 1) & 0x3ffff)]);
  1028:      }
  1029:     @Override protected int mmdRbz (int a) throws M68kException {
  1030:        XEiJ.mpuClockTime += XEiJ.busWaitTime.gvram;
  1031:        return ((a & 1) == 0 ? 0 :
  1032:                GraphicScreen.graM4[0xc0000 + ((a >> 1) & 0x3ffff)] << 4 |
  1033:                GraphicScreen.graM4[0x80000 + ((a >> 1) & 0x3ffff)]);
  1034:      }
  1035:     @Override protected int mmdRws (int a) throws M68kException {
  1036:        XEiJ.mpuClockTime += XEiJ.busWaitTime.gvram;
  1037:        int i = (a >> 1) & 0x3ffff;
  1038:        return (GraphicScreen.graM4[0xc0000 + i] << 4 |
  1039:                GraphicScreen.graM4[0x80000 + i]);
  1040:      }
  1041:     @Override protected int mmdRwz (int a) throws M68kException {
  1042:        XEiJ.mpuClockTime += XEiJ.busWaitTime.gvram;
  1043:        int i = (a >> 1) & 0x3ffff;
  1044:        return (GraphicScreen.graM4[0xc0000 + i] << 4 |
  1045:                GraphicScreen.graM4[0x80000 + i]);
  1046:      }
  1047:     @Override protected int mmdRls (int a) throws M68kException {
  1048:        XEiJ.mpuClockTime += XEiJ.busWaitTime.gvram * 2;
  1049:        int i0 = ( a      >> 1) & 0x3ffff;
  1050:        int i1 = ((a + 2) >> 1) & 0x3ffff;
  1051:        return (GraphicScreen.graM4[0xc0000 + i0] << 20 |
  1052:                GraphicScreen.graM4[0x80000 + i0] << 16 |
  1053:                GraphicScreen.graM4[0xc0000 + i1] << 4 |
  1054:                GraphicScreen.graM4[0x80000 + i1]);
  1055:      }
  1056:     //ライト
  1057:     @Override protected void mmdWb (int a, int d) throws M68kException {
  1058:        XEiJ.mpuClockTime += XEiJ.busWaitTime.gvram;
  1059:        if ((a & 1) != 0) {
  1060:          int i = (a >> 1) & 0x3ffff;
  1061:          GraphicScreen.graM4[0xc0000 + i] = (byte) ((d >> 4) & 15);
  1062:          GraphicScreen.graM4[0x80000 + i] = (byte) ( d       & 15);
  1063:          a >>= 10;
  1064:          int y = a - CRTC.crtR13GrYCurr[2] & 511;
  1065:          CRTC.crtRasterStamp[y      ] = 0;
  1066:          CRTC.crtRasterStamp[y + 512] = 0;
  1067:          y = a - CRTC.crtR13GrYCurr[3] & 511;
  1068:          CRTC.crtRasterStamp[y      ] = 0;
  1069:          CRTC.crtRasterStamp[y + 512] = 0;
  1070:        }
  1071:      }
  1072:     @Override protected void mmdWw (int a, int d) throws M68kException {
  1073:        XEiJ.mpuClockTime += XEiJ.busWaitTime.gvram;
  1074:        int i = (a >> 1) & 0x3ffff;
  1075:        GraphicScreen.graM4[0xc0000 + i] = (byte) ((d >> 4) & 15);
  1076:        GraphicScreen.graM4[0x80000 + i] = (byte) ( d       & 15);
  1077:        a >>= 10;
  1078:        int y = a - CRTC.crtR13GrYCurr[2] & 511;
  1079:        CRTC.crtRasterStamp[y      ] = 0;
  1080:        CRTC.crtRasterStamp[y + 512] = 0;
  1081:        y = a - CRTC.crtR13GrYCurr[3] & 511;
  1082:        CRTC.crtRasterStamp[y      ] = 0;
  1083:        CRTC.crtRasterStamp[y + 512] = 0;
  1084:      }
  1085:     @Override protected void mmdWl (int a, int d) throws M68kException {
  1086:        XEiJ.mpuClockTime += XEiJ.busWaitTime.gvram * 2;
  1087:        int i0 = ( a      >> 1) & 0x3ffff;
  1088:        int i1 = ((a + 2) >> 1) & 0x3ffff;
  1089:        GraphicScreen.graM4[0xc0000 + i0] = (byte) ((d >> 20) & 15);
  1090:        GraphicScreen.graM4[0x80000 + i0] = (byte) ((d >> 16) & 15);
  1091:        GraphicScreen.graM4[0xc0000 + i1] = (byte) ((d >>  4) & 15);
  1092:        GraphicScreen.graM4[0x80000 + i1] = (byte) ( d        & 15);
  1093:        int b = (a + 2) >>> 10;
  1094:        int y = b - CRTC.crtR13GrYCurr[2] & 511;
  1095:        CRTC.crtRasterStamp[y      ] = 0;
  1096:        CRTC.crtRasterStamp[y + 512] = 0;
  1097:        y = b - CRTC.crtR13GrYCurr[3] & 511;
  1098:        CRTC.crtRasterStamp[y      ] = 0;
  1099:        CRTC.crtRasterStamp[y + 512] = 0;
  1100:        a >>>= 10;
  1101:        if (a != b) {
  1102:          y = a - CRTC.crtR13GrYCurr[2] & 511;
  1103:          CRTC.crtRasterStamp[y      ] = 0;
  1104:          CRTC.crtRasterStamp[y + 512] = 0;
  1105:          y = a - CRTC.crtR13GrYCurr[3] & 511;
  1106:          CRTC.crtRasterStamp[y      ] = 0;
  1107:          CRTC.crtRasterStamp[y + 512] = 0;
  1108:        }
  1109:      }
  1110:   },  //MMD_GF1
  1111: 
  1112:   //--------------------------------------------------------------------------------
  1113:   //MMD_GM2 グラフィックス画面(メモリモード2)
  1114:   //
  1115:   //  バイトリード
  1116:   //    0x00c00000  0x00が読み出される
  1117:   //    0x00c00001  4bitページ1-0が読み出される
  1118:   //    0x00c80000  0x00が読み出される
  1119:   //    0x00c80001  0x00が読み出される
  1120:   //    0x00d00000  0x00が読み出される
  1121:   //    0x00d00001  4bitページ1-0が読み出される
  1122:   //    0x00d80000  0x00が読み出される
  1123:   //    0x00d80001  0x00が読み出される
  1124:   //
  1125:   //  ワードリード
  1126:   //    0x00c00000  上位バイトは0x00で下位バイトに4bitページ1-0が読み出される
  1127:   //    0x00c80000  上位バイトは0x00で下位バイトに4bitページ3-2が読み出される
  1128:   //    0x00d00000  上位バイトは0x00で下位バイトに4bitページ1-0が読み出される
  1129:   //    0x00d80000  上位バイトは0x00で下位バイトに4bitページ3-2が読み出される
  1130:   //
  1131:   //  バイトライト
  1132:   //    0x00c00000  060turboの060モードのときデータは無視され0x00が4bitページ3-2に書き込まれる。それ以外はデータが4bitページ3-2に書き込まれる
  1133:   //    0x00c00001  データが4bitページ1-0に書き込まれる
  1134:   //    0x00c80000  060turboの060モードのときデータは無視され0x00が4bitページ3-2に書き込まれる。それ以外はデータが4bitページ3-2に書き込まれる
  1135:   //    0x00c80001  データが4bitページ1-0に書き込まれる
  1136:   //    0x00d00000  060turboの060モードのときデータは無視され0x00が4bitページ3-2に書き込まれる。それ以外はデータが4bitページ3-2に書き込まれる
  1137:   //    0x00d00001  データが4bitページ1-0に書き込まれる
  1138:   //    0x00d80000  060turboの060モードのときデータは無視され0x00が4bitページ3-2に書き込まれる。それ以外はデータが4bitページ3-2に書き込まれる
  1139:   //    0x00d80001  データが4bitページ1-0に書き込まれる
  1140:   //
  1141:   //  ワードライト
  1142:   //    0x00c00000  上位バイトは無視され下位バイトが4bitページ3-2と4bitページ1-0の両方に書き込まれる
  1143:   //    0x00c80000  上位バイトは無視され下位バイトが4bitページ3-2と4bitページ1-0の両方に書き込まれる
  1144:   //    0x00d00000  上位バイトは無視され下位バイトが4bitページ3-2と4bitページ1-0の両方に書き込まれる
  1145:   //    0x00d80000  上位バイトは無視され下位バイトが4bitページ3-2と4bitページ1-0の両方に書き込まれる
  1146:   //
  1147:   MMD_GM2 {
  1148:     @Override public String toString () {
  1149:       return Multilingual.mlnJapanese ? "グラフィックス画面 (メモリモード 2)" : "Graphics Screen (memory mode 2)";
  1150:     }
  1151:     //ピーク
  1152:     @Override protected byte mmdPbs (int a) {
  1153:       if ((a & 0x00080001) == 0x00000001) {  //0x00c00000..0x00c7ffff,0x00d00000..0x00d7ffffかつ下位バイト
  1154:         int i = (a >> 1) & 0x3ffff;
  1155:         return (byte) (GraphicScreen.graM4[0x40000 + i] << 4 |  //4bitページ1
  1156:                        GraphicScreen.graM4[          i]);  //4bitページ0
  1157:       } else {  //0x00c80000..0x00cfffff,0x00d80000..0x00dfffffまたは上位バイト
  1158:         return 0x00;
  1159:       }
  1160:     }
  1161:     @Override protected int mmdPbz (int a) {
  1162:       if ((a & 0x00080001) == 0x00000001) {  //0x00c00000..0x00c7ffff,0x00d00000..0x00d7ffffかつ下位バイト
  1163:         int i = (a >> 1) & 0x3ffff;
  1164:         return (GraphicScreen.graM4[0x40000 + i] << 4 |  //4bitページ1
  1165:                 GraphicScreen.graM4[          i]);  //4bitページ0
  1166:       } else {  //0x00c80000..0x00cfffff,0x00d80000..0x00dfffffまたは上位バイト
  1167:         return 0x00;
  1168:       }
  1169:     }
  1170:     @Override protected int mmdPws (int a) {
  1171:       int i = (a >> 1) & 0x3ffff;
  1172:       if ((a & 0x00080000) == 0x00000000) {  //0x00c00000..0x00c7ffff,0x00d00000..0x00d7ffff
  1173:         return (GraphicScreen.graM4[0x40000 + i] << 4 |  //4bitページ1
  1174:                 GraphicScreen.graM4[          i]);  //4bitページ0
  1175:       } else {  //0x00c80000..0x00cfffff,0x00d80000..0x00dfffff
  1176:         return (GraphicScreen.graM4[0xc0000 + i] << 4 |  //4bitページ3
  1177:                 GraphicScreen.graM4[0x80000 + i]);  //4bitページ2
  1178:       }
  1179:     }
  1180:     @Override protected int mmdPwz (int a) {
  1181:       int i = (a >> 1) & 0x3ffff;
  1182:       if ((a & 0x00080000) == 0x00000000) {  //0x00c00000..0x00c7ffff,0x00d00000..0x00d7ffff
  1183:         return (GraphicScreen.graM4[0x40000 + i] << 4 |  //4bitページ1
  1184:                 GraphicScreen.graM4[          i]);  //4bitページ0
  1185:       } else {  //0x00c80000..0x00cfffff,0x00d80000..0x00dfffff
  1186:         return (GraphicScreen.graM4[0xc0000 + i] << 4 |  //4bitページ3
  1187:                 GraphicScreen.graM4[0x80000 + i]);  //4bitページ2
  1188:       }
  1189:     }
  1190:     @Override protected int mmdPls (int a) {
  1191:       return mmdPws (a) << 16 | mmdPwz (a + 2);
  1192:     }
  1193:     //リード
  1194:     @Override protected byte mmdRbs (int a) throws M68kException {
  1195:        XEiJ.mpuClockTime += XEiJ.busWaitTime.gvram;
  1196:        if ((a & 0x00080001) == 0x00000001) {  //0x00c00000..0x00c7ffff,0x00d00000..0x00d7ffffかつ下位バイト
  1197:          int i = (a >> 1) & 0x3ffff;
  1198:          return (byte) (GraphicScreen.graM4[0x40000 + i] << 4 |  //4bitページ1
  1199:                         GraphicScreen.graM4[          i]);  //4bitページ0
  1200:        } else {  //0x00c80000..0x00cfffff,0x00d80000..0x00dfffffまたは上位バイト
  1201:          return 0x00;
  1202:        }
  1203:      }
  1204:     @Override protected int mmdRbz (int a) throws M68kException {
  1205:        XEiJ.mpuClockTime += XEiJ.busWaitTime.gvram;
  1206:        if ((a & 0x00080001) == 0x00000001) {  //0x00c00000..0x00c7ffff,0x00d00000..0x00d7ffffかつ下位バイト
  1207:          int i = (a >> 1) & 0x3ffff;
  1208:          return (GraphicScreen.graM4[0x40000 + i] << 4 |  //4bitページ1
  1209:                  GraphicScreen.graM4[          i]);  //4bitページ0
  1210:        } else {  //0x00c80000..0x00cfffff,0x00d80000..0x00dfffffまたは上位バイト
  1211:          return 0x00;
  1212:        }
  1213:      }
  1214:     @Override protected int mmdRws (int a) throws M68kException {
  1215:        XEiJ.mpuClockTime += XEiJ.busWaitTime.gvram;
  1216:        int i = (a >> 1) & 0x3ffff;
  1217:        if ((a & 0x00080000) == 0x00000000) {  //0x00c00000..0x00c7ffff,0x00d00000..0x00d7ffff
  1218:          return (GraphicScreen.graM4[0x40000 + i] << 4 |  //4bitページ1
  1219:                  GraphicScreen.graM4[          i]);  //4bitページ0
  1220:        } else {  //0x00c80000..0x00cfffff,0x00d80000..0x00dfffff
  1221:          return (GraphicScreen.graM4[0xc0000 + i] << 4 |  //4bitページ3
  1222:                  GraphicScreen.graM4[0x80000 + i]);  //4bitページ2
  1223:        }
  1224:      }
  1225:     @Override protected int mmdRwz (int a) throws M68kException {
  1226:        XEiJ.mpuClockTime += XEiJ.busWaitTime.gvram;
  1227:        int i = (a >> 1) & 0x3ffff;
  1228:        if ((a & 0x00080000) == 0x00000000) {  //0x00c00000..0x00c7ffff,0x00d00000..0x00d7ffff
  1229:          return (GraphicScreen.graM4[0x40000 + i] << 4 |  //4bitページ1
  1230:                  GraphicScreen.graM4[          i]);  //4bitページ0
  1231:        } else {  //0x00c80000..0x00cfffff,0x00d80000..0x00dfffff
  1232:          return (GraphicScreen.graM4[0xc0000 + i] << 4 |  //4bitページ3
  1233:                  GraphicScreen.graM4[0x80000 + i]);  //4bitページ2
  1234:        }
  1235:      }
  1236:     @Override protected int mmdRls (int a) throws M68kException {
  1237:        return mmdRws (a) << 16 | mmdRwz (a + 2);
  1238:      }
  1239:     //ライト
  1240:     @Override protected void mmdWb (int a, int d) throws M68kException {
  1241:        XEiJ.mpuClockTime += XEiJ.busWaitTime.gvram;
  1242:        int i = (a >> 1) & 0x3ffff;
  1243:        if ((a & 0x00000001) == 0x00000000) {  //上位バイト
  1244:          if (XEiJ.currentMPU < Model.MPU_MC68LC040) {
  1245:            GraphicScreen.graM4[0xc0000 + i] = (byte) ((d >> 4) & 15);  //4bitページ3
  1246:            GraphicScreen.graM4[0x80000 + i] = (byte) ( d       & 15);  //4bitページ2
  1247:          } else {
  1248:            GraphicScreen.graM4[0xc0000 + i] = 0;  //4bitページ3
  1249:            GraphicScreen.graM4[0x80000 + i] = 0;  //4bitページ2
  1250:          }
  1251:          a >>>= 10;
  1252:          int y = a - CRTC.crtR13GrYCurr[3] & 511;
  1253:          CRTC.crtRasterStamp[y      ] = 0;
  1254:          CRTC.crtRasterStamp[y + 512] = 0;
  1255:          y = a - CRTC.crtR13GrYCurr[2] & 511;
  1256:          CRTC.crtRasterStamp[y      ] = 0;
  1257:          CRTC.crtRasterStamp[y + 512] = 0;
  1258:        } else {  //下位バイト
  1259:          GraphicScreen.graM4[0x40000 + i] = (byte) ((d >> 4) & 15);  //4bitページ1
  1260:          GraphicScreen.graM4[          i] = (byte) ( d       & 15);  //4bitページ0
  1261:          a >>>= 10;
  1262:          int y = a - CRTC.crtR13GrYCurr[1] & 511;
  1263:          CRTC.crtRasterStamp[y      ] = 0;
  1264:          CRTC.crtRasterStamp[y + 512] = 0;
  1265:          y = a - CRTC.crtR13GrYCurr[0] & 511;
  1266:          CRTC.crtRasterStamp[y      ] = 0;
  1267:          CRTC.crtRasterStamp[y + 512] = 0;
  1268:        }
  1269:      }
  1270:     @Override protected void mmdWw (int a, int d) throws M68kException {
  1271:        XEiJ.mpuClockTime += XEiJ.busWaitTime.gvram;
  1272:        int i = (a >> 1) & 0x3ffff;
  1273:        GraphicScreen.graM4[0xc0000 + i] = (byte) ((d >>  4) & 15);  //4bitページ3
  1274:        GraphicScreen.graM4[0x80000 + i] = (byte) ( d        & 15);  //4bitページ2
  1275:        GraphicScreen.graM4[0x40000 + i] = (byte) ((d >>  4) & 15);  //4bitページ1
  1276:        GraphicScreen.graM4[          i] = (byte) ( d        & 15);  //4bitページ0
  1277:        a >>>= 10;
  1278:        int y = a - CRTC.crtR13GrYCurr[3] & 511;
  1279:        CRTC.crtRasterStamp[y      ] = 0;
  1280:        CRTC.crtRasterStamp[y + 512] = 0;
  1281:        y = a - CRTC.crtR13GrYCurr[2] & 511;
  1282:        CRTC.crtRasterStamp[y      ] = 0;
  1283:        CRTC.crtRasterStamp[y + 512] = 0;
  1284:        y = a - CRTC.crtR13GrYCurr[1] & 511;
  1285:        CRTC.crtRasterStamp[y      ] = 0;
  1286:        CRTC.crtRasterStamp[y + 512] = 0;
  1287:        y = a - CRTC.crtR13GrYCurr[0] & 511;
  1288:        CRTC.crtRasterStamp[y      ] = 0;
  1289:        CRTC.crtRasterStamp[y + 512] = 0;
  1290:      }
  1291:     @Override protected void mmdWl (int a, int d) throws M68kException {
  1292:        mmdWw (a, d >> 16);
  1293:        mmdWw (a + 2, d);
  1294:      }
  1295:   },  //MMD_GM2
  1296: 
  1297:   //--------------------------------------------------------------------------------
  1298:   //MMD_GG0 グラフィックス画面(512ドット65536色)
  1299:   //
  1300:   //  512ドット65536色
  1301:   //         ------------------参照------------------        --------------格納--------------
  1302:   //    GG0  0x00c00000~0x00c7ffff  fedcba9876543210  ─┬  0x00000000~0x0003ffff  ....3210
  1303:   //                                                     ├  0x00040000~0x0007ffff  ....7654
  1304:   //                                                     ├  0x00080000~0x000bffff  ....ba98
  1305:   //                                                     └  0x000c0000~0x000fffff  ....fedc
  1306:   //    参照  00000000 11000yyy yyyyyyxx xxxxxxx1
  1307:   //    格納  00000000 000000yy yyyyyyyx xxxxxxxx  i=0x00000|((a>>1)&0x3ffff)
  1308:   //          00000000 000001yy yyyyyyyx xxxxxxxx  i=0x40000|((a>>1)&0x3ffff)
  1309:   //    参照  00000000 11000yyy yyyyyyxx xxxxxxx0
  1310:   //    格納  00000000 000010yy yyyyyyyx xxxxxxxx  i=0x80000|((a>>1)&0x3ffff)
  1311:   //          00000000 000011yy yyyyyyyx xxxxxxxx  i=0xc0000|((a>>1)&0x3ffff)
  1312:   //
  1313:   MMD_GG0 {
  1314:     @Override public String toString () {
  1315:       return Multilingual.mlnJapanese ? "グラフィックス画面 (512 ドット 65536 色)" : "Graphics Screen (512 dots 65536 colors)";
  1316:     }
  1317:     //ピーク
  1318:     @Override protected byte mmdPbs (int a) {
  1319:       int i = (a >> 1) & 0x3ffff;
  1320:       return (byte) ((a & 1) == 0 ?
  1321:                      GraphicScreen.graM4[0xc0000 + i] << 4 |
  1322:                      GraphicScreen.graM4[0x80000 + i] :
  1323:                      GraphicScreen.graM4[0x40000 + i] << 4 |
  1324:                      GraphicScreen.graM4[          i]);
  1325:     }
  1326:     @Override protected int mmdPbz (int a) {
  1327:       int i = (a >> 1) & 0x3ffff;
  1328:       return ((a & 1) == 0 ?
  1329:               GraphicScreen.graM4[0xc0000 + i] << 4 |
  1330:               GraphicScreen.graM4[0x80000 + i] :
  1331:               GraphicScreen.graM4[0x40000 + i] << 4 |
  1332:               GraphicScreen.graM4[          i]);
  1333:     }
  1334:     @Override protected int mmdPws (int a) {
  1335:       int i = (a >> 1) & 0x3ffff;
  1336:       return (short) (GraphicScreen.graM4[0xc0000 + i] << 12 |
  1337:                       GraphicScreen.graM4[0x80000 + i] <<  8 |
  1338:                       GraphicScreen.graM4[0x40000 + i] <<  4 |
  1339:                       GraphicScreen.graM4[          i]);
  1340:     }
  1341:     @Override protected int mmdPwz (int a) {
  1342:       int i = (a >> 1) & 0x3ffff;
  1343:       return (GraphicScreen.graM4[0xc0000 + i] << 12 |
  1344:               GraphicScreen.graM4[0x80000 + i] <<  8 |
  1345:               GraphicScreen.graM4[0x40000 + i] <<  4 |
  1346:               GraphicScreen.graM4[          i]);
  1347:     }
  1348:     @Override protected int mmdPls (int a) {
  1349:       int i0 = ( a      >> 1) & 0x3ffff;
  1350:       int i1 = ((a + 2) >> 1) & 0x3ffff;
  1351:       return (GraphicScreen.graM4[0xc0000 + i0] << 28 |
  1352:               GraphicScreen.graM4[0x80000 + i0] << 24 |
  1353:               GraphicScreen.graM4[0x40000 + i0] << 20 |
  1354:               GraphicScreen.graM4[          i0] << 16 |
  1355:               GraphicScreen.graM4[0xc0000 + i1] << 12 |
  1356:               GraphicScreen.graM4[0x80000 + i1] <<  8 |
  1357:               GraphicScreen.graM4[0x40000 + i1] <<  4 |
  1358:               GraphicScreen.graM4[          i1]);
  1359:     }
  1360:     //リード
  1361:     @Override protected byte mmdRbs (int a) throws M68kException {
  1362:        XEiJ.mpuClockTime += XEiJ.busWaitTime.gvram;
  1363:        int i = (a >> 1) & 0x3ffff;
  1364:        return (byte) ((a & 1) == 0 ?
  1365:                       GraphicScreen.graM4[0xc0000 + i] << 4 |
  1366:                       GraphicScreen.graM4[0x80000 + i] :
  1367:                       GraphicScreen.graM4[0x40000 + i] << 4 |
  1368:                       GraphicScreen.graM4[          i]);
  1369:      }
  1370:     @Override protected int mmdRbz (int a) throws M68kException {
  1371:        XEiJ.mpuClockTime += XEiJ.busWaitTime.gvram;
  1372:        int i = (a >> 1) & 0x3ffff;
  1373:        return ((a & 1) == 0 ?
  1374:                GraphicScreen.graM4[0xc0000 + i] << 4 |
  1375:                GraphicScreen.graM4[0x80000 + i] :
  1376:                GraphicScreen.graM4[0x40000 + i] << 4 |
  1377:                GraphicScreen.graM4[          i]);
  1378:      }
  1379:     @Override protected int mmdRws (int a) throws M68kException {
  1380:        XEiJ.mpuClockTime += XEiJ.busWaitTime.gvram;
  1381:        int i = (a >> 1) & 0x3ffff;
  1382:        return (short) (GraphicScreen.graM4[0xc0000 + i] << 12 |
  1383:                        GraphicScreen.graM4[0x80000 + i] <<  8 |
  1384:                        GraphicScreen.graM4[0x40000 + i] <<  4 |
  1385:                        GraphicScreen.graM4[          i]);
  1386:      }
  1387:     @Override protected int mmdRwz (int a) throws M68kException {
  1388:        XEiJ.mpuClockTime += XEiJ.busWaitTime.gvram;
  1389:        int i = (a >> 1) & 0x3ffff;
  1390:        return (GraphicScreen.graM4[0xc0000 + i] << 12 |
  1391:                GraphicScreen.graM4[0x80000 + i] <<  8 |
  1392:                GraphicScreen.graM4[0x40000 + i] <<  4 |
  1393:                GraphicScreen.graM4[          i]);
  1394:      }
  1395:     @Override protected int mmdRls (int a) throws M68kException {
  1396:        XEiJ.mpuClockTime += XEiJ.busWaitTime.gvram * 2;
  1397:        int i0 = ( a      >> 1) & 0x3ffff;
  1398:        int i1 = ((a + 2) >> 1) & 0x3ffff;
  1399:        return (GraphicScreen.graM4[0xc0000 + i0] << 28 |
  1400:                GraphicScreen.graM4[0x80000 + i0] << 24 |
  1401:                GraphicScreen.graM4[0x40000 + i0] << 20 |
  1402:                GraphicScreen.graM4[          i0] << 16 |
  1403:                GraphicScreen.graM4[0xc0000 + i1] << 12 |
  1404:                GraphicScreen.graM4[0x80000 + i1] <<  8 |
  1405:                GraphicScreen.graM4[0x40000 + i1] <<  4 |
  1406:                GraphicScreen.graM4[          i1]);
  1407:      }
  1408:     //ライト
  1409:     @Override protected void mmdWb (int a, int d) throws M68kException {
  1410:        XEiJ.mpuClockTime += XEiJ.busWaitTime.gvram;
  1411:        int i = (a >> 1) & 0x3ffff;
  1412:        if ((a & 1) == 0) {
  1413:          GraphicScreen.graM4[0xc0000 + i] = (byte) ((d >> 4) & 15);
  1414:          GraphicScreen.graM4[0x80000 + i] = (byte) ( d       & 15);
  1415:          a >>= 10;
  1416:          int y = a - CRTC.crtR13GrYCurr[2] & 511;
  1417:          CRTC.crtRasterStamp[y      ] = 0;
  1418:          CRTC.crtRasterStamp[y + 512] = 0;
  1419:          y = a - CRTC.crtR13GrYCurr[3] & 511;
  1420:          CRTC.crtRasterStamp[y      ] = 0;
  1421:          CRTC.crtRasterStamp[y + 512] = 0;
  1422:        } else {
  1423:          GraphicScreen.graM4[0x40000 + i] = (byte) ((d >> 4) & 15);
  1424:          GraphicScreen.graM4[          i] = (byte) ( d       & 15);
  1425:          a >>= 10;
  1426:          int y = a - CRTC.crtR13GrYCurr[0] & 511;
  1427:          CRTC.crtRasterStamp[y      ] = 0;
  1428:          CRTC.crtRasterStamp[y + 512] = 0;
  1429:          y = a - CRTC.crtR13GrYCurr[1] & 511;
  1430:          CRTC.crtRasterStamp[y      ] = 0;
  1431:          CRTC.crtRasterStamp[y + 512] = 0;
  1432:        }
  1433:      }
  1434:     @Override protected void mmdWw (int a, int d) throws M68kException {
  1435:        XEiJ.mpuClockTime += XEiJ.busWaitTime.gvram;
  1436:        int i = (a >> 1) & 0x3ffff;
  1437:        GraphicScreen.graM4[0xc0000 + i] = (byte) ((d >> 12) & 15);
  1438:        GraphicScreen.graM4[0x80000 + i] = (byte) ((d >>  8) & 15);
  1439:        GraphicScreen.graM4[0x40000 + i] = (byte) ((d >>  4) & 15);
  1440:        GraphicScreen.graM4[          i] = (byte) ( d        & 15);
  1441:        a >>= 10;
  1442:        int y = a - CRTC.crtR13GrYCurr[0] & 511;
  1443:        CRTC.crtRasterStamp[y      ] = 0;
  1444:        CRTC.crtRasterStamp[y + 512] = 0;
  1445:        y = a - CRTC.crtR13GrYCurr[1] & 511;
  1446:        CRTC.crtRasterStamp[y      ] = 0;
  1447:        CRTC.crtRasterStamp[y + 512] = 0;
  1448:        y = a - CRTC.crtR13GrYCurr[2] & 511;
  1449:        CRTC.crtRasterStamp[y      ] = 0;
  1450:        CRTC.crtRasterStamp[y + 512] = 0;
  1451:        y = a - CRTC.crtR13GrYCurr[3] & 511;
  1452:        CRTC.crtRasterStamp[y      ] = 0;
  1453:        CRTC.crtRasterStamp[y + 512] = 0;
  1454:      }
  1455:     @Override protected void mmdWl (int a, int d) throws M68kException {
  1456:        XEiJ.mpuClockTime += XEiJ.busWaitTime.gvram * 2;
  1457:        int i0 = ( a      >> 1) & 0x3ffff;
  1458:        int i1 = ((a + 2) >> 1) & 0x3ffff;
  1459:        GraphicScreen.graM4[0xc0000 + i0] = (byte) (d >>> 28);
  1460:        GraphicScreen.graM4[0x80000 + i0] = (byte) ((d >> 24) & 15);
  1461:        GraphicScreen.graM4[0x40000 + i0] = (byte) ((d >> 20) & 15);
  1462:        GraphicScreen.graM4[          i0] = (byte) ((d >> 16) & 15);
  1463:        GraphicScreen.graM4[0xc0000 + i1] = (byte) ((char) d >> 12);
  1464:        GraphicScreen.graM4[0x80000 + i1] = (byte) ((d >>  8) & 15);
  1465:        GraphicScreen.graM4[0x40000 + i1] = (byte) ((d >>  4) & 15);
  1466:        GraphicScreen.graM4[          i1] = (byte) ( d        & 15);
  1467:        int b = (a + 2) >>> 10;
  1468:        int y = b - CRTC.crtR13GrYCurr[0] & 511;
  1469:        CRTC.crtRasterStamp[y      ] = 0;
  1470:        CRTC.crtRasterStamp[y + 512] = 0;
  1471:        y = b - CRTC.crtR13GrYCurr[1] & 511;
  1472:        CRTC.crtRasterStamp[y      ] = 0;
  1473:        CRTC.crtRasterStamp[y + 512] = 0;
  1474:        y = b - CRTC.crtR13GrYCurr[2] & 511;
  1475:        CRTC.crtRasterStamp[y      ] = 0;
  1476:        CRTC.crtRasterStamp[y + 512] = 0;
  1477:        y = b - CRTC.crtR13GrYCurr[3] & 511;
  1478:        CRTC.crtRasterStamp[y      ] = 0;
  1479:        CRTC.crtRasterStamp[y + 512] = 0;
  1480:        a >>>= 10;
  1481:        if (a != b) {
  1482:          y = a - CRTC.crtR13GrYCurr[0] & 511;
  1483:          CRTC.crtRasterStamp[y      ] = 0;
  1484:          CRTC.crtRasterStamp[y + 512] = 0;
  1485:          y = a - CRTC.crtR13GrYCurr[1] & 511;
  1486:          CRTC.crtRasterStamp[y      ] = 0;
  1487:          CRTC.crtRasterStamp[y + 512] = 0;
  1488:          y = a - CRTC.crtR13GrYCurr[2] & 511;
  1489:          CRTC.crtRasterStamp[y      ] = 0;
  1490:          CRTC.crtRasterStamp[y + 512] = 0;
  1491:          y = a - CRTC.crtR13GrYCurr[3] & 511;
  1492:          CRTC.crtRasterStamp[y      ] = 0;
  1493:          CRTC.crtRasterStamp[y + 512] = 0;
  1494:        }
  1495:      }
  1496:   },  //MMD_GG0
  1497: 
  1498:   //--------------------------------------------------------------------------------
  1499:   //MMD_GH0 グラフィックス画面(1024ドット16色)
  1500:   //
  1501:   //  1024ドット16色
  1502:   //         ------------------参照------------------        --------------格納--------------
  1503:   //    GH0  0x00c00000~0x00dfffff  ............3210  ──  0x00000000~0x000fffff  ....3210
  1504:   //    参照  00000000 110Yyyyy yyyyyXxx xxxxxxx1
  1505:   //    格納  00000000 0000YXyy yyyyyyyx xxxxxxxx  i=0x000000|((a>>1)&0x801ff)|((a<<8)&0x40000)|((a>>2)&0x3fe00)
  1506:   //
  1507:   MMD_GH0 {
  1508:     @Override public String toString () {
  1509:       return Multilingual.mlnJapanese ? "グラフィックス画面 (1024 ドット 16 色)" : "Graphics Screen (1024 dots 16 colors)";
  1510:     }
  1511:     //ピーク
  1512:     @Override protected byte mmdPbs (int a) {
  1513:       return ((a & 1) == 0 ? 0 :
  1514:               GraphicScreen.graM4[((a >> 1) & 0x801ff) | ((a << 8) & 0x40000) | ((a >> 2) & 0x3fe00)]);
  1515:     }
  1516:     @Override protected int mmdPbz (int a) {
  1517:       return ((a & 1) == 0 ? 0 :
  1518:               GraphicScreen.graM4[((a >> 1) & 0x801ff) | ((a << 8) & 0x40000) | ((a >> 2) & 0x3fe00)]);
  1519:     }
  1520:     @Override protected int mmdPws (int a) {
  1521:       return GraphicScreen.graM4[((a >> 1) & 0x801ff) | ((a << 8) & 0x40000) | ((a >> 2) & 0x3fe00)];
  1522:     }
  1523:     @Override protected int mmdPwz (int a) {
  1524:       return GraphicScreen.graM4[((a >> 1) & 0x801ff) | ((a << 8) & 0x40000) | ((a >> 2) & 0x3fe00)];
  1525:     }
  1526:     @Override protected int mmdPls (int a) {
  1527:       int i0 = ((a >> 1) & 0x801ff) | ((a << 8) & 0x40000) | ((a >> 2) & 0x3fe00);
  1528:       a += 2;
  1529:       int i1 = ((a >> 1) & 0x801ff) | ((a << 8) & 0x40000) | ((a >> 2) & 0x3fe00);
  1530:       return (GraphicScreen.graM4[i0] << 16 |
  1531:               GraphicScreen.graM4[i1]);
  1532:     }
  1533:     //リード
  1534:     @Override protected byte mmdRbs (int a) throws M68kException {
  1535:        XEiJ.mpuClockTime += XEiJ.busWaitTime.gvram;
  1536:        return ((a & 1) == 0 ? 0 :
  1537:                GraphicScreen.graM4[((a >> 1) & 0x801ff) | ((a << 8) & 0x40000) | ((a >> 2) & 0x3fe00)]);
  1538:      }
  1539:     @Override protected int mmdRbz (int a) throws M68kException {
  1540:        XEiJ.mpuClockTime += XEiJ.busWaitTime.gvram;
  1541:        return ((a & 1) == 0 ? 0 :
  1542:                GraphicScreen.graM4[((a >> 1) & 0x801ff) | ((a << 8) & 0x40000) | ((a >> 2) & 0x3fe00)]);
  1543:      }
  1544:     @Override protected int mmdRws (int a) throws M68kException {
  1545:        XEiJ.mpuClockTime += XEiJ.busWaitTime.gvram;
  1546:        return GraphicScreen.graM4[((a >> 1) & 0x801ff) | ((a << 8) & 0x40000) | ((a >> 2) & 0x3fe00)];
  1547:      }
  1548:     @Override protected int mmdRwz (int a) throws M68kException {
  1549:        XEiJ.mpuClockTime += XEiJ.busWaitTime.gvram;
  1550:        return GraphicScreen.graM4[((a >> 1) & 0x801ff) | ((a << 8) & 0x40000) | ((a >> 2) & 0x3fe00)];
  1551:      }
  1552:     @Override protected int mmdRls (int a) throws M68kException {
  1553:        XEiJ.mpuClockTime += XEiJ.busWaitTime.gvram * 2;
  1554:        int i0 = ((a >> 1) & 0x801ff) | ((a << 8) & 0x40000) | ((a >> 2) & 0x3fe00);
  1555:        a += 2;
  1556:        int i1 = ((a >> 1) & 0x801ff) | ((a << 8) & 0x40000) | ((a >> 2) & 0x3fe00);
  1557:        return (GraphicScreen.graM4[i0] << 16 |
  1558:                GraphicScreen.graM4[i1]);
  1559:      }
  1560:     //ライト
  1561:     @Override protected void mmdWb (int a, int d) throws M68kException {
  1562:        XEiJ.mpuClockTime += XEiJ.busWaitTime.gvram;
  1563:        if ((a & 1) != 0) {
  1564:          CRTC.crtRasterStamp[(a >> 11) - CRTC.crtR13GrYCurr[0] & 1023] = 0;
  1565:          GraphicScreen.graM4[((a >> 1) & 0x801ff) | ((a << 8) & 0x40000) | ((a >> 2) & 0x3fe00)] = (byte) (d & 15);
  1566:        }
  1567:      }
  1568:     @Override protected void mmdWw (int a, int d) throws M68kException {
  1569:        XEiJ.mpuClockTime += XEiJ.busWaitTime.gvram;
  1570:        CRTC.crtRasterStamp[(a >> 11) - CRTC.crtR13GrYCurr[0] & 1023] = 0;
  1571:        GraphicScreen.graM4[((a >> 1) & 0x801ff) | ((a << 8) & 0x40000) | ((a >> 2) & 0x3fe00)] = (byte) (d & 15);
  1572:      }
  1573:     @Override protected void mmdWl (int a, int d) throws M68kException {
  1574:        XEiJ.mpuClockTime += XEiJ.busWaitTime.gvram * 2;
  1575:        CRTC.crtRasterStamp[(a >> 11) - CRTC.crtR13GrYCurr[0] & 1023] = 0;
  1576:        GraphicScreen.graM4[((a >> 1) & 0x801ff) | ((a << 8) & 0x40000) | ((a >> 2) & 0x3fe00)] = (byte) ((d >> 16) & 15);
  1577:        a += 2;
  1578:        CRTC.crtRasterStamp[(a >> 11) - CRTC.crtR13GrYCurr[0] & 1023] = 0;
  1579:        GraphicScreen.graM4[((a >> 1) & 0x801ff) | ((a << 8) & 0x40000) | ((a >> 2) & 0x3fe00)] = (byte) ( d        & 15);
  1580:      }
  1581:   },  //MMD_GH0
  1582: 
  1583:   //--------------------------------------------------------------------------------
  1584:   //MMD_GI0 グラフィックス画面(1024ドット256色)
  1585:   //
  1586:   //  1024ドット256色
  1587:   //         ------------------参照------------------        --------------格納--------------
  1588:   //    GI0  0x00c00000~0x00dfffff  ........76543210  ─┬  0x00000000~0x000fffff  ....3210
  1589:   //                                                     └  0x00100000~0x001fffff  ....7654
  1590:   //    参照  00000000 110Yyyyy yyyyyXxx xxxxxxx1
  1591:   //    格納  00000000 0000YXyy yyyyyyyx xxxxxxxx  i=0x000000|((a>>1)&0x801ff)|((a<<8)&0x40000)|((a>>2)&0x3fe00)
  1592:   //          00000000 0001YXyy yyyyyyyx xxxxxxxx  i=0x100000|((a>>1)&0x801ff)|((a<<8)&0x40000)|((a>>2)&0x3fe00)
  1593:   //
  1594:   MMD_GI0 {
  1595:     @Override public String toString () {
  1596:       return Multilingual.mlnJapanese ? "グラフィックス画面 (1024 ドット 256 色)" : "Graphics Screen (1024 dots 256 colors)";
  1597:     }
  1598:     //ピーク
  1599:     @Override protected byte mmdPbs (int a) {
  1600:       int i = ((a >> 1) & 0x801ff) | ((a << 8) & 0x40000) | ((a >> 2) & 0x3fe00);
  1601:       return (byte) ((a & 1) == 0 ? 0 :
  1602:                      GraphicScreen.graM4[0x100000 + i] << 4 |
  1603:                      GraphicScreen.graM4[           i]);
  1604:     }
  1605:     @Override protected int mmdPbz (int a) {
  1606:       int i = ((a >> 1) & 0x801ff) | ((a << 8) & 0x40000) | ((a >> 2) & 0x3fe00);
  1607:       return ((a & 1) == 0 ? 0 :
  1608:               GraphicScreen.graM4[0x100000 + i] << 4 |
  1609:               GraphicScreen.graM4[           i]);
  1610:     }
  1611:     @Override protected int mmdPws (int a) {
  1612:       int i = ((a >> 1) & 0x801ff) | ((a << 8) & 0x40000) | ((a >> 2) & 0x3fe00);
  1613:       return (GraphicScreen.graM4[0x100000 + i] << 4 |
  1614:               GraphicScreen.graM4[           i]);
  1615:     }
  1616:     @Override protected int mmdPwz (int a) {
  1617:       int i = ((a >> 1) & 0x801ff) | ((a << 8) & 0x40000) | ((a >> 2) & 0x3fe00);
  1618:       return (GraphicScreen.graM4[0x100000 + i] << 4 |
  1619:               GraphicScreen.graM4[           i]);
  1620:     }
  1621:     @Override protected int mmdPls (int a) {
  1622:       int i0 = ((a >> 1) & 0x801ff) | ((a << 8) & 0x40000) | ((a >> 2) & 0x3fe00);
  1623:       a += 2;
  1624:       int i1 = ((a >> 1) & 0x801ff) | ((a << 8) & 0x40000) | ((a >> 2) & 0x3fe00);
  1625:       return (GraphicScreen.graM4[0x100000 + i0] << 20 |
  1626:               GraphicScreen.graM4[           i0] << 16 |
  1627:               GraphicScreen.graM4[0x100000 + i1] <<  4 |
  1628:               GraphicScreen.graM4[           i1]);
  1629:     }
  1630:     //リード
  1631:     @Override protected byte mmdRbs (int a) throws M68kException {
  1632:        XEiJ.mpuClockTime += XEiJ.busWaitTime.gvram;
  1633:        int i = ((a >> 1) & 0x801ff) | ((a << 8) & 0x40000) | ((a >> 2) & 0x3fe00);
  1634:        return (byte) ((a & 1) == 0 ? 0 :
  1635:                       GraphicScreen.graM4[0x100000 + i] << 4 |
  1636:                       GraphicScreen.graM4[           i]);
  1637:      }
  1638:     @Override protected int mmdRbz (int a) throws M68kException {
  1639:        XEiJ.mpuClockTime += XEiJ.busWaitTime.gvram;
  1640:        int i = ((a >> 1) & 0x801ff) | ((a << 8) & 0x40000) | ((a >> 2) & 0x3fe00);
  1641:        return ((a & 1) == 0 ? 0 :
  1642:                GraphicScreen.graM4[0x100000 + i] << 4 |
  1643:                GraphicScreen.graM4[           i]);
  1644:      }
  1645:     @Override protected int mmdRws (int a) throws M68kException {
  1646:        XEiJ.mpuClockTime += XEiJ.busWaitTime.gvram;
  1647:        int i = ((a >> 1) & 0x801ff) | ((a << 8) & 0x40000) | ((a >> 2) & 0x3fe00);
  1648:        return (GraphicScreen.graM4[0x100000 + i] << 4 |
  1649:                GraphicScreen.graM4[           i]);
  1650:      }
  1651:     @Override protected int mmdRwz (int a) throws M68kException {
  1652:        XEiJ.mpuClockTime += XEiJ.busWaitTime.gvram;
  1653:        int i = ((a >> 1) & 0x801ff) | ((a << 8) & 0x40000) | ((a >> 2) & 0x3fe00);
  1654:        return (GraphicScreen.graM4[0x100000 + i] << 4 |
  1655:                GraphicScreen.graM4[           i]);
  1656:      }
  1657:     @Override protected int mmdRls (int a) throws M68kException {
  1658:        XEiJ.mpuClockTime += XEiJ.busWaitTime.gvram * 2;
  1659:        int i0 = ((a >> 1) & 0x801ff) | ((a << 8) & 0x40000) | ((a >> 2) & 0x3fe00);
  1660:        a += 2;
  1661:        int i1 = ((a >> 1) & 0x801ff) | ((a << 8) & 0x40000) | ((a >> 2) & 0x3fe00);
  1662:        return (GraphicScreen.graM4[0x100000 + i0] << 20 |
  1663:                GraphicScreen.graM4[           i0] << 16 |
  1664:                GraphicScreen.graM4[0x100000 + i1] <<  4 |
  1665:                GraphicScreen.graM4[           i1]);
  1666:      }
  1667:     //ライト
  1668:     @Override protected void mmdWb (int a, int d) throws M68kException {
  1669:        XEiJ.mpuClockTime += XEiJ.busWaitTime.gvram;
  1670:        if ((a & 1) != 0) {
  1671:          CRTC.crtRasterStamp[(a >> 11) - CRTC.crtR13GrYCurr[0] & 1023] = 0;
  1672:          int i = ((a >> 1) & 0x801ff) | ((a << 8) & 0x40000) | ((a >> 2) & 0x3fe00);
  1673:          GraphicScreen.graM4[0x100000 + i] = (byte) ((d >> 4) & 15);
  1674:          GraphicScreen.graM4[           i] = (byte) ( d       & 15);
  1675:        }
  1676:      }
  1677:     @Override protected void mmdWw (int a, int d) throws M68kException {
  1678:        XEiJ.mpuClockTime += XEiJ.busWaitTime.gvram;
  1679:        CRTC.crtRasterStamp[(a >> 11) - CRTC.crtR13GrYCurr[0] & 1023] = 0;
  1680:        int i = ((a >> 1) & 0x801ff) | ((a << 8) & 0x40000) | ((a >> 2) & 0x3fe00);
  1681:        GraphicScreen.graM4[0x100000 + i] = (byte) ((d >> 4) & 15);
  1682:        GraphicScreen.graM4[           i] = (byte) ( d       & 15);
  1683:      }
  1684:     @Override protected void mmdWl (int a, int d) throws M68kException {
  1685:        XEiJ.mpuClockTime += XEiJ.busWaitTime.gvram * 2;
  1686:        CRTC.crtRasterStamp[(a >> 11) - CRTC.crtR13GrYCurr[0] & 1023] = 0;
  1687:        int i0 = ((a >> 1) & 0x801ff) | ((a << 8) & 0x40000) | ((a >> 2) & 0x3fe00);
  1688:        a += 2;
  1689:        CRTC.crtRasterStamp[(a >> 11) - CRTC.crtR13GrYCurr[0] & 1023] = 0;
  1690:        int i1 = ((a >> 1) & 0x801ff) | ((a << 8) & 0x40000) | ((a >> 2) & 0x3fe00);
  1691:        GraphicScreen.graM4[0x100000 + i0] = (byte) ((d >> 20) & 15);
  1692:        GraphicScreen.graM4[           i0] = (byte) ((d >> 16) & 15);
  1693:        GraphicScreen.graM4[0x100000 + i1] = (byte) ((d >>  4) & 15);
  1694:        GraphicScreen.graM4[           i1] = (byte) ( d        & 15);
  1695:      }
  1696:   },  //MMD_GI0
  1697: 
  1698:   //--------------------------------------------------------------------------------
  1699:   //MMD_GJ0 グラフィックス画面(1024ドット65536色)
  1700:   //
  1701:   //  1024ドット65536色
  1702:   //         ------------------参照------------------        --------------格納--------------
  1703:   //    GJ0  0x00c00000~0x00dfffff  fedcba9876543210  ─┬  0x00000000~0x000fffff  ....3210
  1704:   //                                                     ├  0x00100000~0x001fffff  ....7654
  1705:   //                                                     ├  0x00200000~0x002fffff  ....ba98
  1706:   //                                                     └  0x00300000~0x003fffff  ....fedc
  1707:   //    参照  00000000 110Yyyyy yyyyyXxx xxxxxxx1
  1708:   //    格納  00000000 0000YXyy yyyyyyyx xxxxxxxx  i=0x000000|((a>>1)&0x801ff)|((a<<8)&0x40000)|((a>>2)&0x3fe00)
  1709:   //          00000000 0001YXyy yyyyyyyx xxxxxxxx  i=0x100000|((a>>1)&0x801ff)|((a<<8)&0x40000)|((a>>2)&0x3fe00)
  1710:   //    参照  00000000 110Yyyyy yyyyyXxx xxxxxxx0
  1711:   //    格納  00000000 0010YXyy yyyyyyyx xxxxxxxx  i=0x200000|((a>>1)&0x801ff)|((a<<8)&0x40000)|((a>>2)&0x3fe00)
  1712:   //          00000000 0011YXyy yyyyyyyx xxxxxxxx  i=0x300000|((a>>1)&0x801ff)|((a<<8)&0x40000)|((a>>2)&0x3fe00)
  1713:   //
  1714:   MMD_GJ0 {
  1715:     @Override public String toString () {
  1716:       return Multilingual.mlnJapanese ? "グラフィックス画面 (1024 ドット 65536 色)" : "Graphics Screen (1024 dots 65536 colors)";
  1717:     }
  1718:     //ピーク
  1719:     @Override protected byte mmdPbs (int a) {
  1720:       int i = ((a >> 1) & 0x801ff) | ((a << 8) & 0x40000) | ((a >> 2) & 0x3fe00);
  1721:       return (byte) ((a & 1) == 0 ?
  1722:                      GraphicScreen.graM4[0x300000 + i] << 4 |
  1723:                      GraphicScreen.graM4[0x200000 + i] :
  1724:                      GraphicScreen.graM4[0x100000 + i] << 4 |
  1725:                      GraphicScreen.graM4[           i]);
  1726:     }
  1727:     @Override protected int mmdPbz (int a) {
  1728:       int i = ((a >> 1) & 0x801ff) | ((a << 8) & 0x40000) | ((a >> 2) & 0x3fe00);
  1729:       return ((a & 1) == 0 ?
  1730:               GraphicScreen.graM4[0x300000 + i] << 4 |
  1731:               GraphicScreen.graM4[0x200000 + i] :
  1732:               GraphicScreen.graM4[0x100000 + i] << 4 |
  1733:               GraphicScreen.graM4[           i]);
  1734:     }
  1735:     @Override protected int mmdPws (int a) {
  1736:       int i = ((a >> 1) & 0x801ff) | ((a << 8) & 0x40000) | ((a >> 2) & 0x3fe00);
  1737:       return (short) (GraphicScreen.graM4[0x300000 + i] << 12 |
  1738:                       GraphicScreen.graM4[0x200000 + i] <<  8 |
  1739:                       GraphicScreen.graM4[0x100000 + i] <<  4 |
  1740:                       GraphicScreen.graM4[           i]);
  1741:     }
  1742:     @Override protected int mmdPwz (int a) {
  1743:       int i = ((a >> 1) & 0x801ff) | ((a << 8) & 0x40000) | ((a >> 2) & 0x3fe00);
  1744:       return (GraphicScreen.graM4[0x300000 + i] << 12 |
  1745:               GraphicScreen.graM4[0x200000 + i] <<  8 |
  1746:               GraphicScreen.graM4[0x100000 + i] <<  4 |
  1747:               GraphicScreen.graM4[           i]);
  1748:     }
  1749:     @Override protected int mmdPls (int a) {
  1750:       int i0 = ((a >> 1) & 0x801ff) | ((a << 8) & 0x40000) | ((a >> 2) & 0x3fe00);
  1751:       a += 2;
  1752:       int i1 = ((a >> 1) & 0x801ff) | ((a << 8) & 0x40000) | ((a >> 2) & 0x3fe00);
  1753:       return (GraphicScreen.graM4[0x300000 + i0] << 28 |
  1754:               GraphicScreen.graM4[0x200000 + i0] << 24 |
  1755:               GraphicScreen.graM4[0x100000 + i0] << 20 |
  1756:               GraphicScreen.graM4[           i0] << 16 |
  1757:               GraphicScreen.graM4[0x300000 + i1] << 12 |
  1758:               GraphicScreen.graM4[0x200000 + i1] <<  8 |
  1759:               GraphicScreen.graM4[0x100000 + i1] <<  4 |
  1760:               GraphicScreen.graM4[           i1]);
  1761:     }
  1762:     //リード
  1763:     @Override protected byte mmdRbs (int a) throws M68kException {
  1764:        XEiJ.mpuClockTime += XEiJ.busWaitTime.gvram;
  1765:        int i = ((a >> 1) & 0x801ff) | ((a << 8) & 0x40000) | ((a >> 2) & 0x3fe00);
  1766:        return (byte) ((a & 1) == 0 ?
  1767:                       GraphicScreen.graM4[0x300000 + i] << 4 |
  1768:                       GraphicScreen.graM4[0x200000 + i] :
  1769:                       GraphicScreen.graM4[0x100000 + i] << 4 |
  1770:                       GraphicScreen.graM4[           i]);
  1771:      }
  1772:     @Override protected int mmdRbz (int a) throws M68kException {
  1773:        XEiJ.mpuClockTime += XEiJ.busWaitTime.gvram;
  1774:        int i = ((a >> 1) & 0x801ff) | ((a << 8) & 0x40000) | ((a >> 2) & 0x3fe00);
  1775:        return ((a & 1) == 0 ?
  1776:                GraphicScreen.graM4[0x300000 + i] << 4 |
  1777:                GraphicScreen.graM4[0x200000 + i] :
  1778:                GraphicScreen.graM4[0x100000 + i] << 4 |
  1779:                GraphicScreen.graM4[           i]);
  1780:      }
  1781:     @Override protected int mmdRws (int a) throws M68kException {
  1782:        XEiJ.mpuClockTime += XEiJ.busWaitTime.gvram;
  1783:        int i = ((a >> 1) & 0x801ff) | ((a << 8) & 0x40000) | ((a >> 2) & 0x3fe00);
  1784:        return (short) (GraphicScreen.graM4[0x300000 + i] << 12 |
  1785:                        GraphicScreen.graM4[0x200000 + i] <<  8 |
  1786:                        GraphicScreen.graM4[0x100000 + i] <<  4 |
  1787:                        GraphicScreen.graM4[           i]);
  1788:      }
  1789:     @Override protected int mmdRwz (int a) throws M68kException {
  1790:        XEiJ.mpuClockTime += XEiJ.busWaitTime.gvram;
  1791:        int i = ((a >> 1) & 0x801ff) | ((a << 8) & 0x40000) | ((a >> 2) & 0x3fe00);
  1792:        return (GraphicScreen.graM4[0x300000 + i] << 12 |
  1793:                GraphicScreen.graM4[0x200000 + i] <<  8 |
  1794:                GraphicScreen.graM4[0x100000 + i] <<  4 |
  1795:                GraphicScreen.graM4[           i]);
  1796:      }
  1797:     @Override protected int mmdRls (int a) throws M68kException {
  1798:        XEiJ.mpuClockTime += XEiJ.busWaitTime.gvram * 2;
  1799:        int i0 = ((a >> 1) & 0x801ff) | ((a << 8) & 0x40000) | ((a >> 2) & 0x3fe00);
  1800:        a += 2;
  1801:        int i1 = ((a >> 1) & 0x801ff) | ((a << 8) & 0x40000) | ((a >> 2) & 0x3fe00);
  1802:        return (GraphicScreen.graM4[0x300000 + i0] << 28 |
  1803:                GraphicScreen.graM4[0x200000 + i0] << 24 |
  1804:                GraphicScreen.graM4[0x100000 + i0] << 20 |
  1805:                GraphicScreen.graM4[           i0] << 16 |
  1806:                GraphicScreen.graM4[0x300000 + i1] << 12 |
  1807:                GraphicScreen.graM4[0x200000 + i1] <<  8 |
  1808:                GraphicScreen.graM4[0x100000 + i1] <<  4 |
  1809:                GraphicScreen.graM4[           i1]);
  1810:      }
  1811:     //ライト
  1812:     @Override protected void mmdWb (int a, int d) throws M68kException {
  1813:        XEiJ.mpuClockTime += XEiJ.busWaitTime.gvram;
  1814:        CRTC.crtRasterStamp[(a >> 11) - CRTC.crtR13GrYCurr[0] & 1023] = 0;
  1815:        int i = ((a >> 1) & 0x801ff) | ((a << 8) & 0x40000) | ((a >> 2) & 0x3fe00);
  1816:        if ((a & 1) == 0) {
  1817:          GraphicScreen.graM4[0x300000 + i] = (byte) ((d >> 4) & 15);
  1818:          GraphicScreen.graM4[0x200000 + i] = (byte) ( d       & 15);
  1819:        } else {
  1820:          GraphicScreen.graM4[0x100000 + i] = (byte) ((d >> 4) & 15);
  1821:          GraphicScreen.graM4[           i] = (byte) ( d       & 15);
  1822:        }
  1823:      }
  1824:     @Override protected void mmdWw (int a, int d) throws M68kException {
  1825:        XEiJ.mpuClockTime += XEiJ.busWaitTime.gvram;
  1826:        CRTC.crtRasterStamp[(a >> 11) - CRTC.crtR13GrYCurr[0] & 1023] = 0;
  1827:        int i = ((a >> 1) & 0x801ff) | ((a << 8) & 0x40000) | ((a >> 2) & 0x3fe00);
  1828:        GraphicScreen.graM4[0x300000 + i] = (byte) ((char) d >> 12);
  1829:        GraphicScreen.graM4[0x200000 + i] = (byte) ((d >>  8) & 15);
  1830:        GraphicScreen.graM4[0x100000 + i] = (byte) ((d >>  4) & 15);
  1831:        GraphicScreen.graM4[           i] = (byte) ( d        & 15);
  1832:      }
  1833:     @Override protected void mmdWl (int a, int d) throws M68kException {
  1834:        XEiJ.mpuClockTime += XEiJ.busWaitTime.gvram * 2;
  1835:        CRTC.crtRasterStamp[(a >> 11) - CRTC.crtR13GrYCurr[0] & 1023] = 0;
  1836:        int i0 = ((a >> 1) & 0x801ff) | ((a << 8) & 0x40000) | ((a >> 2) & 0x3fe00);
  1837:        a += 2;
  1838:        CRTC.crtRasterStamp[(a >> 11) - CRTC.crtR13GrYCurr[0] & 1023] = 0;
  1839:        int i1 = ((a >> 1) & 0x801ff) | ((a << 8) & 0x40000) | ((a >> 2) & 0x3fe00);
  1840:        GraphicScreen.graM4[0x300000 + i0] = (byte) (d >>> 28);
  1841:        GraphicScreen.graM4[0x200000 + i0] = (byte) ((d >> 24) & 15);
  1842:        GraphicScreen.graM4[0x100000 + i0] = (byte) ((d >> 20) & 15);
  1843:        GraphicScreen.graM4[           i0] = (byte) ((d >> 16) & 15);
  1844:        GraphicScreen.graM4[0x300000 + i1] = (byte) ((char) d >> 12);
  1845:        GraphicScreen.graM4[0x200000 + i1] = (byte) ((d >>  8) & 15);
  1846:        GraphicScreen.graM4[0x100000 + i1] = (byte) ((d >>  4) & 15);
  1847:        GraphicScreen.graM4[           i1] = (byte) ( d        & 15);
  1848:      }
  1849:   },  //MMD_GJ0
  1850: 
  1851:   //--------------------------------------------------------------------------------
  1852:   //MMD_TXT テキスト画面
  1853:   MMD_TXT {
  1854:     @Override public String toString () {
  1855:       return Multilingual.mlnJapanese ? "テキスト画面" : "Text Screen";
  1856:     }
  1857:     //ピーク
  1858:     @Override protected byte mmdPbs (int a) {
  1859:       a &= XEiJ.BUS_MOTHER_MASK;
  1860:       return MainMemory.mmrM8[a];
  1861:     }
  1862:     @Override protected int mmdPbz (int a) {
  1863:       a &= XEiJ.BUS_MOTHER_MASK;
  1864:       return MainMemory.mmrM8[a] & 0xff;
  1865:     }
  1866:     @Override protected int mmdPws (int a) {
  1867:       a &= XEiJ.BUS_MOTHER_MASK;
  1868:       if (MainMemory.MMR_USE_BYTE_BUFFER) {
  1869:         return MainMemory.mmrBuffer.getShort (a);
  1870:       } else {
  1871:         return MainMemory.mmrM8[a] << 8 | (MainMemory.mmrM8[a + 1] & 0xff);
  1872:       }
  1873:     }
  1874:     @Override protected int mmdPwz (int a) {
  1875:       a &= XEiJ.BUS_MOTHER_MASK;
  1876:       if (MainMemory.MMR_USE_BYTE_BUFFER) {
  1877:         return MainMemory.mmrBuffer.getChar (a);
  1878:       } else {
  1879:         return (char) (MainMemory.mmrM8[a] << 8 | (MainMemory.mmrM8[a + 1] & 0xff));
  1880:       }
  1881:     }
  1882:     @Override protected int mmdPls (int a) {
  1883:       a &= XEiJ.BUS_MOTHER_MASK;
  1884:       if (MainMemory.MMR_USE_BYTE_BUFFER) {
  1885:         return MainMemory.mmrBuffer.getInt (a);
  1886:       } else {
  1887:         return MainMemory.mmrM8[a] << 24 | (MainMemory.mmrM8[a + 1] & 0xff) << 16 | (char) (MainMemory.mmrM8[a + 2] << 8 | (MainMemory.mmrM8[a + 3] & 0xff));
  1888:       }
  1889:     }
  1890:     //リード
  1891:     @Override protected byte mmdRbs (int a) throws M68kException {
  1892:        XEiJ.mpuClockTime += XEiJ.busWaitTime.tvram;
  1893:        a &= XEiJ.BUS_MOTHER_MASK;
  1894:        return MainMemory.mmrM8[a];
  1895:      }
  1896:     @Override protected int mmdRbz (int a) throws M68kException {
  1897:        XEiJ.mpuClockTime += XEiJ.busWaitTime.tvram;
  1898:        a &= XEiJ.BUS_MOTHER_MASK;
  1899:        return MainMemory.mmrM8[a] & 0xff;
  1900:      }
  1901:     @Override protected int mmdRws (int a) throws M68kException {
  1902:        XEiJ.mpuClockTime += XEiJ.busWaitTime.tvram;
  1903:        a &= XEiJ.BUS_MOTHER_MASK;
  1904:        if (MainMemory.MMR_USE_BYTE_BUFFER) {
  1905:          return MainMemory.mmrBuffer.getShort (a);
  1906:        } else {
  1907:          return MainMemory.mmrM8[a] << 8 | (MainMemory.mmrM8[a + 1] & 0xff);
  1908:        }
  1909:      }
  1910:     @Override protected int mmdRwz (int a) throws M68kException {
  1911:        XEiJ.mpuClockTime += XEiJ.busWaitTime.tvram;
  1912:        a &= XEiJ.BUS_MOTHER_MASK;
  1913:        if (MainMemory.MMR_USE_BYTE_BUFFER) {
  1914:          return MainMemory.mmrBuffer.getChar (a);
  1915:        } else {
  1916:          return (char) (MainMemory.mmrM8[a] << 8 | (MainMemory.mmrM8[a + 1] & 0xff));
  1917:        }
  1918:      }
  1919:     @Override protected int mmdRls (int a) throws M68kException {
  1920:        XEiJ.mpuClockTime += XEiJ.busWaitTime.tvram * 2;
  1921:        a &= XEiJ.BUS_MOTHER_MASK;
  1922:        if (MainMemory.MMR_USE_BYTE_BUFFER) {
  1923:          return MainMemory.mmrBuffer.getInt (a);
  1924:        } else {
  1925:          return MainMemory.mmrM8[a] << 24 | (MainMemory.mmrM8[a + 1] & 0xff) << 16 | (char) (MainMemory.mmrM8[a + 2] << 8 | (MainMemory.mmrM8[a + 3] & 0xff));
  1926:        }
  1927:      }
  1928:     //ライト
  1929:     @Override protected void mmdWb (int a, int d) throws M68kException {
  1930:        XEiJ.mpuClockTime += XEiJ.busWaitTime.tvram;
  1931:        a &= XEiJ.BUS_MOTHER_MASK;
  1932:        int x;  //マスク
  1933:        if (CRTC.crtSimAccess) {  //同時アクセスあり
  1934:          a &= 0x00e1ffff;
  1935:          if (CRTC.crtBitMask) {  //同時アクセスあり,ビットマスクあり
  1936:            d &= ~(x = CRTC.crtR23Mask >> ((~a & 1) << 3));
  1937:            if (CRTC.crtSimPlane0) {
  1938:              MainMemory.mmrM8[a             ] = (byte) (MainMemory.mmrM8[a             ] & x | d);
  1939:            }
  1940:            if (CRTC.crtSimPlane1) {
  1941:              MainMemory.mmrM8[a + 0x00020000] = (byte) (MainMemory.mmrM8[a + 0x00020000] & x | d);
  1942:            }
  1943:            if (CRTC.crtSimPlane2) {
  1944:              MainMemory.mmrM8[a + 0x00040000] = (byte) (MainMemory.mmrM8[a + 0x00040000] & x | d);
  1945:            }
  1946:            if (CRTC.crtSimPlane3) {
  1947:              MainMemory.mmrM8[a + 0x00060000] = (byte) (MainMemory.mmrM8[a + 0x00060000] & x | d);
  1948:            }
  1949:          } else {  //同時アクセスあり,ビットマスクなし
  1950:            if (CRTC.crtSimPlane0) {
  1951:              MainMemory.mmrM8[a             ] = (byte) d;
  1952:            }
  1953:            if (CRTC.crtSimPlane1) {
  1954:              MainMemory.mmrM8[a + 0x00020000] = (byte) d;
  1955:            }
  1956:            if (CRTC.crtSimPlane2) {
  1957:              MainMemory.mmrM8[a + 0x00040000] = (byte) d;
  1958:            }
  1959:            if (CRTC.crtSimPlane3) {
  1960:              MainMemory.mmrM8[a + 0x00060000] = (byte) d;
  1961:            }
  1962:          }
  1963:        } else if (CRTC.crtBitMask) {  //同時アクセスなし,ビットマスクあり
  1964:          x = CRTC.crtR23Mask >> ((~a & 1) << 3);
  1965:          MainMemory.mmrM8[a] = (byte) (MainMemory.mmrM8[a] & x | d & ~x);
  1966:        } else {  //同時アクセスなし,ビットマスクなし
  1967:          MainMemory.mmrM8[a] = (byte) d;
  1968:        }
  1969:        //同時アクセスやビットマスクで1ピクセルも書き換えなくても更新することになる
  1970:        a = ((a & 0x0001ffff) >> 7) - CRTC.crtR11TxYCurr & 1020;
  1971:        CRTC.crtRasterStamp[a    ] = 0;
  1972:        CRTC.crtRasterStamp[a + 1] = 0;
  1973:        CRTC.crtRasterStamp[a + 2] = 0;
  1974:        CRTC.crtRasterStamp[a + 3] = 0;
  1975:      }  //mmdWb
  1976:     @Override protected void mmdWw (int a, int d) throws M68kException {
  1977:        XEiJ.mpuClockTime += XEiJ.busWaitTime.tvram;
  1978:        a &= XEiJ.BUS_MOTHER_MASK;
  1979:        int e;  //上位バイトのデータ
  1980:        int x;  //下位バイトのマスク
  1981:        int y;  //上位バイトのマスク
  1982:        if (CRTC.crtSimAccess) {  //同時アクセスあり
  1983:          a &= 0x00e1ffff;
  1984:          if (CRTC.crtBitMask) {  //同時アクセスあり,ビットマスクあり
  1985:            e = d >> 8 & ~(y = (x = CRTC.crtR23Mask) >> 8);
  1986:            d &= ~x;
  1987:            if (CRTC.crtSimPlane0) {
  1988:              MainMemory.mmrM8[a             ] = (byte) (MainMemory.mmrM8[a             ] & y | e);
  1989:              MainMemory.mmrM8[a + 0x00000001] = (byte) (MainMemory.mmrM8[a + 0x00000001] & x | d);
  1990:            }
  1991:            if (CRTC.crtSimPlane1) {
  1992:              MainMemory.mmrM8[a + 0x00020000] = (byte) (MainMemory.mmrM8[a + 0x00020000] & y | e);
  1993:              MainMemory.mmrM8[a + 0x00020001] = (byte) (MainMemory.mmrM8[a + 0x00020001] & x | d);
  1994:            }
  1995:            if (CRTC.crtSimPlane2) {
  1996:              MainMemory.mmrM8[a + 0x00040000] = (byte) (MainMemory.mmrM8[a + 0x00040000] & y | e);
  1997:              MainMemory.mmrM8[a + 0x00040001] = (byte) (MainMemory.mmrM8[a + 0x00040001] & x | d);
  1998:            }
  1999:            if (CRTC.crtSimPlane3) {
  2000:              MainMemory.mmrM8[a + 0x00060000] = (byte) (MainMemory.mmrM8[a + 0x00060000] & y | e);
  2001:              MainMemory.mmrM8[a + 0x00060001] = (byte) (MainMemory.mmrM8[a + 0x00060001] & x | d);
  2002:            }
  2003:          } else {  //同時アクセスあり,ビットマスクなし
  2004:            e = d >> 8;
  2005:            if (CRTC.crtSimPlane0) {
  2006:              MainMemory.mmrM8[a             ] = (byte) e;
  2007:              MainMemory.mmrM8[a + 0x00000001] = (byte) d;
  2008:            }
  2009:            if (CRTC.crtSimPlane1) {
  2010:              MainMemory.mmrM8[a + 0x00020000] = (byte) e;
  2011:              MainMemory.mmrM8[a + 0x00020001] = (byte) d;
  2012:            }
  2013:            if (CRTC.crtSimPlane2) {
  2014:              MainMemory.mmrM8[a + 0x00040000] = (byte) e;
  2015:              MainMemory.mmrM8[a + 0x00040001] = (byte) d;
  2016:            }
  2017:            if (CRTC.crtSimPlane3) {
  2018:              MainMemory.mmrM8[a + 0x00060000] = (byte) e;
  2019:              MainMemory.mmrM8[a + 0x00060001] = (byte) d;
  2020:            }
  2021:          }
  2022:        } else if (CRTC.crtBitMask) {  //同時アクセスなし,ビットマスクあり
  2023:          y = (x = CRTC.crtR23Mask) >> 8;
  2024:          MainMemory.mmrM8[a    ] = (byte) (MainMemory.mmrM8[a    ] & y | (d >> 8) & ~y);
  2025:          MainMemory.mmrM8[a + 1] = (byte) (MainMemory.mmrM8[a + 1] & x |  d       & ~x);
  2026:        } else {  //同時アクセスなし,ビットマスクなし
  2027:          if (MainMemory.MMR_USE_BYTE_BUFFER) {
  2028:            MainMemory.mmrBuffer.putShort (a, (short) d);
  2029:          } else {
  2030:            MainMemory.mmrM8[a    ] = (byte) (d >> 8);
  2031:            MainMemory.mmrM8[a + 1] = (byte)  d;
  2032:          }
  2033:        }
  2034:        //同時アクセスやビットマスクで1ピクセルも書き換えなくても更新することになる
  2035:        a = ((a & 0x0001ffff) >> 7) - CRTC.crtR11TxYCurr & 1020;
  2036:        CRTC.crtRasterStamp[a    ] = 0;
  2037:        CRTC.crtRasterStamp[a + 1] = 0;
  2038:        CRTC.crtRasterStamp[a + 2] = 0;
  2039:        CRTC.crtRasterStamp[a + 3] = 0;
  2040:      }  //mmdWw
  2041:     @Override protected void mmdWl (int a, int d) throws M68kException {
  2042:        XEiJ.mpuClockTime += XEiJ.busWaitTime.tvram * 2;
  2043:        a &= XEiJ.BUS_MOTHER_MASK;
  2044:        int e;  //下位ワードの上位バイトのデータ
  2045:        int f;  //上位ワードの下位バイトのデータ
  2046:        int g;  //上位ワードの上位バイトのデータ
  2047:        int x;  //下位バイトのマスク
  2048:        int y;  //上位バイトのマスク
  2049:        if (CRTC.crtSimAccess) {  //同時アクセスあり
  2050:          a &= 0x00e1ffff;
  2051:          if (CRTC.crtBitMask) {  //同時アクセスあり,ビットマスクあり
  2052:            g = d >> 24 & ~(y = (x = CRTC.crtR23Mask) >> 8);
  2053:            f = d >> 16 & ~x;
  2054:            e = d >>  8 & ~y;
  2055:            d &= ~x;
  2056:            if (CRTC.crtSimPlane0) {
  2057:              MainMemory.mmrM8[a             ] = (byte) (MainMemory.mmrM8[a             ] & y | g);
  2058:              MainMemory.mmrM8[a + 0x00000001] = (byte) (MainMemory.mmrM8[a + 0x00000001] & x | f);
  2059:              MainMemory.mmrM8[a + 0x00000002] = (byte) (MainMemory.mmrM8[a + 0x00000002] & y | e);
  2060:              MainMemory.mmrM8[a + 0x00000003] = (byte) (MainMemory.mmrM8[a + 0x00000003] & x | d);
  2061:            }
  2062:            if (CRTC.crtSimPlane1) {
  2063:              MainMemory.mmrM8[a + 0x00020000] = (byte) (MainMemory.mmrM8[a + 0x00020000] & y | g);
  2064:              MainMemory.mmrM8[a + 0x00020001] = (byte) (MainMemory.mmrM8[a + 0x00020001] & x | f);
  2065:              MainMemory.mmrM8[a + 0x00020002] = (byte) (MainMemory.mmrM8[a + 0x00020002] & y | e);
  2066:              MainMemory.mmrM8[a + 0x00020003] = (byte) (MainMemory.mmrM8[a + 0x00020003] & x | d);
  2067:            }
  2068:            if (CRTC.crtSimPlane2) {
  2069:              MainMemory.mmrM8[a + 0x00040000] = (byte) (MainMemory.mmrM8[a + 0x00040000] & y | g);
  2070:              MainMemory.mmrM8[a + 0x00040001] = (byte) (MainMemory.mmrM8[a + 0x00040001] & x | f);
  2071:              MainMemory.mmrM8[a + 0x00040002] = (byte) (MainMemory.mmrM8[a + 0x00040002] & y | e);
  2072:              MainMemory.mmrM8[a + 0x00040003] = (byte) (MainMemory.mmrM8[a + 0x00040003] & x | d);
  2073:            }
  2074:            if (CRTC.crtSimPlane3) {
  2075:              MainMemory.mmrM8[a + 0x00060000] = (byte) (MainMemory.mmrM8[a + 0x00060000] & y | g);
  2076:              MainMemory.mmrM8[a + 0x00060001] = (byte) (MainMemory.mmrM8[a + 0x00060001] & x | f);
  2077:              MainMemory.mmrM8[a + 0x00060002] = (byte) (MainMemory.mmrM8[a + 0x00060002] & y | e);
  2078:              MainMemory.mmrM8[a + 0x00060003] = (byte) (MainMemory.mmrM8[a + 0x00060003] & x | d);
  2079:            }
  2080:          } else {  //同時アクセスあり,ビットマスクなし
  2081:            g = d >> 24;
  2082:            f = d >> 16;
  2083:            e = d >>  8;
  2084:            if (CRTC.crtSimPlane0) {
  2085:              MainMemory.mmrM8[a             ] = (byte) g;
  2086:              MainMemory.mmrM8[a + 0x00000001] = (byte) f;
  2087:              MainMemory.mmrM8[a + 0x00000002] = (byte) e;
  2088:              MainMemory.mmrM8[a + 0x00000003] = (byte) d;
  2089:            }
  2090:            if (CRTC.crtSimPlane1) {
  2091:              MainMemory.mmrM8[a + 0x00020000] = (byte) g;
  2092:              MainMemory.mmrM8[a + 0x00020001] = (byte) f;
  2093:              MainMemory.mmrM8[a + 0x00020002] = (byte) e;
  2094:              MainMemory.mmrM8[a + 0x00020003] = (byte) d;
  2095:            }
  2096:            if (CRTC.crtSimPlane2) {
  2097:              MainMemory.mmrM8[a + 0x00040000] = (byte) g;
  2098:              MainMemory.mmrM8[a + 0x00040001] = (byte) f;
  2099:              MainMemory.mmrM8[a + 0x00040002] = (byte) e;
  2100:              MainMemory.mmrM8[a + 0x00040003] = (byte) d;
  2101:            }
  2102:            if (CRTC.crtSimPlane3) {
  2103:              MainMemory.mmrM8[a + 0x00060000] = (byte) g;
  2104:              MainMemory.mmrM8[a + 0x00060001] = (byte) f;
  2105:              MainMemory.mmrM8[a + 0x00060002] = (byte) e;
  2106:              MainMemory.mmrM8[a + 0x00060003] = (byte) d;
  2107:            }
  2108:          }
  2109:        } else if (CRTC.crtBitMask) {  //同時アクセスなし,ビットマスクあり
  2110:          y = (x = CRTC.crtR23Mask) >> 8;
  2111:          MainMemory.mmrM8[a    ] = (byte) (MainMemory.mmrM8[a    ] & y | (d >> 24) & ~y);
  2112:          MainMemory.mmrM8[a + 1] = (byte) (MainMemory.mmrM8[a + 1] & x | (d >> 16) & ~x);
  2113:          MainMemory.mmrM8[a + 2] = (byte) (MainMemory.mmrM8[a + 1] & y | (d >>  8) & ~y);
  2114:          MainMemory.mmrM8[a + 3] = (byte) (MainMemory.mmrM8[a + 1] & x |  d        & ~x);
  2115:        } else {  //同時アクセスなし,ビットマスクなし
  2116:          if (MainMemory.MMR_USE_BYTE_BUFFER) {
  2117:            MainMemory.mmrBuffer.putInt (a, d);
  2118:          } else {
  2119:            MainMemory.mmrM8[a    ] = (byte) (d >> 24);
  2120:            MainMemory.mmrM8[a + 1] = (byte) (d >> 16);
  2121:            MainMemory.mmrM8[a + 2] = (byte) (d >>  8);
  2122:            MainMemory.mmrM8[a + 3] = (byte)  d;
  2123:          }
  2124:        }
  2125:        //同時アクセスやビットマスクで1ピクセルも書き換えなくても更新することになる
  2126:        int b = ((a     & 0x0001ffff) >> 7) - CRTC.crtR11TxYCurr & 1020;
  2127:        CRTC.crtRasterStamp[b    ] = 0;
  2128:        CRTC.crtRasterStamp[b + 1] = 0;
  2129:        CRTC.crtRasterStamp[b + 2] = 0;
  2130:        CRTC.crtRasterStamp[b + 3] = 0;
  2131:        a = ((a + 2 & 0x0001ffff) >> 7) - CRTC.crtR11TxYCurr & 1020;
  2132:        if (a != b) {
  2133:          CRTC.crtRasterStamp[a    ] = 0;
  2134:          CRTC.crtRasterStamp[a + 1] = 0;
  2135:          CRTC.crtRasterStamp[a + 2] = 0;
  2136:          CRTC.crtRasterStamp[a + 3] = 0;
  2137:        }
  2138:      }  //mmdWl
  2139:   },  //MMD_TXT
  2140: 
  2141:   //--------------------------------------------------------------------------------
  2142:   //MMD_CRT CRTコントローラ
  2143:   //
  2144:   //  $00E80000~$00E8002F  ワードレジスタ
  2145:   //  $00E80030~$00E8003F  $0000
  2146:   //  $00E80040~$00E803FF  $00E80000~$00E8003Fの繰り返し
  2147:   //  $00E80400~$00E8047F  バスエラー
  2148:   //  $00E80480~$00E80481  ワードレジスタ
  2149:   //  $00E80482~$00E804FF  $00E80480~$00E80481の繰り返し
  2150:   //  $00E80500~$00E807FF  $00E80400~$00E804FFの繰り返し
  2151:   //  $00E80800~$00E81FFF  $00E80000~$00E807FFの繰り返し
  2152:   //
  2153:   MMD_CRT {
  2154:     @Override public String toString () {
  2155:       return Multilingual.mlnJapanese ? "CRT コントローラ" : "CRT Controller";
  2156:     }
  2157:     //リード
  2158:     @Override protected int mmdRbz (int a) throws M68kException {
  2159:        XEiJ.mpuClockTime += XEiJ.busWaitTime.crtc;
  2160:        int aa = a & 0x07ff;  //$00E80800~$00E81FFF→$00E80000~$00E807FF
  2161:        if (aa < 0x0400) {  //$00E80000~$00E803FF
  2162:          aa &= 0x003f;
  2163:          switch (aa) {
  2164:            //case 0x0001:  //R00の下位
  2165:            //  return CRTC.crtR00HFrontEndPort;
  2166:            //case 0x0003:  //R01の下位
  2167:            //  return CRTC.crtR01HSyncEndPort;
  2168:            //case 0x0005:  //R02の下位
  2169:            //  return CRTC.crtR02HBackEndPort;
  2170:            //case 0x0007:  //R03の下位
  2171:            //  return CRTC.crtR03HDispEndPort;
  2172:            //case 0x0008:  //R04の上位
  2173:            //  return CRTC.crtR04VFrontEndPort >> 8;
  2174:            //case 0x0009:  //R04の下位
  2175:            //  return CRTC.crtR04VFrontEndPort & 0xff;
  2176:            //case 0x000a:  //R05の上位
  2177:            //  return CRTC.crtR05VSyncEndPort >> 8;
  2178:            //case 0x000b:  //R05の下位
  2179:            //  return CRTC.crtR05VSyncEndPort & 0xff;
  2180:            //case 0x000c:  //R06の上位
  2181:            //  return CRTC.crtR06VBackEndPort >> 8;
  2182:            //case 0x000d:  //R06の下位
  2183:            //  return CRTC.crtR06VBackEndPort & 0xff;
  2184:            //case 0x000e:  //R07の上位
  2185:            //  return CRTC.crtR07VDispEndPort >> 8;
  2186:            //case 0x000f:  //R07の下位
  2187:            //  return CRTC.crtR07VDispEndPort & 0xff;
  2188:            //case 0x0011:  //R08の下位
  2189:            //  return CRTC.crtR08Adjust;
  2190:            //case 0x0012:  //R09の上位
  2191:            //  return CRTC.crtR09IRQRasterPort >> 8;
  2192:            //case 0x0013:  //R09の下位
  2193:            //  return CRTC.crtR09IRQRasterPort & 0xff;
  2194:            //case 0x0014:  //R10の上位
  2195:            //  return CRTC.crtR10TxXPort >> 8;
  2196:            //case 0x0015:  //R10の下位
  2197:            //  return CRTC.crtR10TxXPort & 0xff;
  2198:            //case 0x0016:  //R11の上位
  2199:            //  return CRTC.crtR11TxYCurr >> 8;
  2200:            //case 0x0017:  //R11の下位
  2201:            //  return CRTC.crtR11TxYCurr & 0xff;
  2202:            //case 0x0018:  //R12の上位
  2203:            //case 0x001c:  //R14の上位
  2204:            //case 0x0020:  //R16の上位
  2205:            //case 0x0024:  //R18の上位
  2206:            //  return CRTC.crtR12GrXPort[(aa - 0x0018) >> 2] >> 8;
  2207:            //case 0x0019:  //R12の下位
  2208:            //case 0x001d:  //R14の下位
  2209:            //case 0x0021:  //R16の下位
  2210:            //case 0x0025:  //R18の下位
  2211:            //  return CRTC.crtR12GrXPort[(aa - 0x0018) >> 2] & 0xff;
  2212:            //case 0x001a:  //R13の上位
  2213:            //case 0x001e:  //R15の上位
  2214:            //case 0x0022:  //R17の上位
  2215:            //case 0x0026:  //R19の上位
  2216:            //  return CRTC.crtR13GrYPort[(aa - 0x0018) >> 2] >> 8;
  2217:            //case 0x001b:  //R13の下位
  2218:            //case 0x001f:  //R15の下位
  2219:            //case 0x0023:  //R17の下位
  2220:            //case 0x0027:  //R19の下位
  2221:            //  return CRTC.crtR13GrYPort[(aa - 0x0018) >> 2] & 0xff;
  2222:          case 0x0028:  //R20の上位
  2223:            return (CRTC.crtTextStorage    << 4 |
  2224:                    CRTC.crtGraphicStorage << 3 |
  2225:                    CRTC.crtMemoryModePort);
  2226:          case 0x0029:  //R20の下位
  2227:            return (CRTC.crtHighResoPort << 4 |
  2228:                    CRTC.crtVResoPort    << 2 |
  2229:                    CRTC.crtHResoPort);
  2230:          case 0x002a:  //R21の上位
  2231:            return ((CRTC.crtBitMask   ? 0b00000010 : 0) |
  2232:                    (CRTC.crtSimAccess ? 0b00000001 : 0));
  2233:          case 0x002b:  //R21の下位
  2234:            return ((CRTC.crtSimPlane3 ? 0b10000000 : 0) |
  2235:                    (CRTC.crtSimPlane2 ? 0b01000000 : 0) |
  2236:                    (CRTC.crtSimPlane1 ? 0b00100000 : 0) |
  2237:                    (CRTC.crtSimPlane0 ? 0b00010000 : 0) |
  2238:                    (CRTC.crtCCPlane3  ? 0b00001000 : 0) |
  2239:                    (CRTC.crtCCPlane2  ? 0b00000100 : 0) |
  2240:                    (CRTC.crtCCPlane1  ? 0b00000010 : 0) |
  2241:                    (CRTC.crtCCPlane0  ? 0b00000001 : 0));
  2242:            //case 0x002c:  //R22の上位
  2243:            //  return CRTC.crtR22SrcBlock;
  2244:            //case 0x002d:  //R22の下位
  2245:            //  return CRTC.crtR22DstBlock;
  2246:            //case 0x002e:  //R23の上位
  2247:            //  return CRTC.crtR23Mask >> 8;
  2248:            //case 0x002f:  //R23の下位
  2249:            //  return CRTC.crtR23Mask & 0xff;
  2250:            //case 0x0000:  //R00の上位
  2251:            //case 0x0002:  //R01の上位
  2252:            //case 0x0004:  //R02の上位
  2253:            //case 0x0006:  //R03の上位
  2254:            //case 0x0010:  //R08の上位
  2255:            //case 0x0030:  //R24の上位
  2256:            //case 0x0031:  //R24の下位
  2257:            //case 0x0032:  //R25の上位
  2258:            //case 0x0033:  //R25の下位
  2259:            //case 0x0034:  //R26の上位
  2260:            //case 0x0035:  //R26の下位
  2261:            //case 0x0036:  //R27の上位
  2262:            //case 0x0037:  //R27の下位
  2263:            //case 0x0038:  //R28の上位
  2264:            //case 0x0039:  //R28の下位
  2265:            //case 0x003a:  //R29の上位
  2266:            //case 0x003b:  //R29の下位
  2267:            //case 0x003c:  //R30の上位
  2268:            //case 0x003d:  //R30の下位
  2269:            //case 0x003e:  //R31の上位
  2270:            //case 0x003f:  //R31の下位
  2271:          default:
  2272:            return 0x00;
  2273:            //return VideoController.vcnMode.ordinal () >> 8;
  2274:            //return VideoController.vcnMode.ordinal () & 0xff;
  2275:          }
  2276:        } else {  //$00E80400~$00E807FF
  2277:          aa &= 0xff;  //$00E80500~$00E807FF→$00E80400~$00E804FF
  2278:          if (aa < 0x80) {  //$00E80400~$00E8047F
  2279:            return super.mmdRbz (a);  //バスエラー
  2280:          } else {  //$00E80480~$00E804FF
  2281:            aa &= 0x01;  //$00E80482~$00E804FF→$00E80480~$00E80481
  2282:            if (aa == 0) {  //動作ポートの上位
  2283:              return 0;
  2284:            } else {  //動作ポートの下位
  2285:              return ((CRTC.crtRasterCopyOn ? 8 : 0) |  //ラスタコピー
  2286:                      (CRTC.crtClearFrames != 0 ? 2 : 0));  //高速クリア
  2287:            }
  2288:          }
  2289:        }
  2290:      }  //mmdRbz
  2291:     @Override protected int mmdRwz (int a) throws M68kException {
  2292:        XEiJ.mpuClockTime += XEiJ.busWaitTime.crtc;
  2293:        int aa = a & 0x07ff;  //$00E80800~$00E81FFF→$00E80000~$00E807FF
  2294:        if (aa < 0x0400) {  //$00E80000~$00E803FF
  2295:          aa &= 0x003f;
  2296:          switch (aa) {
  2297:            //case 0x0000:  //R00
  2298:            //  return CRTC.crtR00HFrontEndPort;
  2299:            //case 0x0002:  //R01
  2300:            //  return CRTC.crtR01HSyncEndPort;
  2301:            //case 0x0004:  //R02
  2302:            //  return CRTC.crtR02HBackEndPort;
  2303:            //case 0x0006:  //R03
  2304:            //  return CRTC.crtR03HDispEndPort;
  2305:            //case 0x0008:  //R04
  2306:            //  return CRTC.crtR04VFrontEndPort;
  2307:            //case 0x000a:  //R05
  2308:            //  return CRTC.crtR05VSyncEndPort;
  2309:            //case 0x000c:  //R06
  2310:            //  return CRTC.crtR06VBackEndPort;
  2311:            //case 0x000e:  //R07
  2312:            //  return CRTC.crtR07VDispEndPort;
  2313:            //case 0x0010:  //R08
  2314:            //  return CRTC.crtR08Adjust;
  2315:            //case 0x0012:  //R09
  2316:            //  return CRTC.crtR09IRQRasterPort;
  2317:            //case 0x0014:  //R10
  2318:            //  return CRTC.crtR10TxXPort;
  2319:            //case 0x0016:  //R11
  2320:            //  return CRTC.crtR11TxYPort;
  2321:            //case 0x0018:  //R12
  2322:            //case 0x001c:  //R14
  2323:            //case 0x0020:  //R16
  2324:            //case 0x0024:  //R18
  2325:            //  return CRTC.crtR12GrXPort[(aa - 0x0018) >> 2];
  2326:            //case 0x001a:  //R13
  2327:            //case 0x001e:  //R15
  2328:            //case 0x0022:  //R17
  2329:            //case 0x0026:  //R19
  2330:            //  return CRTC.crtR13GrYPort[(aa - 0x0018) >> 2];
  2331:          case 0x0028:  //R20
  2332:            return (CRTC.crtTextStorage    << 12 |
  2333:                    CRTC.crtGraphicStorage << 11 |
  2334:                    CRTC.crtMemoryModePort <<  8 |
  2335:                    CRTC.crtHighResoPort   <<  4 |
  2336:                    CRTC.crtVResoPort      <<  2 |
  2337:                    CRTC.crtHResoPort);
  2338:          case 0x002a:  //R21
  2339:            return ((CRTC.crtBitMask   ? 0b00000010_00000000 : 0) |
  2340:                    (CRTC.crtSimAccess ? 0b00000001_00000000 : 0) |
  2341:                    (CRTC.crtSimPlane3 ? 0b00000000_10000000 : 0) |
  2342:                    (CRTC.crtSimPlane2 ? 0b00000000_01000000 : 0) |
  2343:                    (CRTC.crtSimPlane1 ? 0b00000000_00100000 : 0) |
  2344:                    (CRTC.crtSimPlane0 ? 0b00000000_00010000 : 0) |
  2345:                    (CRTC.crtCCPlane3  ? 0b00000000_00001000 : 0) |
  2346:                    (CRTC.crtCCPlane2  ? 0b00000000_00000100 : 0) |
  2347:                    (CRTC.crtCCPlane1  ? 0b00000000_00000010 : 0) |
  2348:                    (CRTC.crtCCPlane0  ? 0b00000000_00000001 : 0));
  2349:            //case 0x002c:  //R22
  2350:            //  return CRTC.crtR22SrcBlock << 8 | CRTC.crtR22DstBlock;
  2351:            //case 0x002e:  //R23
  2352:            //  return CRTC.crtR23Mask;
  2353:            //case 0x0030:  //R24
  2354:            //case 0x0032:  //R25
  2355:            //case 0x0034:  //R26
  2356:            //case 0x0036:  //R27
  2357:            //case 0x0038:  //R28
  2358:            //case 0x003a:  //R29
  2359:            //case 0x003c:  //R30
  2360:            //case 0x003e:  //R31
  2361:          default:
  2362:            return 0x0000;
  2363:          }
  2364:        } else {  //$00E80400~$00E807FF
  2365:          aa &= 0xff;  //$00E80500~$00E807FF→$00E80400~$00E804FF
  2366:          if (aa < 0x80) {  //$00E80400~$00E8047F
  2367:            return super.mmdRbz (a);  //バスエラー
  2368:          } else {  //$00E80480~$00E804FF  動作ポート
  2369:            return ((CRTC.crtRasterCopyOn ? 8 : 0) |  //ラスタコピー
  2370:                    (CRTC.crtClearFrames != 0 ? 2 : 0));  //高速クリア
  2371:          }
  2372:        }
  2373:      }  //mmdRwz
  2374:     @Override protected int mmdRls (int a) throws M68kException {
  2375:        return mmdRwz (a) << 16 | mmdRwz (a + 2);
  2376:      }
  2377:     //ライト
  2378:     @Override protected void mmdWb (int a, int d) throws M68kException {
  2379:        XEiJ.mpuClockTime += XEiJ.busWaitTime.crtc;
  2380:        int aa = a & 0x07ff;  //$00E80800~$00E81FFF→$00E80000~$00E807FF
  2381:        if (aa < 0x0400) {  //$00E80000~$00E803FF
  2382:          aa &= 0x003f;
  2383:          switch (aa) {
  2384:          case 0x0001:  //R00の下位
  2385:            CRTC.crtR00HFrontEndPort = (d & 0xff) | (CRTC.crtR00Bit0Zero ? 0x00 : 0x01);
  2386:            {
  2387:              int curr = CRTC.crtR00HFrontEndMask == 0 ? CRTC.crtR00HFrontEndPort : CRTC.crtR00HFrontEndTest;
  2388:              if (CRTC.crtR00HFrontEndCurr != curr) {
  2389:                CRTC.crtR00HFrontEndCurr = curr;
  2390:                CRTC.crtRestart ();
  2391:              }
  2392:            }
  2393:          return;
  2394:          case 0x0003:  //R01の下位
  2395:            CRTC.crtR01HSyncEndPort = d & 0xff;
  2396:            {
  2397:              int curr = CRTC.crtR01HSyncEndMask == 0 ? CRTC.crtR01HSyncEndPort : CRTC.crtR01HSyncEndTest;
  2398:              if (CRTC.crtR01HSyncEndCurr != curr) {
  2399:                CRTC.crtR01HSyncEndCurr = curr;
  2400:                CRTC.crtRestart ();
  2401:              }
  2402:            }
  2403:            return;
  2404:          case 0x0005:  //R02の下位
  2405:            CRTC.crtR02HBackEndPort = d & 0xff;
  2406:            {
  2407:              int curr = CRTC.crtR02HBackEndMask == 0 ? CRTC.crtR02HBackEndPort : CRTC.crtR02HBackEndTest;
  2408:              if (CRTC.crtR02HBackEndCurr != curr) {
  2409:                CRTC.crtR02HBackEndCurr = curr;
  2410:                CRTC.crtRestart ();
  2411:              }
  2412:            }
  2413:            return;
  2414:          case 0x0007:  //R03の下位
  2415:            CRTC.crtR03HDispEndPort = d & 0xff;
  2416:            {
  2417:              int curr = CRTC.crtR03HDispEndMask == 0 ? CRTC.crtR03HDispEndPort : CRTC.crtR03HDispEndTest;
  2418:              if (CRTC.crtR03HDispEndCurr != curr) {
  2419:                CRTC.crtR03HDispEndCurr = curr;
  2420:                CRTC.crtRestart ();
  2421:              }
  2422:            }
  2423:            return;
  2424:          case 0x0008:  //R04の上位
  2425:            CRTC.crtR04VFrontEndPort = (d & (CRTC.crtVerticalMask >> 8)) << 8 | (CRTC.crtR04VFrontEndPort & 0xff);
  2426:            {
  2427:              int curr = CRTC.crtR04VFrontEndMask == 0 ? CRTC.crtR04VFrontEndPort : CRTC.crtR04VFrontEndTest;
  2428:              if (CRTC.crtR04VFrontEndCurr != curr) {
  2429:                CRTC.crtR04VFrontEndCurr = curr;
  2430:                if (CRTC.CRT_RASTER_HASH_ON) {
  2431:                  CRTC.crtUpdateRasterHash ();
  2432:                }
  2433:                CRTC.crtRestart ();
  2434:              }
  2435:            }
  2436:            return;
  2437:          case 0x0009:  //R04の下位
  2438:            CRTC.crtR04VFrontEndPort = (CRTC.crtR04VFrontEndPort & ~0xff) | (d & 0xff);
  2439:            {
  2440:              int curr = CRTC.crtR04VFrontEndMask == 0 ? CRTC.crtR04VFrontEndPort : CRTC.crtR04VFrontEndTest;
  2441:              if (CRTC.crtR04VFrontEndCurr != curr) {
  2442:                CRTC.crtR04VFrontEndCurr = curr;
  2443:                if (CRTC.CRT_RASTER_HASH_ON) {
  2444:                  CRTC.crtUpdateRasterHash ();
  2445:                }
  2446:                CRTC.crtRestart ();
  2447:              }
  2448:            }
  2449:            return;
  2450:          case 0x000a:  //R05の上位
  2451:            CRTC.crtR05VSyncEndPort = (d & (CRTC.crtVerticalMask >> 8)) << 8 | (CRTC.crtR05VSyncEndPort & 0xff);
  2452:            {
  2453:              int curr = CRTC.crtR05VSyncEndMask == 0 ? CRTC.crtR05VSyncEndPort : CRTC.crtR05VSyncEndTest;
  2454:              if (CRTC.crtR05VSyncEndCurr != curr) {
  2455:                CRTC.crtR05VSyncEndCurr = curr;
  2456:                CRTC.crtRestart ();
  2457:              }
  2458:            }
  2459:            return;
  2460:          case 0x000b:  //R05の下位
  2461:            CRTC.crtR05VSyncEndPort = (CRTC.crtR05VSyncEndPort & ~0xff) | (d & 0xff);
  2462:            {
  2463:              int curr = CRTC.crtR05VSyncEndMask == 0 ? CRTC.crtR05VSyncEndPort : CRTC.crtR05VSyncEndTest;
  2464:              if (CRTC.crtR05VSyncEndCurr != curr) {
  2465:                CRTC.crtR05VSyncEndCurr = curr;
  2466:                CRTC.crtRestart ();
  2467:              }
  2468:            }
  2469:            return;
  2470:          case 0x000c:  //R06の上位
  2471:            CRTC.crtR06VBackEndPort = (d & (CRTC.crtVerticalMask >> 8)) << 8 | (CRTC.crtR06VBackEndPort & 0xff);
  2472:            {
  2473:              int curr = CRTC.crtR06VBackEndMask == 0 ? CRTC.crtR06VBackEndPort : CRTC.crtR06VBackEndTest;
  2474:              if (CRTC.crtR06VBackEndCurr != curr) {
  2475:                CRTC.crtR06VBackEndCurr = curr;
  2476:                CRTC.crtVDispStart = curr + 1;
  2477:                if (CRTC.CRT_RASTER_HASH_ON) {
  2478:                  CRTC.crtUpdateRasterHash ();
  2479:                }
  2480:                CRTC.crtRestart ();
  2481:              }
  2482:            }
  2483:            return;
  2484:          case 0x000d:  //R06の下位
  2485:            CRTC.crtR06VBackEndPort = (CRTC.crtR06VBackEndPort & ~0xff) | (d & 0xff);
  2486:            {
  2487:              int curr = CRTC.crtR06VBackEndMask == 0 ? CRTC.crtR06VBackEndPort : CRTC.crtR06VBackEndTest;
  2488:              if (CRTC.crtR06VBackEndCurr != curr) {
  2489:                CRTC.crtR06VBackEndCurr = curr;
  2490:                CRTC.crtVDispStart = curr + 1;
  2491:                if (CRTC.CRT_RASTER_HASH_ON) {
  2492:                  CRTC.crtUpdateRasterHash ();
  2493:                }
  2494:                CRTC.crtRestart ();
  2495:              }
  2496:            }
  2497:            return;
  2498:          case 0x000e:  //R07の上位
  2499:            CRTC.crtR07VDispEndPort = (d & (CRTC.crtVerticalMask >> 8)) << 8 | (CRTC.crtR07VDispEndPort & 0xff);
  2500:            {
  2501:              int curr = CRTC.crtR07VDispEndMask == 0 ? CRTC.crtR07VDispEndPort : CRTC.crtR07VDispEndTest;
  2502:              if (CRTC.crtR07VDispEndCurr != curr) {
  2503:                CRTC.crtR07VDispEndCurr = curr;
  2504:                CRTC.crtVIdleStart = curr + 1;
  2505:                if (CRTC.CRT_RASTER_HASH_ON) {
  2506:                  CRTC.crtUpdateRasterHash ();
  2507:                }
  2508:                CRTC.crtRestart ();
  2509:              }
  2510:            }
  2511:            return;
  2512:          case 0x000f:  //R07の下位
  2513:            CRTC.crtR07VDispEndPort = (CRTC.crtR07VDispEndPort & ~0xff) | (d & 0xff);
  2514:            {
  2515:              int curr = CRTC.crtR07VDispEndMask == 0 ? CRTC.crtR07VDispEndPort : CRTC.crtR07VDispEndTest;
  2516:              if (CRTC.crtR07VDispEndCurr != curr) {
  2517:                CRTC.crtR07VDispEndCurr = curr;
  2518:                CRTC.crtVIdleStart = curr + 1;
  2519:                if (CRTC.CRT_RASTER_HASH_ON) {
  2520:                  CRTC.crtUpdateRasterHash ();
  2521:                }
  2522:                CRTC.crtRestart ();
  2523:              }
  2524:            }
  2525:            return;
  2526:          case 0x0011:  //R08の下位
  2527:            d &= 0xff;
  2528:            if (CRTC.crtR08Adjust != d) {
  2529:              CRTC.crtR08Adjust = d;
  2530:              CRTC.crtRestart ();
  2531:            }
  2532:            return;
  2533:          case 0x0012:  //R09の上位
  2534:            CRTC.crtR09IRQRasterPort = (d & (CRTC.crtVerticalMask >> 8)) << 8 | (CRTC.crtR09IRQRasterPort & 0xff);
  2535:            {
  2536:              int curr = CRTC.crtR09IRQRasterMask == 0 ? CRTC.crtR09IRQRasterPort : CRTC.crtR09IRQRasterTest;
  2537:              if (CRTC.crtR09IRQRasterCurr != curr) {
  2538:                CRTC.crtR09IRQRasterCurr = curr;
  2539:                if (CRTC.CRT_RASTER_HASH_ON) {
  2540:                  CRTC.crtUpdateRasterHash ();
  2541:                }
  2542:                if (RasterBreakPoint.RBP_ON) {
  2543:                  RasterBreakPoint.rbpCheckIRQ ();
  2544:                }
  2545:              }
  2546:            }
  2547:            return;
  2548:          case 0x0013:  //R09の下位
  2549:            CRTC.crtR09IRQRasterPort = (CRTC.crtR09IRQRasterPort & ~0xff) | (d & 0xff);
  2550:            {
  2551:              int curr = CRTC.crtR09IRQRasterMask == 0 ? CRTC.crtR09IRQRasterPort : CRTC.crtR09IRQRasterTest;
  2552:              if (CRTC.crtR09IRQRasterCurr != curr) {
  2553:                CRTC.crtR09IRQRasterCurr = curr;
  2554:                if (CRTC.CRT_RASTER_HASH_ON) {
  2555:                  CRTC.crtUpdateRasterHash ();
  2556:                }
  2557:                if (RasterBreakPoint.RBP_ON) {
  2558:                  RasterBreakPoint.rbpCheckIRQ ();
  2559:                }
  2560:              }
  2561:            }
  2562:            return;
  2563:          case 0x0014:  //R10の上位
  2564:            CRTC.crtR10TxXPort = (d & 0x03) << 8 | (CRTC.crtR10TxXPort & 0xff);
  2565:            {
  2566:              int curr = CRTC.crtR10TxXMask == 0 ? CRTC.crtR10TxXPort : CRTC.crtR10TxXTest;
  2567:              if (CRTC.crtR10TxXCurr != curr) {
  2568:                CRTC.crtR10TxXCurr = curr;
  2569:                CRTC.crtAllStamp += 2;
  2570:              }
  2571:            }
  2572:            return;
  2573:          case 0x0015:  //R10の下位
  2574:            CRTC.crtR10TxXPort = (CRTC.crtR10TxXPort & ~0xff) | (d & 0xff);
  2575:            {
  2576:              int curr = CRTC.crtR10TxXMask == 0 ? CRTC.crtR10TxXPort : CRTC.crtR10TxXTest;
  2577:              if (CRTC.crtR10TxXCurr != curr) {
  2578:                CRTC.crtR10TxXCurr = curr;
  2579:                CRTC.crtAllStamp += 2;
  2580:              }
  2581:            }
  2582:            return;
  2583:          case 0x0016:  //R11の上位
  2584:            CRTC.crtR11TxYPort = (d & 0x03) << 8 | (CRTC.crtR11TxYPort & 0xff);
  2585:            {
  2586:              int curr = CRTC.crtR11TxYMask == 0 ? CRTC.crtR11TxYPort : CRTC.crtR11TxYTest;
  2587:              if (CRTC.crtR11TxYCurr != curr) {
  2588:                CRTC.crtR11TxYCurr = curr;
  2589:                //CRTC.crtAllStamp += 2;  //ラッチするとき更新する
  2590:              }
  2591:            }
  2592:            return;
  2593:          case 0x0017:  //R11の下位
  2594:            CRTC.crtR11TxYPort = (CRTC.crtR11TxYPort & ~0xff) | (d & 0xff);
  2595:            {
  2596:              int curr = CRTC.crtR11TxYMask == 0 ? CRTC.crtR11TxYPort : CRTC.crtR11TxYTest;
  2597:              if (CRTC.crtR11TxYCurr != curr) {
  2598:                CRTC.crtR11TxYCurr = curr;
  2599:                //CRTC.crtAllStamp += 2;  //ラッチするとき更新する
  2600:              }
  2601:            }
  2602:            return;
  2603:          case 0x0018:  //R12の上位
  2604:          case 0x001c:  //R14の上位
  2605:          case 0x0020:  //R16の上位
  2606:          case 0x0024:  //R18の上位
  2607:            {
  2608:              int p = (aa - 0x0018) >> 2;  //0,1,2,3
  2609:              CRTC.crtR12GrXPort[p] = (d & (p == 0 ? 0x03 : 0x01)) << 8 | (CRTC.crtR12GrXPort[p] & 0xff);
  2610:              int curr = CRTC.crtR12GrXMask[p] == 0 ? CRTC.crtR12GrXPort[p] : CRTC.crtR12GrXTest[p];
  2611:              if (CRTC.crtR12GrXCurr[p] != curr) {
  2612:                CRTC.crtR12GrXCurr[p] = curr;
  2613:                CRTC.crtAllStamp += 2;
  2614:              }
  2615:            }
  2616:            return;
  2617:          case 0x0019:  //R12の下位
  2618:          case 0x001d:  //R14の下位
  2619:          case 0x0021:  //R16の下位
  2620:          case 0x0025:  //R18の下位
  2621:            {
  2622:              int p = (aa - 0x0018) >> 2;  //0,1,2,3
  2623:              CRTC.crtR12GrXPort[p] = (CRTC.crtR12GrXPort[p] & ~0xff) | (d & 0xff);
  2624:              int curr = CRTC.crtR12GrXMask[p] == 0 ? CRTC.crtR12GrXPort[p] : CRTC.crtR12GrXTest[p];
  2625:              if (CRTC.crtR12GrXCurr[p] != curr) {
  2626:                CRTC.crtR12GrXCurr[p] = curr;
  2627:                CRTC.crtAllStamp += 2;
  2628:              }
  2629:            }
  2630:            return;
  2631:          case 0x001a:  //R13の上位
  2632:          case 0x001e:  //R15の上位
  2633:          case 0x0022:  //R17の上位
  2634:          case 0x0026:  //R19の上位
  2635:            {
  2636:              int p = (aa - 0x0018) >> 2;  //0,1,2,3
  2637:              CRTC.crtR13GrYPort[p] = (d & (p == 0 ? 0x03 : 0x01)) << 8 | (CRTC.crtR13GrYPort[p] & 0xff);
  2638:              int curr = CRTC.crtR13GrYMask[p] == 0 ? CRTC.crtR13GrYPort[p] : CRTC.crtR13GrYTest[p];
  2639:              if (CRTC.crtR13GrYCurr[p] != curr) {
  2640:                CRTC.crtR13GrYCurr[p] = curr;
  2641:                //CRTC.crtAllStamp += 2;  //ラッチするとき更新する
  2642:              }
  2643:            }
  2644:            return;
  2645:          case 0x001b:  //R13の下位
  2646:          case 0x001f:  //R15の下位
  2647:          case 0x0023:  //R17の下位
  2648:          case 0x0027:  //R19の下位
  2649:            {
  2650:              int p = (aa - 0x0018) >> 2;  //0,1,2,3
  2651:              CRTC.crtR13GrYPort[p] = (CRTC.crtR13GrYPort[p] & ~0xff) | (d & 0xff);
  2652:              int curr = CRTC.crtR13GrYMask[p] == 0 ? CRTC.crtR13GrYPort[p] : CRTC.crtR13GrYTest[p];
  2653:              if (CRTC.crtR13GrYCurr[p] != curr) {
  2654:                CRTC.crtR13GrYCurr[p] = curr;
  2655:                //CRTC.crtAllStamp += 2;  //ラッチするとき更新する
  2656:              }
  2657:            }
  2658:            return;
  2659:          case 0x0028:  //R20の上位
  2660:            CRTC.crtSetMemoryMode (d >> 4, d >> 3, d);
  2661:            return;
  2662:          case 0x0029:  //R20の下位
  2663:            CRTC.crtHighResoPort = d >>> 4 & 1;
  2664:            CRTC.crtVResoPort    = d >>> 2 & 3;
  2665:            CRTC.crtHResoPort    = d       & 3;
  2666:            SpriteScreen.sprAccessible = SpriteScreen.spr768x512 || (d & 0b10010) != 0b10010;
  2667:            int highResoCurr = CRTC.crtHighResoMask == 0 ? CRTC.crtHighResoPort : CRTC.crtHighResoTest;
  2668:            int vResoCurr = CRTC.crtVResoMask == 0 ? CRTC.crtVResoPort : CRTC.crtVResoTest;
  2669:            int hResoCurr = CRTC.crtHResoMask == 0 ? CRTC.crtHResoPort : CRTC.crtHResoTest;
  2670:            if (CRTC.crtHighResoCurr != highResoCurr ||
  2671:                CRTC.crtVResoCurr != vResoCurr ||
  2672:                CRTC.crtHResoCurr != hResoCurr) {
  2673:              CRTC.crtHighResoCurr = highResoCurr;
  2674:              CRTC.crtVResoCurr = vResoCurr;
  2675:              CRTC.crtHResoCurr = hResoCurr;
  2676:              CRTC.crtRestart ();
  2677:            }
  2678:            return;
  2679:          case 0x002a:  //R21の上位
  2680:            CRTC.crtBitMask   = XEiJ.TEST_BIT_1_SHIFT ? d << 31 - 1 < 0 : (d & 2) != 0;
  2681:            CRTC.crtSimAccess = XEiJ.TEST_BIT_0_SHIFT ? d << 31 - 0 < 0 : (d & 1) != 0;
  2682:            return;
  2683:          case 0x002b:  //R21の下位
  2684:            CRTC.crtSimPlane3 = (byte) d < 0;  //(d & 128) != 0。d << 24 < 0
  2685:            CRTC.crtSimPlane2 = d << 25 < 0;  //(d & 64) != 0
  2686:            CRTC.crtSimPlane1 = d << 26 < 0;  //(d & 32) != 0
  2687:            CRTC.crtSimPlane0 = d << 27 < 0;  //(d & 16) != 0
  2688:            CRTC.crtCCPlane3  = XEiJ.TEST_BIT_3_SHIFT ? d << 31 - 3 < 0 : (d & 8) != 0;
  2689:            CRTC.crtCCPlane2  = XEiJ.TEST_BIT_2_SHIFT ? d << 31 - 2 < 0 : (d & 4) != 0;
  2690:            CRTC.crtCCPlane1  = XEiJ.TEST_BIT_1_SHIFT ? d << 31 - 1 < 0 : (d & 2) != 0;
  2691:            CRTC.crtCCPlane0  = XEiJ.TEST_BIT_0_SHIFT ? d << 31 - 0 < 0 : (d & 1) != 0;
  2692:            return;
  2693:          case 0x002c:  //R22の上位
  2694:            CRTC.crtR22SrcBlock = d & 0xff;
  2695:            return;
  2696:          case 0x002d:  //R22の下位
  2697:            CRTC.crtR22DstBlock = d & 0xff;
  2698:            return;
  2699:          case 0x002e:  //R23の上位
  2700:            CRTC.crtR23Mask = (d & 0xff) << 8 | (CRTC.crtR23Mask & 0xff);
  2701:            return;
  2702:          case 0x002f:  //R23の下位
  2703:            CRTC.crtR23Mask = (CRTC.crtR23Mask & ~0xff) | (d & 0xff);
  2704:            return;
  2705:            //case 0x0000:  //R00の上位
  2706:            //case 0x0002:  //R01の上位
  2707:            //case 0x0004:  //R02の上位
  2708:            //case 0x0006:  //R03の上位
  2709:            //case 0x0010:  //R08の上位
  2710:            //case 0x0030:  //R24の上位
  2711:            //case 0x0031:  //R24の下位
  2712:            //case 0x0032:  //R25の上位
  2713:            //case 0x0033:  //R25の下位
  2714:            //case 0x0034:  //R26の上位
  2715:            //case 0x0035:  //R26の下位
  2716:            //case 0x0036:  //R27の上位
  2717:            //case 0x0037:  //R27の下位
  2718:            //case 0x0038:  //R28の上位
  2719:            //case 0x0039:  //R28の下位
  2720:            //case 0x003a:  //R29の上位
  2721:            //case 0x003b:  //R29の下位
  2722:            //case 0x003c:  //R30の上位
  2723:            //case 0x003d:  //R30の下位
  2724:            //case 0x003e:  //R31の上位
  2725:            //case 0x003f:  //R31の下位
  2726:          default:
  2727:            return;
  2728:          }
  2729:        } else {  //$00E80400~$00E807FF
  2730:          aa &= 0xff;  //$00E80500~$00E807FF→$00E80400~$00E804FF
  2731:          if (aa < 0x80) {  //$00E80400~$00E8047F
  2732:            super.mmdWb (a, d);  //バスエラー
  2733:          } else {  //$00E80480~$00E804FF
  2734:            aa &= 0x01;  //$00E80482~$00E804FF→$00E80480~$00E80481
  2735:            if (aa == 0) {  //動作ポートの上位
  2736:              return;
  2737:            } else {  //動作ポートの下位
  2738:              boolean rasterCopyOn = (d & 8) != 0;
  2739:              if (CRTC.crtRasterCopyOn != rasterCopyOn) {
  2740:                CRTC.crtRasterCopyOn = rasterCopyOn;  //ラスタコピー
  2741:                if (CRTC.CRT_RASTER_HASH_ON) {
  2742:                  CRTC.crtUpdateRasterHash ();
  2743:                }
  2744:              }
  2745:              if (CRTC.crtClearFrames == 0) {
  2746:                CRTC.crtClearStandby = (d & 2) != 0;  //高速クリア
  2747:              }
  2748:              return;
  2749:            }
  2750:          }
  2751:        }
  2752:      }
  2753:     @Override protected void mmdWw (int a, int d) throws M68kException {
  2754:        XEiJ.mpuClockTime += XEiJ.busWaitTime.crtc;
  2755:        int aa = a & 0x07ff;  //$00E80800~$00E81FFF→$00E80000~$00E807FF
  2756:        if (aa < 0x0400) {  //$00E80000~$00E803FF
  2757:          aa &= 0x003f;
  2758:          switch (aa) {
  2759:          case 0x0000:  //R00
  2760:            CRTC.crtR00HFrontEndPort = (d & 0xff) | (CRTC.crtR00Bit0Zero ? 0x00 : 0x01);
  2761:            {
  2762:              int curr = CRTC.crtR00HFrontEndMask == 0 ? CRTC.crtR00HFrontEndPort : CRTC.crtR00HFrontEndTest;
  2763:              if (CRTC.crtR00HFrontEndCurr != curr) {
  2764:                CRTC.crtR00HFrontEndCurr = curr;
  2765:                CRTC.crtRestart ();
  2766:              }
  2767:            }
  2768:            return;
  2769:          case 0x0002:  //R01
  2770:            CRTC.crtR01HSyncEndPort = d & 0xff;
  2771:            {
  2772:              int curr = CRTC.crtR01HSyncEndMask == 0 ? CRTC.crtR01HSyncEndPort : CRTC.crtR01HSyncEndTest;
  2773:              if (CRTC.crtR01HSyncEndCurr != curr) {
  2774:                CRTC.crtR01HSyncEndCurr = curr;
  2775:                CRTC.crtRestart ();
  2776:              }
  2777:            }
  2778:            return;
  2779:          case 0x0004:  //R02
  2780:            CRTC.crtR02HBackEndPort = d & 0xff;
  2781:            {
  2782:              int curr = CRTC.crtR02HBackEndMask == 0 ? CRTC.crtR02HBackEndPort : CRTC.crtR02HBackEndTest;
  2783:              if (CRTC.crtR02HBackEndCurr != curr) {
  2784:                CRTC.crtR02HBackEndCurr = curr;
  2785:                CRTC.crtRestart ();
  2786:              }
  2787:            }
  2788:            return;
  2789:          case 0x0006:  //R03
  2790:            CRTC.crtR03HDispEndPort = d & 0xff;
  2791:            {
  2792:              int curr = CRTC.crtR03HDispEndMask == 0 ? CRTC.crtR03HDispEndPort : CRTC.crtR03HDispEndTest;
  2793:              if (CRTC.crtR03HDispEndCurr != curr) {
  2794:                CRTC.crtR03HDispEndCurr = curr;
  2795:                CRTC.crtRestart ();
  2796:              }
  2797:            }
  2798:            return;
  2799:          case 0x0008:  //R04
  2800:            CRTC.crtR04VFrontEndPort = d & CRTC.crtVerticalMask;
  2801:            {
  2802:              int curr = CRTC.crtR04VFrontEndMask == 0 ? CRTC.crtR04VFrontEndPort : CRTC.crtR04VFrontEndTest;
  2803:              if (CRTC.crtR04VFrontEndCurr != curr) {
  2804:                CRTC.crtR04VFrontEndCurr = curr;
  2805:                if (CRTC.CRT_RASTER_HASH_ON) {
  2806:                  CRTC.crtUpdateRasterHash ();
  2807:                }
  2808:                CRTC.crtRestart ();
  2809:              }
  2810:            }
  2811:            return;
  2812:          case 0x000a:  //R05
  2813:            CRTC.crtR05VSyncEndPort = d & CRTC.crtVerticalMask;
  2814:            {
  2815:              int curr = CRTC.crtR05VSyncEndMask == 0 ? CRTC.crtR05VSyncEndPort : CRTC.crtR05VSyncEndTest;
  2816:              if (CRTC.crtR05VSyncEndCurr != curr) {
  2817:                CRTC.crtR05VSyncEndCurr = curr;
  2818:                CRTC.crtRestart ();
  2819:              }
  2820:            }
  2821:            return;
  2822:          case 0x000c:  //R06
  2823:            CRTC.crtR06VBackEndPort = d & CRTC.crtVerticalMask;
  2824:            {
  2825:              int curr = CRTC.crtR06VBackEndMask == 0 ? CRTC.crtR06VBackEndPort : CRTC.crtR06VBackEndTest;
  2826:              if (CRTC.crtR06VBackEndCurr != curr) {
  2827:                CRTC.crtR06VBackEndCurr = curr;
  2828:                CRTC.crtVDispStart = curr + 1;
  2829:                if (CRTC.CRT_RASTER_HASH_ON) {
  2830:                  CRTC.crtUpdateRasterHash ();
  2831:                }
  2832:                CRTC.crtRestart ();
  2833:              }
  2834:            }
  2835:            return;
  2836:          case 0x000e:  //R07
  2837:            CRTC.crtR07VDispEndPort = d & CRTC.crtVerticalMask;
  2838:            {
  2839:              int curr = CRTC.crtR07VDispEndMask == 0 ? CRTC.crtR07VDispEndPort : CRTC.crtR07VDispEndTest;
  2840:              if (CRTC.crtR07VDispEndCurr != curr) {
  2841:                CRTC.crtR07VDispEndCurr = curr;
  2842:                CRTC.crtVIdleStart = curr + 1;
  2843:                if (CRTC.CRT_RASTER_HASH_ON) {
  2844:                  CRTC.crtUpdateRasterHash ();
  2845:                }
  2846:                CRTC.crtRestart ();
  2847:              }
  2848:            }
  2849:            return;
  2850:          case 0x0010:  //R08
  2851:            d &= 0xff;
  2852:            if (CRTC.crtR08Adjust != d) {
  2853:              CRTC.crtR08Adjust = d;
  2854:              CRTC.crtRestart ();
  2855:            }
  2856:            return;
  2857:          case 0x0012:  //R09
  2858:            CRTC.crtR09IRQRasterPort = d & CRTC.crtVerticalMask;
  2859:            {
  2860:              int curr = CRTC.crtR09IRQRasterMask == 0 ? CRTC.crtR09IRQRasterPort : CRTC.crtR09IRQRasterTest;
  2861:              if (CRTC.crtR09IRQRasterCurr != curr) {
  2862:                CRTC.crtR09IRQRasterCurr = curr;
  2863:                if (CRTC.CRT_RASTER_HASH_ON) {
  2864:                  CRTC.crtUpdateRasterHash ();
  2865:                }
  2866:                if (RasterBreakPoint.RBP_ON) {
  2867:                  RasterBreakPoint.rbpCheckIRQ ();
  2868:                }
  2869:              }
  2870:            }
  2871:            return;
  2872:          case 0x0014:  //R10
  2873:            CRTC.crtR10TxXPort = d & 0x03ff;
  2874:            {
  2875:              int curr = CRTC.crtR10TxXMask == 0 ? CRTC.crtR10TxXPort : CRTC.crtR10TxXTest;
  2876:              if (CRTC.crtR10TxXCurr != curr) {
  2877:                CRTC.crtR10TxXCurr = curr;
  2878:                CRTC.crtAllStamp += 2;
  2879:              }
  2880:            }
  2881:            return;
  2882:          case 0x0016:  //R11
  2883:            CRTC.crtR11TxYPort = d & 0x03ff;
  2884:            {
  2885:              int curr = CRTC.crtR11TxYMask == 0 ? CRTC.crtR11TxYPort : CRTC.crtR11TxYTest;
  2886:              if (CRTC.crtR11TxYCurr != curr) {
  2887:                CRTC.crtR11TxYCurr = curr;
  2888:                //CRTC.crtAllStamp += 2;  //ラッチするとき更新する
  2889:              }
  2890:            }
  2891:            return;
  2892:          case 0x0018:  //R12
  2893:          case 0x001c:  //R14
  2894:          case 0x0020:  //R16
  2895:          case 0x0024:  //R18
  2896:            {
  2897:              int p = (aa - 0x0018) >> 2;  //0,1,2,3
  2898:              CRTC.crtR12GrXPort[p] = d & (p == 0 ? 0x03ff : 0x01ff);
  2899:              int curr = CRTC.crtR12GrXMask[p] == 0 ? CRTC.crtR12GrXPort[p] : CRTC.crtR12GrXTest[p];
  2900:              if (CRTC.crtR12GrXCurr[p] != curr) {
  2901:                CRTC.crtR12GrXCurr[p] = curr;
  2902:                CRTC.crtAllStamp += 2;
  2903:              }
  2904:            }
  2905:            return;
  2906:          case 0x001a:  //R13
  2907:          case 0x001e:  //R15
  2908:          case 0x0022:  //R17
  2909:          case 0x0026:  //R19
  2910:            {
  2911:              int p = (aa - 0x0018) >> 2;  //0,1,2,3
  2912:              CRTC.crtR13GrYPort[p] = d & (p == 0 ? 0x03ff : 0x01ff);
  2913:              int curr = CRTC.crtR13GrYMask[p] == 0 ? CRTC.crtR13GrYPort[p] : CRTC.crtR13GrYTest[p];
  2914:              if (CRTC.crtR13GrYCurr[p] != curr) {
  2915:                CRTC.crtR13GrYCurr[p] = curr;
  2916:                //CRTC.crtAllStamp += 2;  //ラッチするとき更新する
  2917:              }
  2918:            }
  2919:            return;
  2920:          case 0x0028:  //R20
  2921:            CRTC.crtSetMemoryMode (d >> 12, d >> 11, d >> 8);
  2922:            CRTC.crtHighResoPort = d >>> 4 & 1;
  2923:            CRTC.crtVResoPort    = d >>> 2 & 3;
  2924:            CRTC.crtHResoPort    = d       & 3;
  2925:            SpriteScreen.sprAccessible = SpriteScreen.spr768x512 || (d & 0b10010) != 0b10010;
  2926:            int highResoCurr = CRTC.crtHighResoMask == 0 ? CRTC.crtHighResoPort : CRTC.crtHighResoTest;
  2927:            int vResoCurr = CRTC.crtVResoMask == 0 ? CRTC.crtVResoPort : CRTC.crtVResoTest;
  2928:            int hResoCurr = CRTC.crtHResoMask == 0 ? CRTC.crtHResoPort : CRTC.crtHResoTest;
  2929:            if (CRTC.crtHighResoCurr != highResoCurr ||
  2930:                CRTC.crtVResoCurr != vResoCurr ||
  2931:                CRTC.crtHResoCurr != hResoCurr) {
  2932:              CRTC.crtHighResoCurr = highResoCurr;
  2933:              CRTC.crtVResoCurr = vResoCurr;
  2934:              CRTC.crtHResoCurr = hResoCurr;
  2935:              CRTC.crtRestart ();
  2936:            }
  2937:            return;
  2938:          case 0x002a:  //R21
  2939:            CRTC.crtBitMask   = d << 22 < 0;  //(d & 512) != 0
  2940:            CRTC.crtSimAccess = d << 23 < 0;  //(d & 256) != 0
  2941:            CRTC.crtSimPlane3 = (byte) d < 0;  //(d & 128) != 0。d << 24 < 0
  2942:            CRTC.crtSimPlane2 = d << 25 < 0;  //(d & 64) != 0
  2943:            CRTC.crtSimPlane1 = d << 26 < 0;  //(d & 32) != 0
  2944:            CRTC.crtSimPlane0 = d << 27 < 0;  //(d & 16) != 0
  2945:            CRTC.crtCCPlane3  = XEiJ.TEST_BIT_3_SHIFT ? d << 31 - 3 < 0 : (d & 8) != 0;
  2946:            CRTC.crtCCPlane2  = XEiJ.TEST_BIT_2_SHIFT ? d << 31 - 2 < 0 : (d & 4) != 0;
  2947:            CRTC.crtCCPlane1  = XEiJ.TEST_BIT_1_SHIFT ? d << 31 - 1 < 0 : (d & 2) != 0;
  2948:            CRTC.crtCCPlane0  = XEiJ.TEST_BIT_0_SHIFT ? d << 31 - 0 < 0 : (d & 1) != 0;
  2949:            return;
  2950:          case 0x002c:  //R22
  2951:            CRTC.crtR22SrcBlock = d >> 8 & 0xff;
  2952:            CRTC.crtR22DstBlock = d      & 0xff;
  2953:            return;
  2954:          case 0x002e:  //R23
  2955:            CRTC.crtR23Mask = (char) d;
  2956:            return;
  2957:            //case 0x0030:  //R24
  2958:            //case 0x0032:  //R25
  2959:            //case 0x0034:  //R26
  2960:            //case 0x0036:  //R27
  2961:            //case 0x0038:  //R28
  2962:            //case 0x003a:  //R29
  2963:            //case 0x003c:  //R30
  2964:            //case 0x003e:  //R31
  2965:          default:
  2966:            return;
  2967:          }
  2968:        } else {  //$00E80400~$00E807FF
  2969:          aa &= 0xff;  //$00E80500~$00E807FF→$00E80400~$00E804FF
  2970:          if (aa < 0x80) {  //$00E80400~$00E8047F
  2971:            super.mmdWw (a, d);  //バスエラー
  2972:          } else {  //$00E80480~$00E804FF  動作ポート
  2973:            boolean rasterCopyOn = (d & 8) != 0;
  2974:            if (CRTC.crtRasterCopyOn != rasterCopyOn) {
  2975:              CRTC.crtRasterCopyOn = rasterCopyOn;  //ラスタコピー
  2976:              if (CRTC.CRT_RASTER_HASH_ON) {
  2977:                CRTC.crtUpdateRasterHash ();
  2978:              }
  2979:            }
  2980:            if (CRTC.crtClearFrames == 0) {
  2981:              CRTC.crtClearStandby = (d & 2) != 0;  //高速クリア
  2982:            }
  2983:            return;
  2984:          }
  2985:        }
  2986:      }
  2987:     @Override protected void mmdWl (int a, int d) throws M68kException {
  2988:        mmdWw (a    , d >> 16);
  2989:        mmdWw (a + 2, d      );
  2990:      }
  2991:   },  //MMD_CRT
  2992: 
  2993:   //--------------------------------------------------------------------------------
  2994:   //MMD_VCN ビデオコントローラ
  2995:   //
  2996:   //  $00E82000~$00E821FF  ワードレジスタ
  2997:   //  $00E82200~$00E823FF  ワードレジスタ
  2998:   //  $00E82400~$00E82401  ワードレジスタ
  2999:   //  $00E82402~$00E824FF  $00E82400~$00E82401の繰り返し
  3000:   //  $00E82500~$00E82501  ワードレジスタ
  3001:   //  $00E82502~$00E825FF  $00E82500~$00E82501の繰り返し
  3002:   //  $00E82600~$00E82601  ワードレジスタ
  3003:   //  $00E82602~$00E826FF  $00E82600~$00E82601の繰り返し
  3004:   //  $00E82700~$00E82FFF  $0000
  3005:   //  $00E83000~$00E83FFF  $00E82000~$00E82FFFの繰り返し
  3006:   //
  3007:   MMD_VCN {
  3008:     @Override public String toString () {
  3009:       return Multilingual.mlnJapanese ? "ビデオコントローラ" : "Video Controller";
  3010:     }
  3011:     //リード
  3012:     @Override protected int mmdRbz (int a) throws M68kException {
  3013:        int aa = a & 0x1fff;  //$00E83000~$00E83FFF→$00E82000~$00E82FFF
  3014:        if (aa < 0x0400) {  //パレット
  3015:          XEiJ.mpuClockTime += XEiJ.busWaitTime.palet;
  3016:          int d = (aa < 0x0200 ? VideoController.vcnPal16G8Port[aa >> 1] :  //$00E82000~$00E821FF  グラフィック
  3017:                   VideoController.vcnPal16TSPort[(aa - 0x0200) >> 1]);  //$00E82200~$00E823FF  テキストスプライト
  3018:          return (aa & 1) == 0 ? d >> 8 : d & 0xff;
  3019:        } else {  //レジスタ
  3020:          XEiJ.mpuClockTime += XEiJ.busWaitTime.vicon;
  3021:          int d = (aa < 0x0500 ? VideoController.vcnReg1Port :  //$00E82400~$00E824FF
  3022:                   aa < 0x0600 ? VideoController.vcnReg2Port :  //$00E82500~$00E825FF
  3023:                   aa < 0x0700 ? VideoController.vcnReg3Port :  //$00E82600~$00E826FF
  3024:                   0);  //$00E82700~$00E82FFF
  3025:          return (aa & 1) == 0 ? d >> 8 : d & 0xff;
  3026:        }
  3027:      }
  3028:     @Override protected int mmdRwz (int a) throws M68kException {
  3029:        int aa = a & 0x1fff;  //$00E83000~$00E83FFF→$00E82000~$00E82FFF
  3030:        if (aa < 0x0400) {  //パレット
  3031:          XEiJ.mpuClockTime += XEiJ.busWaitTime.palet;
  3032:          return (aa < 0x0200 ? VideoController.vcnPal16G8Port[aa >> 1] :  //$00E82000~$00E821FF  グラフィックスパレット
  3033:                  VideoController.vcnPal16TSPort[(aa - 0x0200) >> 1]);  //$00E82200~$00E823FF  テキストスプライトパレット
  3034:        } else {  //レジスタ
  3035:          XEiJ.mpuClockTime += XEiJ.busWaitTime.vicon;
  3036:          return (aa < 0x0500 ? VideoController.vcnReg1Port :  //$00E82400~$00E824FF
  3037:                  aa < 0x0600 ? VideoController.vcnReg2Port :  //$00E82500~$00E825FF
  3038:                  aa < 0x0700 ? VideoController.vcnReg3Port :  //$00E82600~$00E826FF
  3039:                  0);  //$00E82700~$00E82FFF
  3040:        }
  3041:      }
  3042:     @Override protected int mmdRls (int a) throws M68kException {
  3043:        return mmdRwz (a) << 16 | mmdRwz (a + 2);
  3044:      }
  3045:     //ライト
  3046:     @Override protected void mmdWb (int a, int d) throws M68kException {
  3047:        int aa = a & 0x1fff;  //$00E83000~$00E83FFF→$00E82000~$00E82FFF
  3048:        if (aa < 0x0200) {  //$00E82000~$00E821FF  グラフィックスパレット
  3049:          XEiJ.mpuClockTime += XEiJ.busWaitTime.palet;
  3050:          if (FlashingLights.FLR_ON) {
  3051:            FlashingLights.flrWriteByteG8 (a, d);
  3052:          } else {
  3053:            d &= 0xff;
  3054:            int n = aa >> 1;
  3055:            if ((aa & 1) == 0) {  //a=0,2,4,6,8,10,12,14
  3056:              int t = VideoController.vcnPal16G8Port[n] = d << 8 | (VideoController.vcnPal16G8Port[n] & 0xff);
  3057:              VideoController.vcnPal32G8[n] = VideoController.vcnPalTbl[t];
  3058:              if ((n & 1) == 0) {  //a=0,4,8,12 n=0,2,4,6
  3059:                VideoController.vcnPal8G16LPort[n] = d;
  3060:              } else {  //a=2,6,10,14 n-1=0,2,4,6
  3061:                VideoController.vcnPal8G16HPort[n - 1] = d << 8;
  3062:              }
  3063:            } else {  //a=1,3,5,7,9,11,13,15
  3064:              int t = VideoController.vcnPal16G8Port[n] = (VideoController.vcnPal16G8Port[n] & ~0xff) | d;
  3065:              VideoController.vcnPal32G8[n] = VideoController.vcnPalTbl[t];
  3066:              if ((n & 1) == 0) {  //a=1,5,9,13 n+1=1,3,5,7
  3067:                VideoController.vcnPal8G16LPort[n + 1] = d;
  3068:              } else {  //a=3,7,11,15 n=1,3,5,7
  3069:                VideoController.vcnPal8G16HPort[n] = d << 8;
  3070:              }
  3071:            }
  3072:            if ((VideoController.vcnReg3Curr & 0x001f) != 0) {  //グラフィックス画面が表示されている
  3073:              CRTC.crtAllStamp += 2;
  3074:            }
  3075:          }
  3076:        } else if (aa < 0x0400) {  //$00E82200~$00E823FF  テキストスプライトパレット
  3077:          XEiJ.mpuClockTime += XEiJ.busWaitTime.palet;
  3078:          if (FlashingLights.FLR_ON) {
  3079:            FlashingLights.flrWriteByteTS (a, d);
  3080:          } else {
  3081:            d &= 0xff;
  3082:            int n = (aa - 0x0200) >> 1;
  3083:            d = ((aa & 1) == 0 ?
  3084:                 d << 8 | (VideoController.vcnPal16TSPort[n] & 0xff) :
  3085:                 (VideoController.vcnPal16TSPort[n] & ~0xff) | d);
  3086:            VideoController.vcnPal16TSPort[n] = d;
  3087:            if (!ScreenModeTest.smtPatternTestOn) {
  3088:              VideoController.vcnPal32TS[n] = VideoController.vcnPalTbl[d];
  3089:              if ((VideoController.vcnReg3Curr << 31 - 6 < 0 && SpriteScreen.sprReg4BgCtrlCurr << 31 - 9 < 0) ||  //スプライト画面が表示されている
  3090:                  (VideoController.vcnReg3Curr << 31 - 5 < 0 && n < 16)) {  //テキスト画面が表示されていてテキストパレットが操作された
  3091:                CRTC.crtAllStamp += 2;
  3092:              }
  3093:            }
  3094:          }
  3095:        } else if (aa < 0x0500) {  //$00E82400~$00E824FF
  3096:          XEiJ.mpuClockTime += XEiJ.busWaitTime.vicon;
  3097:          d = (aa & 1) == 0 ? 0x00 : d & 0x07;
  3098:          if (VideoController.vcnReg1Port != d) {
  3099:            VideoController.vcnReg1Port = d;
  3100:            VideoController.vcnReg1Curr = ((VideoController.vcnReg1Port & ~VideoController.vcnReg1Mask) |
  3101:                                           (VideoController.vcnReg1Test & VideoController.vcnReg1Mask));
  3102:            VideoController.vcnUpdateMode ();
  3103:          }
  3104:        } else if (aa < 0x0600) {  //$00E82500~$00E825FF
  3105:          XEiJ.mpuClockTime += XEiJ.busWaitTime.vicon;
  3106:          d = ((aa & 1) == 0 ?
  3107:               (d & 0x3f) << 8 | (VideoController.vcnReg2Port & 0xff) :
  3108:               (VideoController.vcnReg2Port & ~0xff) | (d & 0xff));
  3109:          if (VideoController.vcnReg2Port != d) {
  3110:            VideoController.vcnReg2Port = d;
  3111:            VideoController.vcnReg2Curr = ((VideoController.vcnReg2Port & ~VideoController.vcnReg2Mask) |
  3112:                                           (VideoController.vcnReg2Test & VideoController.vcnReg2Mask));
  3113:            VideoController.vcnUpdateMode ();
  3114:          }
  3115:        } else if (aa < 0x0700) {  //$00E82600~$00E826FF
  3116:          XEiJ.mpuClockTime += XEiJ.busWaitTime.vicon;
  3117:          d = ((aa & 1) == 0 ?
  3118:               (d & 0xff) << 8 | (VideoController.vcnReg3Port & 0xff) :
  3119:               (VideoController.vcnReg3Port & ~0xff) | (d & 0xff));
  3120:          if (VideoController.vcnReg3Port != d) {
  3121:            VideoController.vcnReg3Port = d;
  3122:            VideoController.vcnReg3Curr = ((VideoController.vcnReg3Port & ~VideoController.vcnReg3Mask) |
  3123:                                           (VideoController.vcnReg3Test & VideoController.vcnReg3Mask));
  3124:            VideoController.vcnUpdateMode ();
  3125:          }
  3126:        } else {  //$00E82700~$00E82FFF
  3127:          XEiJ.mpuClockTime += XEiJ.busWaitTime.vicon;
  3128:        }
  3129:      }
  3130:     @Override protected void mmdWw (int a, int d) throws M68kException {
  3131:        int aa = a & 0x1fff;  //$00E83000~$00E83FFF→$00E82000~$00E82FFF
  3132:        if (aa < 0x0200) {  //$00E82000~$00E821FF  グラフィックスパレット
  3133:          XEiJ.mpuClockTime += XEiJ.busWaitTime.palet;
  3134:          if (FlashingLights.FLR_ON) {
  3135:            FlashingLights.flrWriteWordG8 (a, d);
  3136:          } else {
  3137:            int n = aa >> 1;  //a=0,2,4,6,8,10,12,14 n=0,1,2,3,4,5,6,7
  3138:            int t = VideoController.vcnPal16G8Port[n] = (char) d;
  3139:            VideoController.vcnPal32G8[n] = VideoController.vcnPalTbl[t];
  3140:            if ((n & 1) == 0) {  //a=0,4,8,12 n=0,2,4,6 n+1=1,3,5,7
  3141:              VideoController.vcnPal8G16LPort[n] = d >> 8 & 0xff;
  3142:              VideoController.vcnPal8G16LPort[n + 1] = d & 0xff;
  3143:            } else {  //a=2,4,6,8 n-1=0,2,4,6 n=1,3,5,7
  3144:              VideoController.vcnPal8G16HPort[n - 1] = d & 0xff00;
  3145:              VideoController.vcnPal8G16HPort[n] = (d & 0xff) << 8;
  3146:            }
  3147:            if ((VideoController.vcnReg3Curr & 0x001f) != 0) {  //グラフィックス画面が表示されている
  3148:              CRTC.crtAllStamp += 2;
  3149:            }
  3150:          }
  3151:        } else if (aa < 0x0400) {  //$00E82200~$00E823FF  テキストスプライトパレット
  3152:          XEiJ.mpuClockTime += XEiJ.busWaitTime.palet;
  3153:          if (FlashingLights.FLR_ON) {
  3154:            FlashingLights.flrWriteWordTS (a, d);
  3155:          } else {
  3156:            int n = (aa - 0x0200) >> 1;
  3157:            d = (char) d;
  3158:            VideoController.vcnPal16TSPort[n] = d;
  3159:            if (!ScreenModeTest.smtPatternTestOn) {
  3160:              VideoController.vcnPal32TS[n] = VideoController.vcnPalTbl[d];
  3161:              if ((VideoController.vcnReg3Curr << 31 - 6 < 0 && SpriteScreen.sprReg4BgCtrlCurr << 31 - 9 < 0) ||  //スプライト画面が表示されている
  3162:                  (VideoController.vcnReg3Curr << 31 - 5 < 0 && n < 16)) {  //テキスト画面が表示されていてテキストパレットが操作された
  3163:                CRTC.crtAllStamp += 2;
  3164:              }
  3165:            }
  3166:          }
  3167:        } else if (aa < 0x0500) {  //$00E82400~$00E824FF
  3168:          XEiJ.mpuClockTime += XEiJ.busWaitTime.vicon;
  3169:          d &= 0x0007;
  3170:          if (VideoController.vcnReg1Port != d) {
  3171:            VideoController.vcnReg1Port = d;
  3172:            VideoController.vcnReg1Curr = ((VideoController.vcnReg1Port & ~VideoController.vcnReg1Mask) |
  3173:                                           (VideoController.vcnReg1Test & VideoController.vcnReg1Mask));
  3174:            VideoController.vcnUpdateMode ();
  3175:          }
  3176:        } else if (aa < 0x0600) {  //$00E82500~$00E825FF
  3177:          XEiJ.mpuClockTime += XEiJ.busWaitTime.vicon;
  3178:          d &= 0x3fff;
  3179:          if (VideoController.vcnReg2Port != d) {
  3180:            VideoController.vcnReg2Port = d;
  3181:            VideoController.vcnReg2Curr = ((VideoController.vcnReg2Port & ~VideoController.vcnReg2Mask) |
  3182:                                           (VideoController.vcnReg2Test & VideoController.vcnReg2Mask));
  3183:            VideoController.vcnUpdateMode ();
  3184:          }
  3185:        } else if (aa < 0x0700) {  //$00E82600~$00E826FF
  3186:          XEiJ.mpuClockTime += XEiJ.busWaitTime.vicon;
  3187:          d &= 0xffff;
  3188:          if (VideoController.vcnReg3Port != d) {
  3189:            VideoController.vcnReg3Port = d;
  3190:            VideoController.vcnReg3Curr = ((VideoController.vcnReg3Port & ~VideoController.vcnReg3Mask) |
  3191:                                           (VideoController.vcnReg3Test & VideoController.vcnReg3Mask));
  3192:            VideoController.vcnUpdateMode ();
  3193:          }
  3194:        } else {  //$00E82700~$00E82FFF
  3195:          XEiJ.mpuClockTime += XEiJ.busWaitTime.vicon;
  3196:        }
  3197:      }
  3198:     @Override protected void mmdWl (int a, int d) throws M68kException {
  3199:        mmdWw (a    , d >> 16);
  3200:        mmdWw (a + 2, d      );
  3201:      }
  3202:   },  //MMD_VCN
  3203: 
  3204:   //--------------------------------------------------------------------------------
  3205:   //MMD_DMA DMAコントローラ
  3206:   //
  3207:   //  $00E84000~$00E8403F  ワードまたはロングワードレジスタ(CH0)
  3208:   //  $00E84040~$00E8407F  ワードまたはロングワードレジスタ(CH1)
  3209:   //  $00E84080~$00E840BF  ワードまたはロングワードレジスタ(CH2)
  3210:   //  $00E840C0~$00E840FF  ワードまたはロングワードレジスタ(CH4)
  3211:   //  $00E84100~$00E85FFF  $00E84000~$00E840FFの繰り返し
  3212:   //
  3213:   MMD_DMA {
  3214:     @Override public String toString () {
  3215:       return Multilingual.mlnJapanese ? "DMA コントローラ" : "DMA Controller";
  3216:     }
  3217:     //リード
  3218:     @Override protected int mmdRbz (int a) throws M68kException {
  3219:        XEiJ.mpuClockTime += XEiJ.busWaitTime.dmac;
  3220:        return HD63450.dmaReadByte (a);
  3221:      }
  3222:     @Override protected int mmdRwz (int a) throws M68kException {
  3223:        XEiJ.mpuClockTime += XEiJ.busWaitTime.dmac;
  3224:        return HD63450.dmaReadWord (a);
  3225:      }
  3226:     @Override protected int mmdRls (int a) throws M68kException {
  3227:        XEiJ.mpuClockTime += XEiJ.busWaitTime.dmac * 2;
  3228:        return HD63450.dmaReadLong (a);
  3229:      }
  3230:     //ライト
  3231:     @Override protected void mmdWb (int a, int d) throws M68kException {
  3232:        XEiJ.mpuClockTime += XEiJ.busWaitTime.dmac;
  3233:        HD63450.dmaWriteByte (a, d);
  3234:        return;
  3235:      }
  3236:     @Override protected void mmdWw (int a, int d) throws M68kException {
  3237:        XEiJ.mpuClockTime += XEiJ.busWaitTime.dmac;
  3238:        HD63450.dmaWriteWord (a, d);
  3239:        return;
  3240:      }
  3241:     @Override protected void mmdWl (int a, int d) throws M68kException {
  3242:        XEiJ.mpuClockTime += XEiJ.busWaitTime.dmac * 2;
  3243:        HD63450.dmaWriteLong (a, d);
  3244:        return;
  3245:      }
  3246:   },  //MMD_DMA
  3247: 
  3248:   //--------------------------------------------------------------------------------
  3249:   //MMD_SVS スーパーバイザ領域設定
  3250:   //
  3251:   //  $00E86000  バイトアクセスはバスエラー。ワードリードはバスエラー。ワードライトは$??xx
  3252:   //  $00E86001  バイトリードはバスエラー。バイトライトは$xx
  3253:   //  $00E86002~$00E87FFF  $00E86000~$00E86001の繰り返し
  3254:   //
  3255:   MMD_SVS {
  3256:     @Override public String toString () {
  3257:       return Multilingual.mlnJapanese ? "スーパーバイザ領域設定" : "Supervisor Area Setting";
  3258:     }
  3259:     //ライト
  3260:     @Override protected void mmdWb (int a, int d) throws M68kException {
  3261:        if ((a & 1) == 0) {  //偶数アドレスへのバイトライト
  3262:          super.mmdWb (a, d);  //バスエラー
  3263:        } else {  //奇数アドレスへのバイトライト
  3264:          XEiJ.mpuClockTime += XEiJ.busWaitTime.sysport;  //!!!
  3265:          MainMemory.mmrSetSupervisorArea (d);
  3266:        }
  3267:      }
  3268:     @Override protected void mmdWw (int a, int d) throws M68kException {
  3269:        mmdWb (a + 1, d);
  3270:      }
  3271:     @Override protected void mmdWl (int a, int d) throws M68kException {
  3272:        mmdWw (a, d >> 16);
  3273:        mmdWw (a + 2, d);
  3274:      }
  3275:   },  //MMD_SVS
  3276: 
  3277:   //--------------------------------------------------------------------------------
  3278:   //MMD_MFP MFP
  3279:   //
  3280:   //  $00E88000~$00E8803F(偶数)  バイトアクセスはバスエラー。ワードリードは$FFxx。ワードライトは$??xx
  3281:   //  $00E88000~$00E8803F(奇数)  バイトレジスタ
  3282:   //  $00E88040~$00E89FFF  $00E88000~$00E8803Fの繰り返し
  3283:   //
  3284:   MMD_MFP {
  3285:     @Override public String toString () {
  3286:       return Multilingual.mlnJapanese ? "MFP" : "MFP";  //Multi Function Peripheral
  3287:     }
  3288:     //ピーク
  3289:     @Override protected int mmdPbz (int a) {
  3290:       return MC68901.mfpPeekByte (a);
  3291:     }
  3292:     //リード
  3293:     @Override protected int mmdRbz (int a) throws M68kException {
  3294:        return MC68901.mfpReadByte (a);
  3295:      }
  3296:     @Override protected int mmdRwz (int a) throws M68kException {
  3297:        return 0xff00 | mmdRbz (a + 1);
  3298:      }
  3299:     @Override protected int mmdRls (int a) throws M68kException {
  3300:        return mmdRwz (a) << 16 | mmdRwz (a + 2);
  3301:      }
  3302:     //ライト
  3303:     @Override protected void mmdWb (int a, int d) throws M68kException {
  3304:        MC68901.mfpWriteByte (a, d);
  3305:      }
  3306:     @Override protected void mmdWw (int a, int d) throws M68kException {
  3307:        mmdWb (a + 1, d);
  3308:      }
  3309:     @Override protected void mmdWl (int a, int d) throws M68kException {
  3310:        mmdWw (a, d >> 16);
  3311:        mmdWw (a + 2, d);
  3312:      }
  3313:   },  //MMD_MFP
  3314: 
  3315:   //--------------------------------------------------------------------------------
  3316:   //MMD_RTC_FIRST RTC
  3317:   //
  3318:   //  $00E8A000~$00E8A01F(偶数)  バイトアクセスはバスエラー。ワードリードは$FFxx。ワードライトは$??xx
  3319:   //  $00E8A000~$00E8A01F(奇数)  バイトレジスタ
  3320:   //  $00E8A020~$00E8AFFF  $00E8A000~$00E8A01Fの繰り返し
  3321:   //
  3322:   MMD_RTC_FIRST {
  3323:     @Override public String toString () {
  3324:       return Multilingual.mlnJapanese ? "RTC" : "RTC";  //Real-Time Clock
  3325:     }
  3326:     //ピーク
  3327:     @Override protected byte mmdPbs (int a) {
  3328:       return (byte) RP5C15.rtcPeekByte (a);
  3329:     }
  3330:     @Override protected int mmdPbz (int a) {
  3331:       return RP5C15.rtcPeekByte (a);
  3332:     }
  3333:     @Override protected int mmdPws (int a) {
  3334:       return RP5C15.rtcPeekByte (a + 1);
  3335:     }
  3336:     @Override protected int mmdPwz (int a) {
  3337:       return RP5C15.rtcPeekByte (a + 1);
  3338:     }
  3339:     @Override protected int mmdPls (int a) {
  3340:       return (RP5C15.rtcPeekByte (a + 1) << 16 |
  3341:               RP5C15.rtcPeekByte (a + 3));
  3342:     }
  3343:     //リード
  3344:     @Override protected byte mmdRbs (int a) throws M68kException {
  3345:        if ((a & 1) == 0 &&  //偶数アドレスのバイトリード
  3346:            !XEiJ.currentIsSecond) {  //Xellent30の030モードではない
  3347:          return super.mmdRbs (a);  //バスエラー
  3348:        }
  3349:        XEiJ.mpuClockTime += XEiJ.busWaitTime.rtc;
  3350:        XEiJ.busSuper (MemoryMappedDevice.MMD_RTC_NEXT, 0x00e8a000, 0x00e8c000);  //RTC RTC
  3351:        RP5C15.rtcUpdate ();
  3352:        return (byte) RP5C15.rtcReadByte (a);
  3353:      }
  3354:     @Override protected int mmdRbz (int a) throws M68kException {
  3355:        if ((a & 1) == 0 &&  //偶数アドレスのバイトリード
  3356:            !XEiJ.currentIsSecond) {  //Xellent30の030モードではない
  3357:          return super.mmdRbz (a);  //バスエラー
  3358:        }
  3359:        XEiJ.mpuClockTime += XEiJ.busWaitTime.rtc;
  3360:        XEiJ.busSuper (MemoryMappedDevice.MMD_RTC_NEXT, 0x00e8a000, 0x00e8c000);  //RTC RTC
  3361:        RP5C15.rtcUpdate ();
  3362:        return RP5C15.rtcReadByte (a);
  3363:      }
  3364:     @Override protected int mmdRws (int a) throws M68kException {
  3365:        XEiJ.mpuClockTime += XEiJ.busWaitTime.rtc;
  3366:        XEiJ.busSuper (MemoryMappedDevice.MMD_RTC_NEXT, 0x00e8a000, 0x00e8c000);  //RTC RTC
  3367:        RP5C15.rtcUpdate ();
  3368:        return RP5C15.rtcReadByte (a + 1);
  3369:      }
  3370:     @Override protected int mmdRwz (int a) throws M68kException {
  3371:        XEiJ.mpuClockTime += XEiJ.busWaitTime.rtc;
  3372:        XEiJ.busSuper (MemoryMappedDevice.MMD_RTC_NEXT, 0x00e8a000, 0x00e8c000);  //RTC RTC
  3373:        RP5C15.rtcUpdate ();
  3374:        return RP5C15.rtcReadByte (a + 1);
  3375:      }
  3376:     @Override protected int mmdRls (int a) throws M68kException {
  3377:        XEiJ.mpuClockTime += XEiJ.busWaitTime.rtc * 2;
  3378:        XEiJ.busSuper (MemoryMappedDevice.MMD_RTC_NEXT, 0x00e8a000, 0x00e8c000);  //RTC RTC
  3379:        RP5C15.rtcUpdate ();
  3380:        return (RP5C15.rtcReadByte (a + 1) << 16 |
  3381:                RP5C15.rtcReadByte (a + 3));
  3382:      }
  3383:     //ライト
  3384:     @Override protected void mmdWb (int a, int d) throws M68kException {
  3385:        if ((a & 1) == 0 &&  //偶数アドレスのバイトライト
  3386:            !XEiJ.currentIsSecond) {  //Xellent30の030モードではない
  3387:          super.mmdWb (a, d);  //バスエラー
  3388:        }
  3389:        XEiJ.mpuClockTime += XEiJ.busWaitTime.rtc;
  3390:        XEiJ.busSuper (MemoryMappedDevice.MMD_RTC_NEXT, 0x00e8a000, 0x00e8c000);  //RTC RTC
  3391:        RP5C15.rtcUpdate ();
  3392:        RP5C15.rtcWriteByte (a, d);
  3393:      }
  3394:     @Override protected void mmdWw (int a, int d) throws M68kException {
  3395:        XEiJ.mpuClockTime += XEiJ.busWaitTime.rtc;
  3396:        XEiJ.busSuper (MemoryMappedDevice.MMD_RTC_NEXT, 0x00e8a000, 0x00e8c000);  //RTC RTC
  3397:        RP5C15.rtcUpdate ();
  3398:        RP5C15.rtcWriteByte (a + 1, d);
  3399:      }
  3400:     @Override protected void mmdWl (int a, int d) throws M68kException {
  3401:        XEiJ.mpuClockTime += XEiJ.busWaitTime.rtc * 2;
  3402:        XEiJ.busSuper (MemoryMappedDevice.MMD_RTC_NEXT, 0x00e8a000, 0x00e8c000);  //RTC RTC
  3403:        RP5C15.rtcUpdate ();
  3404:        RP5C15.rtcWriteByte (a + 1, d >> 16);
  3405:        RP5C15.rtcWriteByte (a + 3, d);
  3406:      }
  3407:   },  //MMD_RTC_FIRST
  3408: 
  3409:   //--------------------------------------------------------------------------------
  3410:   //MMD_RTC_NEXT RTC
  3411:   MMD_RTC_NEXT {
  3412:     @Override public String toString () {
  3413:       return Multilingual.mlnJapanese ? "RTC" : "RTC";  //Real-Time Clock
  3414:     }
  3415:     //ピーク
  3416:     @Override protected byte mmdPbs (int a) {
  3417:       return (byte) RP5C15.rtcPeekByte (a);
  3418:     }
  3419:     @Override protected int mmdPbz (int a) {
  3420:       return RP5C15.rtcPeekByte (a);
  3421:     }
  3422:     @Override protected int mmdPws (int a) {
  3423:       return RP5C15.rtcPeekByte (a + 1);
  3424:     }
  3425:     @Override protected int mmdPwz (int a) {
  3426:       return RP5C15.rtcPeekByte (a + 1);
  3427:     }
  3428:     @Override protected int mmdPls (int a) {
  3429:       return (RP5C15.rtcPeekByte (a + 1) << 16 |
  3430:               RP5C15.rtcPeekByte (a + 3));
  3431:     }
  3432:     //リード
  3433:     @Override protected byte mmdRbs (int a) throws M68kException {
  3434:        if ((a & 1) == 0 &&  //偶数アドレスのバイトリード
  3435:            !XEiJ.currentIsSecond) {  //Xellent30の030モードではない
  3436:          return super.mmdRbs (a);  //バスエラー
  3437:        }
  3438:        XEiJ.mpuClockTime += XEiJ.busWaitTime.rtc;
  3439:        return (byte) RP5C15.rtcReadByte (a);
  3440:      }
  3441:     @Override protected int mmdRbz (int a) throws M68kException {
  3442:        if ((a & 1) == 0 &&  //偶数アドレスのバイトリード
  3443:            !XEiJ.currentIsSecond) {  //Xellent30の030モードではない
  3444:          return super.mmdRbz (a);  //バスエラー
  3445:        }
  3446:        XEiJ.mpuClockTime += XEiJ.busWaitTime.rtc;
  3447:        return RP5C15.rtcReadByte (a);
  3448:      }
  3449:     @Override protected int mmdRws (int a) throws M68kException {
  3450:        XEiJ.mpuClockTime += XEiJ.busWaitTime.rtc;
  3451:        return RP5C15.rtcReadByte (a + 1);
  3452:      }
  3453:     @Override protected int mmdRwz (int a) throws M68kException {
  3454:        XEiJ.mpuClockTime += XEiJ.busWaitTime.rtc;
  3455:        return RP5C15.rtcReadByte (a + 1);
  3456:      }
  3457:     @Override protected int mmdRls (int a) throws M68kException {
  3458:        XEiJ.mpuClockTime += XEiJ.busWaitTime.rtc * 2;
  3459:        return (RP5C15.rtcReadByte (a + 1) << 16 |
  3460:                RP5C15.rtcReadByte (a + 3));
  3461:      }
  3462:     //ライト
  3463:     @Override protected void mmdWb (int a, int d) throws M68kException {
  3464:        if ((a & 1) == 0 &&  //偶数アドレスのバイトライト
  3465:            !XEiJ.currentIsSecond) {  //Xellent30の030モードではない
  3466:          super.mmdWb (a, d);  //バスエラー
  3467:        }
  3468:        XEiJ.mpuClockTime += XEiJ.busWaitTime.rtc;
  3469:        RP5C15.rtcWriteByte (a, d);
  3470:      }
  3471:     @Override protected void mmdWw (int a, int d) throws M68kException {
  3472:        XEiJ.mpuClockTime += XEiJ.busWaitTime.rtc;
  3473:        RP5C15.rtcWriteByte (a + 1, d);
  3474:      }
  3475:     @Override protected void mmdWl (int a, int d) throws M68kException {
  3476:        XEiJ.mpuClockTime += XEiJ.busWaitTime.rtc * 2;
  3477:        RP5C15.rtcWriteByte (a + 1, d >> 16);
  3478:        RP5C15.rtcWriteByte (a + 3, d);
  3479:      }
  3480:   },  //MMD_RTC_NEXT
  3481: 
  3482:   //--------------------------------------------------------------------------------
  3483:   //MMD_RTC_TEST RTC
  3484:   MMD_RTC_TEST {
  3485:     @Override public String toString () {
  3486:       return Multilingual.mlnJapanese ? "RTC テスト" : "RTC test";  //Real-Time Clock
  3487:     }
  3488:     //ピーク
  3489:     @Override protected byte mmdPbs (int a) {
  3490:       return (byte) RP5C15.rtcPeekByte (a);
  3491:     }
  3492:     @Override protected int mmdPbz (int a) {
  3493:       return RP5C15.rtcPeekByte (a);
  3494:     }
  3495:     @Override protected int mmdPws (int a) {
  3496:       return RP5C15.rtcPeekByte (a + 1);
  3497:     }
  3498:     @Override protected int mmdPwz (int a) {
  3499:       return RP5C15.rtcPeekByte (a + 1);
  3500:     }
  3501:     @Override protected int mmdPls (int a) {
  3502:       return (RP5C15.rtcPeekByte (a + 1) << 16 |
  3503:               RP5C15.rtcPeekByte (a + 3));
  3504:     }
  3505:     //リード
  3506:     @Override protected byte mmdRbs (int a) throws M68kException {
  3507:        if ((a & 1) == 0 &&  //偶数アドレスのバイトリード
  3508:            !XEiJ.currentIsSecond) {  //Xellent30の030モードではない
  3509:          return super.mmdRbs (a);  //バスエラー
  3510:        }
  3511:        XEiJ.mpuClockTime += XEiJ.busWaitTime.rtc;
  3512:        RP5C15.rtcTestUpdate ();
  3513:        return (byte) RP5C15.rtcReadByte (a);
  3514:      }
  3515:     @Override protected int mmdRbz (int a) throws M68kException {
  3516:        if ((a & 1) == 0 &&  //偶数アドレスのバイトリード
  3517:            !XEiJ.currentIsSecond) {  //Xellent30の030モードではない
  3518:          return super.mmdRbz (a);  //バスエラー
  3519:        }
  3520:        XEiJ.mpuClockTime += XEiJ.busWaitTime.rtc;
  3521:        RP5C15.rtcTestUpdate ();
  3522:        return RP5C15.rtcReadByte (a);
  3523:      }
  3524:     @Override protected int mmdRws (int a) throws M68kException {
  3525:        XEiJ.mpuClockTime += XEiJ.busWaitTime.rtc;
  3526:        RP5C15.rtcTestUpdate ();
  3527:        return RP5C15.rtcReadByte (a + 1);
  3528:      }
  3529:     @Override protected int mmdRwz (int a) throws M68kException {
  3530:        XEiJ.mpuClockTime += XEiJ.busWaitTime.rtc;
  3531:        RP5C15.rtcTestUpdate ();
  3532:        return RP5C15.rtcReadByte (a + 1);
  3533:      }
  3534:     @Override protected int mmdRls (int a) throws M68kException {
  3535:        XEiJ.mpuClockTime += XEiJ.busWaitTime.rtc * 2;
  3536:        RP5C15.rtcTestUpdate ();
  3537:        return (RP5C15.rtcReadByte (a + 1) << 16 |
  3538:                RP5C15.rtcReadByte (a + 3));
  3539:      }
  3540:     //ライト
  3541:     @Override protected void mmdWb (int a, int d) throws M68kException {
  3542:        if ((a & 1) == 0 &&  //偶数アドレスのバイトライト
  3543:            !XEiJ.currentIsSecond) {  //Xellent30の030モードではない
  3544:          super.mmdWb (a, d);  //バスエラー
  3545:        }
  3546:        XEiJ.mpuClockTime += XEiJ.busWaitTime.rtc;
  3547:        RP5C15.rtcTestUpdate ();
  3548:        RP5C15.rtcWriteByte (a, d);
  3549:      }
  3550:     @Override protected void mmdWw (int a, int d) throws M68kException {
  3551:        XEiJ.mpuClockTime += XEiJ.busWaitTime.rtc;
  3552:        RP5C15.rtcTestUpdate ();
  3553:        RP5C15.rtcWriteByte (a + 1, d);
  3554:      }
  3555:     @Override protected void mmdWl (int a, int d) throws M68kException {
  3556:        XEiJ.mpuClockTime += XEiJ.busWaitTime.rtc * 2;
  3557:        RP5C15.rtcTestUpdate ();
  3558:        RP5C15.rtcWriteByte (a + 1, d >> 16);
  3559:        RP5C15.rtcWriteByte (a + 3, d);
  3560:      }
  3561:   },  //MMD_RTC_TEST
  3562: 
  3563:   //--------------------------------------------------------------------------------
  3564:   //MMD_PRN プリンタポート
  3565:   //
  3566:   //  $00E8C000~$00E8C003(偶数)  バイトリードは$FF。バイトライトは$??。ワードリードは$FFxx。ワードライトは$??xx
  3567:   //  $00E8C000~$00E8C003(奇数)  バイトリードは$FF。バイトライトは$??
  3568:   //  $00E8C004~$00E8DFFF  $00E8C000~$00E8C003の繰り返し(?)
  3569:   //
  3570:   MMD_PRN {
  3571:     @Override public String toString () {
  3572:       return Multilingual.mlnJapanese ? "プリンタポート" : "Printer Port";
  3573:     }
  3574:     //リード
  3575:     @Override protected int mmdRbz (int a) throws M68kException {
  3576:        XEiJ.mpuClockTime += XEiJ.busWaitTime.prnport;
  3577:        a &= 3;
  3578:        return (a == (PrinterPort.PRN_DATA & 3) ? PrinterPort.prnReadData () :
  3579:                a == (PrinterPort.PRN_STROBE & 3) ? PrinterPort.prnReadStrobe () :
  3580:                0xff);
  3581:      }
  3582:     @Override protected int mmdRwz (int a) throws M68kException {
  3583:        return 0xff00 | mmdRbz (a + 1);
  3584:      }
  3585:     @Override protected int mmdRls (int a) throws M68kException {
  3586:        return 0xff00ff00 | mmdRbz (a + 1) << 16 | mmdRbz (a + 3);
  3587:      }
  3588:     //ライト
  3589:     @Override protected void mmdWb (int a, int d) throws M68kException {
  3590:        XEiJ.mpuClockTime += XEiJ.busWaitTime.prnport;
  3591:        a &= 3;
  3592:        if (a == (PrinterPort.PRN_DATA & 3)) {
  3593:          PrinterPort.prnWriteData (d);
  3594:        } else if (a == (PrinterPort.PRN_STROBE & 3)) {
  3595:          PrinterPort.prnWriteStrobe (d);
  3596:        }
  3597:      }
  3598:     @Override protected void mmdWw (int a, int d) throws M68kException {
  3599:        mmdWb (a + 1, d);
  3600:      }
  3601:     @Override protected void mmdWl (int a, int d) throws M68kException {
  3602:        mmdWb (a + 1, d >> 16);
  3603:        mmdWb (a + 3, d);
  3604:      }
  3605:   },  //MMD_PRN
  3606: 
  3607:   //--------------------------------------------------------------------------------
  3608:   //MMD_SYS システムポート
  3609:   //
  3610:   //  $00E8E000~$00E8E00F(偶数)  バイトリードは$FF、バイトライトは$??、ワードリードは$FFxx、ワードライトは$??xx
  3611:   //  $00E8E000~$00E8E00F(奇数)  バイトリードは$xx、バイトライトは$xx
  3612:   //  $00E8E010~$00E8FFFF  $00E8E000~$00E8E00Fの繰り返し
  3613:   //
  3614:   MMD_SYS {
  3615:     @Override public String toString () {
  3616:       return Multilingual.mlnJapanese ? "システムポート" : "System Port";
  3617:     }
  3618:     //リード
  3619:     @Override protected int mmdRbz (int a) throws M68kException {
  3620:        XEiJ.mpuClockTime += XEiJ.busWaitTime.sysport;
  3621:        switch (a & 15) {
  3622:        case 0x01:
  3623:          return 0b11110000 | VideoController.vcnTargetContrastPort;
  3624:        case 0x03:
  3625:          return 0b11111000 | XEiJ.pnlStereoscopicShutter;
  3626:        case 0x07:
  3627:          return 0b11110100 | (Keyboard.kbdOn ? 8 : 0) | CRTC.crtHRLPort << 1;
  3628:        case 0x0b:
  3629:          return (XEiJ.currentModel.isX68030 () ? 0xdc :
  3630:                  XEiJ.currentMPU < Model.MPU_MC68020 ?
  3631:                  XEiJ.mpuClockMHz <= 10.0 ? 0xff : 0xfe :
  3632:                  XEiJ.mpuClockMHz <= 20.0 ? 0xff : 0xfe);
  3633:        }
  3634:        return 0xff;
  3635:      }
  3636:     @Override protected int mmdRwz (int a) throws M68kException {
  3637:        return 0xff00 | mmdRbz (a + 1);
  3638:      }
  3639:     @Override protected int mmdRls (int a) throws M68kException {
  3640:        return 0xff00ff00 | mmdRbz (a + 1) << 16 | mmdRbz (a + 3);
  3641:      }
  3642:     //ライト
  3643:     @Override protected void mmdWb (int a, int d) throws M68kException {
  3644:        d &= 0xff;
  3645:        switch (a & 15) {
  3646:        case 0x01:
  3647:          VideoController.vcnTargetContrastPort = d & 15;
  3648:          if (FlashingLights.FLR_ON) {
  3649:            FlashingLights.flrUpdateContrast ();
  3650:          } else {
  3651:            int curr = VideoController.vcnTargetContrastMask == 0 ? VideoController.vcnTargetContrastPort : VideoController.vcnTargetContrastTest;
  3652:            if (VideoController.vcnTargetContrastCurr != curr) {
  3653:              VideoController.vcnTargetContrastCurr = curr;
  3654:              VideoController.vcnTargetScaledContrast = VideoController.VCN_CONTRAST_SCALE * VideoController.vcnTargetContrastCurr;
  3655:              CRTC.crtContrastClock = XEiJ.mpuClockTime;
  3656:              CRTC.crtFrameTaskClock = Math.min (CRTC.crtContrastClock, CRTC.crtCaptureClock);
  3657:            }
  3658:          }
  3659:          return;
  3660:        case 0x03:
  3661:          XEiJ.pnlStereoscopicShutter = d & 3;
  3662:          break;
  3663:        case 0x07:
  3664:          {
  3665:            CRTC.crtHRLPort = d >> 1 & 1;
  3666:            int curr = CRTC.crtHRLMask == 0 ? CRTC.crtHRLPort : CRTC.crtHRLTest;
  3667:            if (CRTC.crtHRLCurr != curr) {
  3668:              CRTC.crtHRLCurr = curr;
  3669:              CRTC.crtRestart ();
  3670:            }
  3671:            if ((d & 1 << 2) != 0) {
  3672:              XEiJ.sysResetNMI ();  //NMIリセット
  3673:            }
  3674:          }
  3675:          return;
  3676:        case 0x09:
  3677:          if (XEiJ.currentModel.isX68030 ()) {
  3678:            //X68030のとき
  3679:            //  d=ROMウェイト設定値<<4|RAMウェイト設定値
  3680:            //  ROMウェイト
  3681:            //    ROMウェイト設定値+2
  3682:            //  RAMウェイト
  3683:            //    RAMウェイト設定値が0のとき
  3684:            //      スタティックカラムが有効なとき0
  3685:            //      スタティックカラムが無効なとき4
  3686:            //    RAMウェイト設定値が0でないとき
  3687:            //      RAMウェイト設定値+2
  3688:            //  ROMとRAMにはキャッシュが効く
  3689:            if (XEiJ.currentModel.isX68030 ()) {  //X68030
  3690:              XEiJ.mpuROMWaitCycles = (d >> 4 & 15) + 2;
  3691:              XEiJ.mpuRAMWaitCycles = (d & 15) == 0 ? 0 : (d & 15) + 2;
  3692:              XEiJ.mpuSetWait ();
  3693:            }
  3694:          }
  3695:          return;
  3696:        case 0x0d:
  3697:          SRAM.smrWriteEnableOn = d == 0x31;
  3698:          return;
  3699:        }
  3700:      }
  3701:     @Override protected void mmdWw (int a, int d) throws M68kException {
  3702:        mmdWb (a + 1, d);
  3703:      }
  3704:     @Override protected void mmdWl (int a, int d) throws M68kException {
  3705:        mmdWb (a + 1, d >> 16);
  3706:        mmdWb (a + 3, d);
  3707:      }
  3708:   },  //MMD_SYS
  3709: 
  3710:   //--------------------------------------------------------------------------------
  3711:   //MMD_OPM FM音源
  3712:   //
  3713:   //  $00E90000  バイトリードはバスエラー、バイトライトはバスエラー、ワードリードは$FFFF、ワードライトは$??xx
  3714:   //  $00E90001  バイトリードは$FF、バイトライトは$xx
  3715:   //  $00E90002  バイトリードはバスエラー、バイトライトはバスエラー、ワードリードは$FFxx、ワードライトは$??xx
  3716:   //  $00E90003  バイトリードは$xx、バイトライトは$xx
  3717:   //  $00E90004~$00E91FFF  $00E90000~$00E90003の繰り返し
  3718:   //
  3719:   MMD_OPM {
  3720:     @Override public String toString () {
  3721:       return Multilingual.mlnJapanese ? "FM 音源" : "FM Sound Generator";
  3722:     }
  3723:     //リード
  3724:     @Override protected int mmdRbz (int a) throws M68kException {
  3725:        if ((a & 1) == 0 &&  //偶数アドレスのバイトリード
  3726:            !XEiJ.currentIsSecond) {  //Xellent30の030モードではない
  3727:          return super.mmdRbz (a);  //バスエラー
  3728:        }
  3729:        XEiJ.mpuClockTime += XEiJ.busWaitTime.opm;
  3730:        return (a & 3) == 3 ? OPM.opmYM2151.readStatus () : 0xff;
  3731:      }
  3732:     @Override protected int mmdRwz (int a) throws M68kException {
  3733:        return 0xff00 | mmdRbz (a + 1);
  3734:      }
  3735:     @Override protected int mmdRls (int a) throws M68kException {
  3736:        return 0xff00ff00 | mmdRbz (a + 1) << 16 | mmdRbz (a + 3);
  3737:      }
  3738:     //ライト
  3739:     @Override protected void mmdWb (int a, int d) throws M68kException {
  3740:        if ((a & 1) == 0 &&  //偶数アドレスのバイトライト
  3741:            !XEiJ.currentIsSecond) {  //Xellent30の030モードではない
  3742:          super.mmdWb (a, d);  //バスエラー
  3743:        }
  3744:        XEiJ.mpuClockTime += XEiJ.busWaitTime.opm;
  3745:        a &= XEiJ.BUS_MOTHER_MASK;
  3746:        a &= 3;
  3747:        d &= 0xff;
  3748:        if (a == 3) {  //データレジスタ
  3749:          OPM.opmYM2151.generate (SoundSource.SND_CHANNELS *
  3750:                                  (OPM.OPM_BLOCK_SAMPLES - Math.max (0, (int) ((double) (SoundSource.sndBlockClock - XEiJ.mpuClockTime) /
  3751:                                                                               (double) OPM.OPM_SAMPLE_TIME))));
  3752:          OPM.opmYM2151.writeData (d);
  3753:        } else if (a == 1) {  //アドレスレジスタ
  3754:          OPM.opmYM2151.writeAddress (d);
  3755:        }
  3756:      }
  3757:     @Override protected void mmdWw (int a, int d) throws M68kException {
  3758:        mmdWb (a + 1, d);
  3759:      }
  3760:     @Override protected void mmdWl (int a, int d) throws M68kException {
  3761:        mmdWb (a + 1, d >> 16);
  3762:        mmdWb (a + 3, d);
  3763:      }
  3764:   },  //MMD_OPM
  3765: 
  3766:   //--------------------------------------------------------------------------------
  3767:   //MMD_PCM ADPCM音源
  3768:   //
  3769:   //  $00E92000~$00E92003(偶数)  バイトリードはバスエラー、バイトライトはバスエラー、ワードリードは$FFxx、ワードライトは$??xx
  3770:   //  $00E92000~$00E92003(奇数)  バイトリードは$xx、バイトライトは$xx
  3771:   //  $00E92004~$00E93FFF  $00E92000~$00E92003の繰り返し
  3772:   //
  3773:   MMD_PCM {
  3774:     @Override public String toString () {
  3775:       return Multilingual.mlnJapanese ? "ADPCM 音源" : "ADPCM Sound Generator";
  3776:     }
  3777:     //リード
  3778:     @Override protected int mmdRbz (int a) throws M68kException {
  3779:        if ((a & 1) == 0 &&  //偶数アドレスのバイトリード
  3780:            !XEiJ.currentIsSecond) {  //Xellent30の030モードではない
  3781:          return super.mmdRbz (a);  //バスエラー
  3782:        }
  3783:        XEiJ.mpuClockTime += XEiJ.busWaitTime.adpcm;
  3784:        return (a & 3) == 1 ? (ADPCM.pcmActive ? 0b10000000 : 0) | 0x40 : 0xff;
  3785:      }
  3786:     @Override protected int mmdRwz (int a) throws M68kException {
  3787:        return 0xff00 | mmdRbz (a + 1);
  3788:      }
  3789:     @Override protected int mmdRls (int a) throws M68kException {
  3790:        return 0xff00ff00 | mmdRbz (a + 1) << 16 | mmdRbz (a + 3);
  3791:      }
  3792:     //ライト
  3793:     @Override protected void mmdWb (int a, int d) throws M68kException {
  3794:        if ((a & 1) == 0 &&  //偶数アドレスのバイトライト
  3795:            !XEiJ.currentIsSecond) {  //Xellent30の030モードではない
  3796:          super.mmdWb (a, d);  //バスエラー
  3797:        }
  3798:        XEiJ.mpuClockTime += XEiJ.busWaitTime.adpcm;
  3799:        a &= XEiJ.BUS_MOTHER_MASK;
  3800:        a &= 3;
  3801:        if (a == 1) {  //コマンド
  3802:          if ((d & 0b00000001) != 0) {  //動作終了
  3803:            if (ADPCM.pcmActive) {  //動作中
  3804:              ADPCM.pcmClock = XEiJ.FAR_FUTURE;
  3805:              TickerQueue.tkqRemove (SoundSource.sndPcmTicker);
  3806:              ADPCM.pcmActive = false;
  3807:              ADPCM.pcmEncodedData = -1;
  3808:              ADPCM.pcmDecoderPointer = 0;
  3809:              HD63450.dmaRisePCL (3);
  3810:              HD63450.dmaRiseREQ (3);
  3811:            }
  3812:          } else if ((d & 0b00000010) != 0) {  //動作開始
  3813:            if (!ADPCM.pcmActive) {  //停止中
  3814:              //現在のブロックの残り時間が1サンプルの時間の倍数になるように切り上げる
  3815:              int remainingSamples = Math.max (0, (int) ((double) (SoundSource.sndBlockClock - XEiJ.mpuClockTime) / (double) ADPCM.PCM_SAMPLE_TIME));  //現在のブロックの残りサンプル数
  3816:              ADPCM.pcmClock = SoundSource.sndBlockClock - ADPCM.PCM_SAMPLE_TIME * (long) remainingSamples;  //書き込み開始時刻
  3817:              TickerQueue.tkqAdd (SoundSource.sndPcmTicker, ADPCM.pcmClock);
  3818:              ADPCM.pcmActive = true;
  3819:              int newPointer = SoundSource.SND_CHANNELS * (ADPCM.PCM_BLOCK_SAMPLES - remainingSamples);  //書き込み開始位置
  3820:              if (ADPCM.pcmPointer < newPointer) {
  3821:                ADPCM.pcmFillBuffer (newPointer);
  3822:              } else {
  3823:                ADPCM.pcmPointer = newPointer;  //少し戻る場合がある
  3824:              }
  3825:              //DMAに最初のデータを要求する
  3826:              HD63450.dmaFallPCL (3);
  3827:              HD63450.dmaFallREQ (3);
  3828:            }
  3829:            //} else if ((d & 0b00000100) != 0) {  //録音開始
  3830:            //! 非対応
  3831:          }
  3832:        } else if (a == 3) {  //データ
  3833:          if (ADPCM.pcmActive) {
  3834:            ADPCM.pcmEncodedData = d & 0xff;
  3835:            HD63450.dmaRisePCL (3);
  3836:            HD63450.dmaRiseREQ (3);
  3837:          }
  3838:        }
  3839:      }
  3840:     @Override protected void mmdWw (int a, int d) throws M68kException {
  3841:        mmdWb (a + 1, d);
  3842:      }
  3843:     @Override protected void mmdWl (int a, int d) throws M68kException {
  3844:        mmdWb (a + 1, d >> 16);
  3845:        mmdWb (a + 3, d);
  3846:      }
  3847:   },  //MMD_PCM
  3848: 
  3849:   //--------------------------------------------------------------------------------
  3850:   //MMD_FDC FDコントローラ
  3851:   //
  3852:   //  $00E94000~$00E94007(偶数)  バイトリードはバスエラー、バイトライトはバスエラー、ワードリードは$FFxx、ワードライトは$??xx
  3853:   //  $00E94000~$00E94007(奇数)  バイトリードは$xx、バイトライトは$xx
  3854:   //  $00E94008~$00E95FFF  $00E94000~$00E94007の繰り返し
  3855:   //
  3856:   MMD_FDC {
  3857:     @Override public String toString () {
  3858:       return Multilingual.mlnJapanese ? "FD コントローラ" : "FD Controller";
  3859:     }
  3860:     //ピーク
  3861:     @Override protected byte mmdPbs (int a) {
  3862:       return (byte) mmdPbz (a);
  3863:     }
  3864:     @Override protected int mmdPbz (int a) {
  3865:       a &= XEiJ.BUS_MOTHER_MASK;
  3866:       switch (a) {
  3867:       case FDC.FDC_STATUS_PORT:  //0x00e94001
  3868:         return FDC.fdcPeekStatus ();
  3869:       case FDC.FDC_DATA_PORT:  //0x00e94003
  3870:         return FDC.fdcPeekData ();
  3871:       case FDC.FDC_DRIVE_STATUS:  //0x00e94005
  3872:         return FDC.fdcPeekDriveStatus ();
  3873:       }
  3874:       return 0xff;
  3875:     }
  3876:     @Override protected int mmdPws (int a) {
  3877:       return (short) (mmdPbz (a) << 8 | mmdPbz (a + 1));
  3878:     }
  3879:     @Override protected int mmdPwz (int a) {
  3880:       return mmdPbz (a) << 8 | mmdPbz (a + 1);
  3881:     }
  3882:     @Override protected int mmdPls (int a) {
  3883:       return mmdPwz (a) << 16 | mmdPwz (a + 2);
  3884:     }
  3885:     //リード
  3886:     @Override protected int mmdRbz (int a) throws M68kException {
  3887:        if ((a & 1) == 0 &&  //偶数アドレスのバイトリード
  3888:            !XEiJ.currentIsSecond) {  //Xellent30の030モードではない
  3889:          return super.mmdRbz (a);  //バスエラー
  3890:        }
  3891:        XEiJ.mpuClockTime += XEiJ.busWaitTime.fdc;
  3892:        a &= XEiJ.BUS_MOTHER_MASK;
  3893:        switch (a) {
  3894:        case FDC.FDC_STATUS_PORT:  //0x00e94001
  3895:          return FDC.fdcReadStatus ();
  3896:        case FDC.FDC_DATA_PORT:  //0x00e94003
  3897:          return FDC.fdcReadData ();
  3898:        case FDC.FDC_DRIVE_STATUS:  //0x00e94005
  3899:          return FDC.fdcReadDriveStatus ();
  3900:        }
  3901:        return 0xff;
  3902:      }
  3903:     @Override protected int mmdRwz (int a) throws M68kException {
  3904:        return 0xff00 | mmdRbz (a + 1);
  3905:      }
  3906:     @Override protected int mmdRls (int a) throws M68kException {
  3907:        return 0xff00ff00 | mmdRbz (a + 1) << 16 | mmdRbz (a + 3);
  3908:      }
  3909:     //ライト
  3910:     @Override protected void mmdWb (int a, int d) throws M68kException {
  3911:        if ((a & 1) == 0 &&  //偶数アドレスのバイトライト
  3912:            !XEiJ.currentIsSecond) {  //Xellent30の030モードではない
  3913:          super.mmdWb (a, d);  //バスエラー
  3914:        }
  3915:        XEiJ.mpuClockTime += XEiJ.busWaitTime.fdc;
  3916:        a &= XEiJ.BUS_MOTHER_MASK;
  3917:        switch (a) {
  3918:        case FDC.FDC_STATUS_PORT:  //0x00e94001
  3919:          FDC.fdcWriteCommand (d);
  3920:          break;
  3921:        case FDC.FDC_DATA_PORT:  //0x00e94003
  3922:          FDC.fdcWriteData (d);
  3923:          break;
  3924:        case FDC.FDC_DRIVE_STATUS:  //0x00e94005
  3925:          FDC.fdcWriteDriveControl (d);
  3926:          break;
  3927:        case FDC.FDC_DRIVE_SELECT:  //0x00e94007
  3928:          FDC.fdcWriteDriveSelect (d);
  3929:          break;
  3930:        }
  3931:      }
  3932:     @Override protected void mmdWw (int a, int d) throws M68kException {
  3933:        mmdWb (a + 1, d);
  3934:      }
  3935:     @Override protected void mmdWl (int a, int d) throws M68kException {
  3936:        mmdWb (a + 1, d >> 16);
  3937:        mmdWb (a + 3, d);
  3938:      }
  3939:   },  //MMD_FDC
  3940: 
  3941:   //--------------------------------------------------------------------------------
  3942:   //MMD_HDC SASI HDコントローラ
  3943:   //
  3944:   //  $00E96000~$00E9603F(偶数)  バイトリードはバスエラー、バイトライトはバスエラー、ワードリードは$FFxx、ワードライトは$??xx
  3945:   //  $00E96000~$00E9603F(奇数)  バイトリードは$xx、バイトライトは$xx
  3946:   //                              X68030の$00E96000~$00E9601Fは$00,$00,$FF,$FFの繰り返し。$00E9603Fは$FF
  3947:   //  $00E96040~$00E97FFF  $00E96000~$00E9603Fの繰り返し
  3948:   //
  3949:   MMD_HDC {
  3950:     @Override public String toString () {
  3951:       return Multilingual.mlnJapanese ? "内蔵 SASI/SCSI ポート" : "Internal SASI/SCSI Port";
  3952:     }
  3953:     //ピーク
  3954:     @Override protected int mmdPbz (int a) {
  3955:       if ((a & 0x01) == 0) {  //偶数番地
  3956:         return 0xff;
  3957:       } else {  //奇数番地
  3958:         if (SPC.spcSCSIINOn) {  //SCSI内蔵機
  3959:           if ((a & 0x20) == 0) {  //SASIポート
  3960:             return ((a & 0x02) == 0 ? 0x00 : 0xff);
  3961:           } else {  //SCSIポート
  3962:             return SPC.spcSCSIINChip.spiPeek (a);
  3963:           }
  3964:         } else {  //SASI内蔵機
  3965:           switch (a & 0x3f) {
  3966:           case HDC.HDC_DATA_PORT & 0x3f:  //0x00e96001
  3967:             return HDC.hdcPeekData ();
  3968:           case HDC.HDC_STATUS_PORT & 0x3f:  //0x00e96003
  3969:             return HDC.hdcPeekStatus ();
  3970:           case HDC.HDC_RESET_PORT & 0x3f:  //0x00e96005
  3971:             return 0xff;
  3972:           case HDC.HDC_SELECTION_PORT & 0x3f:  //0x00e96007
  3973:             return 0xff;
  3974:           default:
  3975:             return 0xff;
  3976:           }
  3977:         }
  3978:       }
  3979:     }
  3980:     @Override protected int mmdPwz (int a) {
  3981:       return 0xff00 | mmdPbz (a + 1);
  3982:     }
  3983:     @Override protected int mmdPls (int a) {
  3984:       return 0xff00ff00 | mmdPbz (a + 1) << 16 | mmdPbz (a + 3);
  3985:     }
  3986:     //リード
  3987:     @Override protected int mmdRbz (int a) throws M68kException {
  3988:        XEiJ.mpuClockTime += XEiJ.busWaitTime.hdc;
  3989:        if ((a & 0x01) == 0) {  //偶数番地
  3990:          if (XEiJ.currentIsSecond) {  //Xellent30の030モード
  3991:            return 0xff;
  3992:          }
  3993:          return super.mmdRbz (a);  //バスエラー
  3994:        } else {  //奇数番地
  3995:          if (SPC.spcSCSIINOn) {  //SCSI内蔵機
  3996:            if ((a & 0x20) == 0) {  //SASIポート
  3997:              return ((a & 0x02) == 0 ? 0x00 : 0xff);
  3998:            } else {  //SCSIポート
  3999:              return SPC.spcSCSIINChip.spiRead (a);
  4000:            }
  4001:          } else {  //SASI内蔵機
  4002:            switch (a & 0x3f) {
  4003:            case HDC.HDC_DATA_PORT & 0x3f:  //0x00e96001
  4004:              return HDC.hdcReadData ();
  4005:            case HDC.HDC_STATUS_PORT & 0x3f:  //0x00e96003
  4006:              return HDC.hdcReadStatus ();
  4007:            case HDC.HDC_RESET_PORT & 0x3f:  //0x00e96005
  4008:              return 0xff;
  4009:            case HDC.HDC_SELECTION_PORT & 0x3f:  //0x00e96007
  4010:              return 0xff;
  4011:            default:
  4012:              return 0xff;
  4013:            }
  4014:          }
  4015:        }
  4016:      }
  4017:     @Override protected int mmdRwz (int a) throws M68kException {
  4018:        return 0xff00 | mmdRbz (a + 1);
  4019:      }
  4020:     @Override protected int mmdRls (int a) throws M68kException {
  4021:        return 0xff00ff00 | mmdRbz (a + 1) << 16 | mmdRbz (a + 3);
  4022:      }
  4023:     //ライト
  4024:     @Override protected void mmdWb (int a, int d) throws M68kException {
  4025:        XEiJ.mpuClockTime += XEiJ.busWaitTime.hdc;
  4026:        if ((a & 0x01) == 0) {  //偶数番地
  4027:          if (XEiJ.currentIsSecond) {  //Xellent30の030モード
  4028:            return;
  4029:          }
  4030:          super.mmdWb (a, d);  //バスエラー
  4031:        } else {  //奇数番地
  4032:          if (SPC.spcSCSIINOn) {  //SCSI内蔵機
  4033:            if ((a & 0x20) == 0) {  //SASIポート
  4034:              return;
  4035:            } else {  //SCSIポート
  4036:              SPC.spcSCSIINChip.spiWrite (a, d);
  4037:              return;
  4038:            }
  4039:          } else {  //SASI内蔵機
  4040:            switch (a & 0x3f) {
  4041:            case HDC.HDC_DATA_PORT & 0x3f:  //0x00e96001
  4042:              HDC.hdcWriteData (d);
  4043:              return;
  4044:            case HDC.HDC_STATUS_PORT & 0x3f:  //0x00e96003
  4045:              HDC.hdcWriteCommand (d);
  4046:              return;
  4047:            case HDC.HDC_RESET_PORT & 0x3f:  //0x00e96005
  4048:              HDC.hdcWriteReset (d);
  4049:              return;
  4050:            case HDC.HDC_SELECTION_PORT & 0x3f:  //0x00e96007
  4051:              HDC.hdcWriteSelect (d);
  4052:              return;
  4053:            default:
  4054:              return;
  4055:            }
  4056:          }
  4057:        }
  4058:      }
  4059:     @Override protected void mmdWw (int a, int d) throws M68kException {
  4060:        mmdWb (a + 1, d);
  4061:      }
  4062:     @Override protected void mmdWl (int a, int d) throws M68kException {
  4063:        mmdWb (a + 1, d >> 16);
  4064:        mmdWb (a + 3, d);
  4065:      }
  4066:   },  //MMD_HDC
  4067: 
  4068:   //--------------------------------------------------------------------------------
  4069:   //MMD_SCC SCC
  4070:   //
  4071:   //  $00E98000~$00E98007(偶数)  バイトリードはバスエラー、バイトライトはバスエラー、ワードリードは$FFxx、ワードライトは$??xx
  4072:   //  $00E98000~$00E98007(奇数)  バイトリードは$xx、バイトライトは$xx
  4073:   //  $00E98008~$00E99FFF  $00E98000~$00E98007の繰り返し
  4074:   //
  4075:   MMD_SCC {
  4076:     @Override public String toString () {
  4077:       return Multilingual.mlnJapanese ? "SCC" : "SCC";  //Serial Communication Controller
  4078:     }
  4079:     //ピーク
  4080:     @Override protected int mmdPbz (int a) {
  4081:       return Z8530.sccReadByte (a, true);
  4082:     }
  4083:     @Override protected int mmdPwz (int a) {
  4084:       return 0xff00 | mmdPbz (a + 1);
  4085:     }
  4086:     @Override protected int mmdPls (int a) {
  4087:       return 0xff00ff00 | mmdPbz (a + 1) << 16 | mmdPbz (a + 3);
  4088:     }
  4089:     //リード
  4090:     @Override protected int mmdRbz (int a) throws M68kException {
  4091:        if ((a & 1) == 0 &&  //偶数アドレスのバイトリード
  4092:            !XEiJ.currentIsSecond) {  //Xellent30の030モードではない
  4093:          return super.mmdRbz (a);  //バスエラー
  4094:        }
  4095:        return Z8530.sccReadByte (a, false);
  4096:      }
  4097:     @Override protected int mmdRwz (int a) throws M68kException {
  4098:        return 0xff00 | mmdRbz (a + 1);
  4099:      }
  4100:     @Override protected int mmdRls (int a) throws M68kException {
  4101:        return 0xff00ff00 | mmdRbz (a + 1) << 16 | mmdRbz (a + 3);
  4102:      }
  4103:     //ライト
  4104:     @Override protected void mmdWb (int a, int d) throws M68kException {
  4105:        if ((a & 1) == 0 &&  //偶数アドレスのバイトライト
  4106:            !XEiJ.currentIsSecond) {  //Xellent30の030モードではない
  4107:          super.mmdWb (a, d);  //バスエラー
  4108:        }
  4109:        Z8530.sccWriteByte (a, d);
  4110:      }
  4111:     @Override protected void mmdWw (int a, int d) throws M68kException {
  4112:        mmdWb (a + 1, d);
  4113:      }
  4114:     @Override protected void mmdWl (int a, int d) throws M68kException {
  4115:        mmdWb (a + 1, d >> 16);
  4116:        mmdWb (a + 3, d);
  4117:      }
  4118:   },  //MMD_SCC
  4119: 
  4120:   //--------------------------------------------------------------------------------
  4121:   //MMD_PPI PPI
  4122:   //
  4123:   //  $00E9A000~$00E9A007(偶数)  バイトリードはバスエラー、バイトライトはバスエラー、ワードリードは$FFxx、ワードライトは$??xx
  4124:   //  $00E9A000~$00E9A007(奇数)  バイトリードは$xx、バイトライトは$xx
  4125:   //  $00E9A008~$00E9BFFF  $00E9A000~$00E9A007の繰り返し
  4126:   //
  4127:   MMD_PPI {
  4128:     @Override public String toString () {
  4129:       return Multilingual.mlnJapanese ? "PPI" : "PPI";  //Programmable Peripheral Interface
  4130:     }
  4131:     //リード
  4132:     @Override protected int mmdRbz (int a) throws M68kException {
  4133:        if ((a & 1) == 0 &&  //偶数アドレスのバイトリード
  4134:            !XEiJ.currentIsSecond) {  //Xellent30の030モードではない
  4135:          return super.mmdRbz (a);  //バスエラー
  4136:        }
  4137:        XEiJ.mpuClockTime += XEiJ.busWaitTime.ppi;
  4138:        return PPI.ppiReadByte (a);
  4139:      }
  4140:     @Override protected int mmdRwz (int a) throws M68kException {
  4141:        return 0xff00 | mmdRbz (a + 1);
  4142:      }
  4143:     @Override protected int mmdRls (int a) throws M68kException {
  4144:        return 0xff00ff00 | mmdRbz (a + 1) << 16 | mmdRbz (a + 3);
  4145:      }
  4146:     //ライト
  4147:     @Override protected void mmdWb (int a, int d) throws M68kException {
  4148:        if ((a & 1) == 0 &&  //偶数アドレスのバイトライト
  4149:            !XEiJ.currentIsSecond) {  //Xellent30の030モードではない
  4150:          super.mmdWb (a, d);  //バスエラー
  4151:        }
  4152:        XEiJ.mpuClockTime += XEiJ.busWaitTime.ppi;
  4153:        PPI.ppiWriteByte (a, d);
  4154:      }
  4155:     @Override protected void mmdWw (int a, int d) throws M68kException {
  4156:        mmdWb (a + 1, d);
  4157:      }
  4158:     @Override protected void mmdWl (int a, int d) throws M68kException {
  4159:        mmdWb (a + 1, d >> 16);
  4160:        mmdWb (a + 3, d);
  4161:      }
  4162:   },  //MMD_PPI
  4163: 
  4164:   //--------------------------------------------------------------------------------
  4165:   //MMD_IOI I/O割り込み
  4166:   //
  4167:   //  $00E9C000~$00E9C00F(偶数)  バイトリードはバスエラー、バイトライトはバスエラー、ワードリードは$FFxx、ワードライトは$??xx
  4168:   //  $00E9C000~$00E9C00F(奇数)  バイトリードは$xx、バイトライトは$xx
  4169:   //  $00E9C010~$00E9BFFF  $00E9C000~$00E9C00Fの繰り返し
  4170:   //
  4171:   MMD_IOI {
  4172:     @Override public String toString () {
  4173:       return Multilingual.mlnJapanese ? "I/O 割り込み" : "I/O Interrupt";
  4174:     }
  4175:     //リード
  4176:     @Override protected int mmdRbz (int a) throws M68kException {
  4177:        if ((a & 1) == 0 &&  //偶数アドレスのバイトリード
  4178:            !XEiJ.currentIsSecond) {  //Xellent30の030モードではない
  4179:          return super.mmdRbz (a);  //バスエラー
  4180:        }
  4181:        XEiJ.mpuClockTime += XEiJ.busWaitTime.ioi;
  4182:        a &= XEiJ.BUS_MOTHER_MASK;
  4183:        if (a == IOInterrupt.IOI_STATUS) {
  4184:          return IOInterrupt.ioiReadStatus ();
  4185:        } else if (a == IOInterrupt.IOI_VECTOR) {  //ライトオンリー。リードすると$FFが返る
  4186:          //return IOInterrupt.ioiReadVector ();
  4187:          return 0xff;
  4188:        } else {
  4189:          return super.mmdRbz (a);  //バスエラー
  4190:        }
  4191:      }
  4192:     @Override protected int mmdRwz (int a) throws M68kException {
  4193:        return 0xff00 | mmdRbz (a + 1);
  4194:      }
  4195:     @Override protected int mmdRls (int a) throws M68kException {
  4196:        return 0xff00ff00 | mmdRbz (a + 1) << 16 | mmdRbz (a + 3);
  4197:      }
  4198:     //ライト
  4199:     @Override protected void mmdWb (int a, int d) throws M68kException {
  4200:        if ((a & 1) == 0 &&  //偶数アドレスのバイトライト
  4201:            !XEiJ.currentIsSecond) {  //Xellent30の030モードではない
  4202:          super.mmdWb (a, d);  //バスエラー
  4203:        }
  4204:        XEiJ.mpuClockTime += XEiJ.busWaitTime.ioi;
  4205:        a &= XEiJ.BUS_MOTHER_MASK;
  4206:        if (a == IOInterrupt.IOI_STATUS) {
  4207:          IOInterrupt.ioiWriteEnable (d);
  4208:        } else if (a == IOInterrupt.IOI_VECTOR) {
  4209:          IOInterrupt.ioiWriteVector (d);
  4210:        } else {
  4211:          super.mmdWb (a, d);  //バスエラー
  4212:        }
  4213:      }
  4214:     @Override protected void mmdWw (int a, int d) throws M68kException {
  4215:        mmdWb (a + 1, d);
  4216:      }
  4217:     @Override protected void mmdWl (int a, int d) throws M68kException {
  4218:        mmdWb (a + 1, d >> 16);
  4219:        mmdWb (a + 3, d);
  4220:      }
  4221:   },  //MMD_IOI
  4222: 
  4223:   //--------------------------------------------------------------------------------
  4224:   //MMD_XB1 拡張ボード領域1
  4225:   MMD_XB1 {
  4226:     @Override public String toString () {
  4227:       return Multilingual.mlnJapanese ? "拡張ボード領域 1" : "Expansion Board Area 1";
  4228:     }
  4229:     //ピーク
  4230:     @Override protected int mmdPbz (int a) {
  4231:       if ((a & (XEiJ.BUS_MOTHER_MASK & -0x20)) == 0x00e9e000) {  //数値演算プロセッサボード1
  4232:         if ((7 & XEiJ.currentCopro1) != 0) {
  4233:           return XEiJ.fpuCoproboard1.cirPeekByteZero (a);
  4234:         } else {
  4235:           return 0xff;
  4236:         }
  4237:       }
  4238:       if ((a & (XEiJ.BUS_MOTHER_MASK & -0x20)) == 0x00e9e080) {  //数値演算プロセッサボード2
  4239:         if ((7 & XEiJ.currentCopro2) != 0) {
  4240:           return XEiJ.fpuCoproboard2.cirPeekByteZero (a);
  4241:         } else {
  4242:           return 0xff;
  4243:         }
  4244:       }
  4245:       if ((a & (XEiJ.BUS_MOTHER_MASK & -HFS.HFS_ROM_SIZE)) == HFS.HFS_ADDRESS) {  //ホストファイルシステムインタフェイス
  4246:         a &= XEiJ.BUS_MOTHER_MASK;
  4247:         return MainMemory.mmrM8[a] & 0xff;
  4248:       }
  4249:       if (Keyboard.KBD_ZKEY_ON &&
  4250:           (a & (XEiJ.BUS_MOTHER_MASK & -Keyboard.KBD_ZKEY_IO_SIZE)) == Keyboard.KBD_ZKEY_IO_ADDRESS) {  //Zキーボード
  4251:         return Keyboard.kbdZKeyIOReadByte (a);
  4252:       }
  4253:       return 0xff;
  4254:     }
  4255:     @Override protected int mmdPwz (int a) {
  4256:       if ((a & (XEiJ.BUS_MOTHER_MASK & -0x20)) == 0x00e9e000) {  //数値演算プロセッサボード1
  4257:         if ((7 & XEiJ.currentCopro1) != 0) {
  4258:           return XEiJ.fpuCoproboard1.cirPeekWordZero (a);
  4259:         } else {
  4260:           return 0xffff;
  4261:         }
  4262:       }
  4263:       if ((a & (XEiJ.BUS_MOTHER_MASK & -0x20)) == 0x00e9e080) {  //数値演算プロセッサボード2
  4264:         if ((7 & XEiJ.currentCopro2) != 0) {
  4265:           return XEiJ.fpuCoproboard2.cirPeekWordZero (a);
  4266:         } else {
  4267:           return 0xffff;
  4268:         }
  4269:       }
  4270:       if ((a & (XEiJ.BUS_MOTHER_MASK & -HFS.HFS_ROM_SIZE)) == HFS.HFS_ADDRESS) {  //ホストファイルシステムインタフェイス
  4271:         a &= XEiJ.BUS_MOTHER_MASK;
  4272:         return (char) (MainMemory.mmrM8[a] << 8 | (MainMemory.mmrM8[a + 1] & 0xff));
  4273:       }
  4274:       if (Keyboard.KBD_ZKEY_ON &&
  4275:           (a & (XEiJ.BUS_MOTHER_MASK & -Keyboard.KBD_ZKEY_IO_SIZE)) == Keyboard.KBD_ZKEY_IO_ADDRESS) {  //Zキーボード
  4276:         return Keyboard.kbdZKeyIOReadWord (a);
  4277:       }
  4278:       return 0xffff;
  4279:     }
  4280:     @Override protected int mmdPls (int a) {
  4281:       if ((a & (XEiJ.BUS_MOTHER_MASK & -0x20)) == 0x00e9e000) {  //数値演算プロセッサボード1
  4282:         if ((7 & XEiJ.currentCopro1) != 0) {
  4283:           return XEiJ.fpuCoproboard1.cirPeekLong (a);
  4284:         } else {
  4285:           return -1;
  4286:         }
  4287:       }
  4288:       if ((a & (XEiJ.BUS_MOTHER_MASK & -0x20)) == 0x00e9e080) {  //数値演算プロセッサボード2
  4289:         if ((7 & XEiJ.currentCopro2) != 0) {
  4290:           return XEiJ.fpuCoproboard2.cirPeekLong (a);
  4291:         } else {
  4292:           return -1;
  4293:         }
  4294:       }
  4295:       if ((a & (XEiJ.BUS_MOTHER_MASK & -HFS.HFS_ROM_SIZE)) == HFS.HFS_ADDRESS) {  //ホストファイルシステムインタフェイス
  4296:         a &= XEiJ.BUS_MOTHER_MASK;
  4297:         return MainMemory.mmrM8[a] << 24 | (MainMemory.mmrM8[a + 1] & 0xff) << 16 | (char) (MainMemory.mmrM8[a + 2] << 8 | (MainMemory.mmrM8[a + 3] & 0xff));
  4298:       }
  4299:       if (Keyboard.KBD_ZKEY_ON &&
  4300:           (a & (XEiJ.BUS_MOTHER_MASK & -Keyboard.KBD_ZKEY_IO_SIZE)) == Keyboard.KBD_ZKEY_IO_ADDRESS) {  //Zキーボード
  4301:         return Keyboard.kbdZKeyIOReadLong (a);
  4302:       }
  4303:       return -1;
  4304:     }
  4305:     //リード
  4306:     @Override protected int mmdRbz (int a) throws M68kException {
  4307:        if ((a & (XEiJ.BUS_MOTHER_MASK & -0x20)) == 0x00e9e000) {  //数値演算プロセッサボード1
  4308:          if ((7 & XEiJ.currentCopro1) != 0) {
  4309:            return XEiJ.fpuCoproboard1.cirReadByteZero (a);
  4310:          } else {
  4311:            return super.mmdRbz (a);  //バスエラー
  4312:          }
  4313:        }
  4314:        if ((a & (XEiJ.BUS_MOTHER_MASK & -0x20)) == 0x00e9e080) {  //数値演算プロセッサボード2
  4315:          if ((7 & XEiJ.currentCopro2) != 0) {
  4316:            return XEiJ.fpuCoproboard2.cirReadByteZero (a);
  4317:          } else {
  4318:            return super.mmdRbz (a);  //バスエラー
  4319:          }
  4320:        }
  4321:        if ((a & (XEiJ.BUS_MOTHER_MASK & -HFS.HFS_ROM_SIZE)) == HFS.HFS_ADDRESS) {  //ホストファイルシステムインタフェイス
  4322:          a &= XEiJ.BUS_MOTHER_MASK;
  4323:          return MainMemory.mmrM8[a] & 0xff;
  4324:        }
  4325:        if (Keyboard.KBD_ZKEY_ON &&
  4326:            (a & (XEiJ.BUS_MOTHER_MASK & -Keyboard.KBD_ZKEY_IO_SIZE)) == Keyboard.KBD_ZKEY_IO_ADDRESS) {  //Zキーボード
  4327:          return Keyboard.kbdZKeyIOReadByte (a);
  4328:        }
  4329:        return super.mmdRbz (a);  //バスエラー
  4330:      }
  4331:     @Override protected int mmdRwz (int a) throws M68kException {
  4332:        if ((a & (XEiJ.BUS_MOTHER_MASK & -0x20)) == 0x00e9e000) {  //数値演算プロセッサボード1
  4333:          if ((7 & XEiJ.currentCopro1) != 0) {
  4334:            return XEiJ.fpuCoproboard1.cirReadWordZero (a);
  4335:          } else {
  4336:            return super.mmdRwz (a);  //バスエラー
  4337:          }
  4338:        }
  4339:        if ((a & (XEiJ.BUS_MOTHER_MASK & -0x20)) == 0x00e9e080) {  //数値演算プロセッサボード2
  4340:          if ((7 & XEiJ.currentCopro2) != 0) {
  4341:            return XEiJ.fpuCoproboard2.cirReadWordZero (a);
  4342:          } else {
  4343:            return super.mmdRwz (a);  //バスエラー
  4344:          }
  4345:        }
  4346:        if ((a & (XEiJ.BUS_MOTHER_MASK & -HFS.HFS_ROM_SIZE)) == HFS.HFS_ADDRESS) {  //ホストファイルシステムインタフェイス
  4347:          a &= XEiJ.BUS_MOTHER_MASK;
  4348:          return (char) (MainMemory.mmrM8[a] << 8 | (MainMemory.mmrM8[a + 1] & 0xff));
  4349:        }
  4350:        if (Keyboard.KBD_ZKEY_ON &&
  4351:            (a & (XEiJ.BUS_MOTHER_MASK & -Keyboard.KBD_ZKEY_IO_SIZE)) == Keyboard.KBD_ZKEY_IO_ADDRESS) {  //Zキーボード
  4352:          return Keyboard.kbdZKeyIOReadWord (a);
  4353:        }
  4354:        return super.mmdRwz (a);  //バスエラー
  4355:      }
  4356:     @Override protected int mmdRls (int a) throws M68kException {
  4357:        if ((a & (XEiJ.BUS_MOTHER_MASK & -0x20)) == 0x00e9e000) {  //数値演算プロセッサボード1
  4358:          if ((7 & XEiJ.currentCopro1) != 0) {
  4359:            return XEiJ.fpuCoproboard1.cirReadLong (a);
  4360:          } else {
  4361:            return super.mmdRls (a);  //バスエラー
  4362:          }
  4363:        }
  4364:        if ((a & (XEiJ.BUS_MOTHER_MASK & -0x20)) == 0x00e9e080) {  //数値演算プロセッサボード2
  4365:          if ((7 & XEiJ.currentCopro2) != 0) {
  4366:            return XEiJ.fpuCoproboard2.cirReadLong (a);
  4367:          } else {
  4368:            return super.mmdRls (a);  //バスエラー
  4369:          }
  4370:        }
  4371:        if ((a & (XEiJ.BUS_MOTHER_MASK & -HFS.HFS_ROM_SIZE)) == HFS.HFS_ADDRESS) {  //ホストファイルシステムインタフェイス
  4372:          a &= XEiJ.BUS_MOTHER_MASK;
  4373:          return MainMemory.mmrM8[a] << 24 | (MainMemory.mmrM8[a + 1] & 0xff) << 16 | (char) (MainMemory.mmrM8[a + 2] << 8 | (MainMemory.mmrM8[a + 3] & 0xff));
  4374:        }
  4375:        if (Keyboard.KBD_ZKEY_ON &&
  4376:            (a & (XEiJ.BUS_MOTHER_MASK & -Keyboard.KBD_ZKEY_IO_SIZE)) == Keyboard.KBD_ZKEY_IO_ADDRESS) {  //Zキーボード
  4377:          return Keyboard.kbdZKeyIOReadLong (a);
  4378:        }
  4379:        return super.mmdRls (a);  //バスエラー
  4380:      }
  4381:     //ライト
  4382:     @Override protected void mmdWb (int a, int d) throws M68kException {
  4383:        if ((a & (XEiJ.BUS_MOTHER_MASK & -0x20)) == 0x00e9e000) {  //数値演算プロセッサボード1
  4384:          if ((7 & XEiJ.currentCopro1) != 0) {
  4385:            XEiJ.fpuCoproboard1.cirWriteByte (a, d);
  4386:            return;
  4387:          } else {
  4388:            super.mmdWb (a, d);  //バスエラー
  4389:            return;
  4390:          }
  4391:        }
  4392:        if ((a & (XEiJ.BUS_MOTHER_MASK & -0x20)) == 0x00e9e080) {  //数値演算プロセッサボード2
  4393:          if ((7 & XEiJ.currentCopro2) != 0) {
  4394:            XEiJ.fpuCoproboard2.cirWriteByte (a, d);
  4395:            return;
  4396:          } else {
  4397:            super.mmdWb (a, d);  //バスエラー
  4398:            return;
  4399:          }
  4400:        }
  4401:        if (Keyboard.KBD_ZKEY_ON &&
  4402:            (a & (XEiJ.BUS_MOTHER_MASK & -Keyboard.KBD_ZKEY_IO_SIZE)) == Keyboard.KBD_ZKEY_IO_ADDRESS) {  //Zキーボード
  4403:          Keyboard.kbdZKeyIOWriteByte (a, d);
  4404:          return;
  4405:        }
  4406:        super.mmdWb (a, d);  //バスエラー
  4407:      }
  4408:     @Override protected void mmdWw (int a, int d) throws M68kException {
  4409:        if ((a & (XEiJ.BUS_MOTHER_MASK & -0x20)) == 0x00e9e000) {  //数値演算プロセッサボード1
  4410:          if ((7 & XEiJ.currentCopro1) != 0) {
  4411:            XEiJ.fpuCoproboard1.cirWriteWord (a, d);
  4412:            return;
  4413:          } else {
  4414:            super.mmdWw (a, d);  //バスエラー
  4415:            return;
  4416:          }
  4417:        }
  4418:        if ((a & (XEiJ.BUS_MOTHER_MASK & -0x20)) == 0x00e9e080) {  //数値演算プロセッサボード2
  4419:          if ((7 & XEiJ.currentCopro2) != 0) {
  4420:            XEiJ.fpuCoproboard2.cirWriteWord (a, d);
  4421:            return;
  4422:          } else {
  4423:            super.mmdWw (a, d);  //バスエラー
  4424:            return;
  4425:          }
  4426:        }
  4427:        if (Keyboard.KBD_ZKEY_ON &&
  4428:            (a & (XEiJ.BUS_MOTHER_MASK & -Keyboard.KBD_ZKEY_IO_SIZE)) == Keyboard.KBD_ZKEY_IO_ADDRESS) {  //Zキーボード
  4429:          Keyboard.kbdZKeyIOWriteWord (a, d);
  4430:          return;
  4431:        }
  4432:        super.mmdWw (a, d);  //バスエラー
  4433:      }
  4434:     @Override protected void mmdWl (int a, int d) throws M68kException {
  4435:        if ((a & (XEiJ.BUS_MOTHER_MASK & -0x20)) == 0x00e9e000) {  //数値演算プロセッサボード1
  4436:          if ((7 & XEiJ.currentCopro1) != 0) {
  4437:            XEiJ.fpuCoproboard1.cirWriteLong (a, d);
  4438:            return;
  4439:          } else {
  4440:            super.mmdWl (a, d);  //バスエラー
  4441:            return;
  4442:          }
  4443:        }
  4444:        if ((a & (XEiJ.BUS_MOTHER_MASK & -0x20)) == 0x00e9e080) {  //数値演算プロセッサボード2
  4445:          if ((7 & XEiJ.currentCopro2) != 0) {
  4446:            XEiJ.fpuCoproboard2.cirWriteLong (a, d);
  4447:            return;
  4448:          } else {
  4449:            super.mmdWl (a, d);  //バスエラー
  4450:            return;
  4451:          }
  4452:        }
  4453:        if (Keyboard.KBD_ZKEY_ON &&
  4454:            (a & (XEiJ.BUS_MOTHER_MASK & -Keyboard.KBD_ZKEY_IO_SIZE)) == Keyboard.KBD_ZKEY_IO_ADDRESS) {  //Zキーボード
  4455:          Keyboard.kbdZKeyIOWriteLong (a, d);
  4456:          return;
  4457:        }
  4458:        super.mmdWl (a, d);  //バスエラー
  4459:      }
  4460:   },  //MMD_XB1
  4461: 
  4462:   //--------------------------------------------------------------------------------
  4463:   //MMD_EXS 拡張SCSI
  4464:   //  必要なときだけ接続される
  4465:   //  拡張SCSIのROMのサイズは8KBなのでリードのときのバスエラーのチェックは不要
  4466:   //  ライトのときはROMには書き込めないのでSPCのレジスタでなければバスエラー
  4467:   MMD_EXS {
  4468:     @Override public String toString () {
  4469:       return Multilingual.mlnJapanese ? "拡張 SCSI ポート" : "Expansion SCSI Port";
  4470:     }
  4471:     //ピーク
  4472:     @Override protected int mmdPbz (int a) {
  4473:       if ((a & (-32 & XEiJ.BUS_MOTHER_MASK)) == SPC.SPC_BASE_EX) {  //レジスタ
  4474:         if ((a & 0x01) == 0) {  //偶数番地
  4475:           return 0xff;
  4476:         } else {  //奇数番地
  4477:           return SPC.spcSCSIEXChip.spiPeek (a);
  4478:         }
  4479:       } else {  //ROM
  4480:         return 0xff & MainMemory.mmrM8[a];
  4481:       }
  4482:     }
  4483:     @Override protected int mmdPwz (int a) {
  4484:       XEiJ.mpuClockTime += XEiJ.busWaitTime.hdc;  //!!!
  4485:       if ((a & (-32 & XEiJ.BUS_MOTHER_MASK)) == SPC.SPC_BASE_EX) {  //レジスタ
  4486:         return 0xff00 | SPC.spcSCSIEXChip.spiPeek (a + 1);
  4487:       } else {  //ROM
  4488:         return (0xff & MainMemory.mmrM8[a]) << 8 | (0xff & MainMemory.mmrM8[a + 1]);
  4489:       }
  4490:     }
  4491:     @Override protected int mmdPls (int a) {
  4492:       return mmdPwz (a) << 16 | mmdPwz (a + 2);
  4493:     }
  4494:     //リード
  4495:     @Override protected int mmdRbz (int a) throws M68kException {
  4496:        XEiJ.mpuClockTime += XEiJ.busWaitTime.hdc;  //!!!
  4497:        if ((a & (-32 & XEiJ.BUS_MOTHER_MASK)) == SPC.SPC_BASE_EX) {  //レジスタ
  4498:          if ((a & 0x01) == 0) {  //偶数番地
  4499:            if (XEiJ.currentIsSecond) {  //Xellent30の030モード
  4500:              return 0xff;
  4501:            }
  4502:            return super.mmdRbz (a);  //バスエラー
  4503:          } else {  //奇数番地
  4504:            return SPC.spcSCSIEXChip.spiRead (a);
  4505:          }
  4506:        } else {  //ROM
  4507:          return 0xff & MainMemory.mmrM8[a];
  4508:        }
  4509:      }
  4510:     @Override protected int mmdRwz (int a) throws M68kException {
  4511:        XEiJ.mpuClockTime += XEiJ.busWaitTime.hdc;  //!!!
  4512:        if ((a & (-32 & XEiJ.BUS_MOTHER_MASK)) == SPC.SPC_BASE_EX) {  //レジスタ
  4513:          return 0xff00 | SPC.spcSCSIEXChip.spiRead (a + 1);
  4514:        } else {  //ROM
  4515:          return (0xff & MainMemory.mmrM8[a]) << 8 | (0xff & MainMemory.mmrM8[a + 1]);
  4516:        }
  4517:      }
  4518:     @Override protected int mmdRls (int a) throws M68kException {
  4519:        return mmdRwz (a) << 16 | mmdRwz (a + 2);
  4520:      }
  4521:     //ライト
  4522:     @Override protected void mmdWb (int a, int d) throws M68kException {
  4523:        XEiJ.mpuClockTime += XEiJ.busWaitTime.hdc;  //!!!
  4524:        if ((a & (-32 & XEiJ.BUS_MOTHER_MASK)) == SPC.SPC_BASE_EX) {  //レジスタ
  4525:          if ((a & 1) == 0) {  //偶数番地
  4526:            if (XEiJ.currentIsSecond) {  //Xellent30の030モード
  4527:              return;
  4528:            }
  4529:            super.mmdWb (a, d);  //バスエラー
  4530:          } else {  //奇数番地
  4531:            SPC.spcSCSIEXChip.spiWrite (a, d);
  4532:            return;
  4533:          }
  4534:        } else {  //ROM
  4535:          super.mmdWb (a, d);  //バスエラー
  4536:        }
  4537:      }
  4538:     @Override protected void mmdWw (int a, int d) throws M68kException {
  4539:        XEiJ.mpuClockTime += XEiJ.busWaitTime.hdc;  //!!!
  4540:        if ((a & (-32 & XEiJ.BUS_MOTHER_MASK)) == SPC.SPC_BASE_EX) {  //レジスタ
  4541:          SPC.spcSCSIEXChip.spiWrite (a + 1, d);
  4542:          return;
  4543:        } else {  //ROM
  4544:          super.mmdWw (a, d);  //バスエラー
  4545:        }
  4546:      }
  4547:     @Override protected void mmdWl (int a, int d) throws M68kException {
  4548:        mmdWw (a, d >> 16);
  4549:        mmdWw (a + 2, d);
  4550:      }
  4551:   },  //MMD_EXS
  4552: 
  4553:   //--------------------------------------------------------------------------------
  4554:   //MMD_XB2 拡張ボード領域2
  4555:   //
  4556:   //  $00EAFF80  リードはバスエラー、バイトライトはバスエラー、ワードライトは$00200000~$003FFFFFがあるとき$??xx、ないときバスエラー
  4557:   //  $00EAFF81  リードはバスエラー、ライトは$00200000~$003FFFFFがあるとき$xx、ないときバスエラー
  4558:   //  $00EAFF82  リードはバスエラー、バイトライトはバスエラー、ワードライトは$00400000~$005FFFFFがあるとき$??xx、ないときバスエラー
  4559:   //  $00EAFF83  リードはバスエラー、ライトは$00400000~$005FFFFFがあるとき$xx、ないときバスエラー
  4560:   //  $00EAFF84  リードはバスエラー、バイトライトはバスエラー、ワードライトは$00600000~$007FFFFFがあるとき$??xx、ないときバスエラー
  4561:   //  $00EAFF85  リードはバスエラー、ライトは$00600000~$007FFFFFがあるとき$xx、ないときバスエラー
  4562:   //  $00EAFF86  リードはバスエラー、バイトライトはバスエラー、ワードライトは$00800000~$009FFFFFがあるとき$??xx、ないときバスエラー
  4563:   //  $00EAFF87  リードはバスエラー、ライトは$00800000~$009FFFFFがあるとき$xx、ないときバスエラー
  4564:   //  $00EAFF88  リードはバスエラー、バイトライトはバスエラー、ワードライトは$00A00000~$00BFFFFFがあるとき$??xx、ないときバスエラー
  4565:   //  $00EAFF89  リードはバスエラー、ライトは$00A00000~$00BFFFFFがあるとき$xx、ないときバスエラー
  4566:   //  $00EAFF8A~$00EAFF8F  バスエラー
  4567:   //  $00EAFF90~$00EAFFFF  $00EAFF80~$00EAFF8Fの繰り返し
  4568:   //
  4569:   //  拡張
  4570:   //  $00EAFF7F  バンクメモリのページ番号
  4571:   //
  4572:   MMD_XB2 {
  4573:     @Override public String toString () {
  4574:       return Multilingual.mlnJapanese ? "拡張ボード領域 2" : "Expansion Board Area 2";
  4575:     }
  4576:     //リード
  4577:     @Override protected int mmdRbz (int a) throws M68kException {
  4578:        a &= XEiJ.BUS_MOTHER_MASK;
  4579:        if (0x00eaff81 <= a && a <= 0x00eaff89 && (a & 1) != 0) {  //スーパーバイザエリア設定ポート
  4580:          return MainMemory.mmrM8[a] & 0xff;  //読み出せるようにしておく(本来はライトオンリー)
  4581:        }
  4582:        if (XEiJ.bnkOn && a == 0x00eaff7f) {  //バンクメモリのページ番号
  4583:          return XEiJ.bnkPageStart >> 17;
  4584:        }
  4585:        return super.mmdRbz (a);  //バスエラー
  4586:      }
  4587:     //ライト
  4588:     @Override protected void mmdWb (int a, int d) throws M68kException {
  4589:        a &= XEiJ.BUS_MOTHER_MASK;
  4590:        if (0x00eaff81 <= a && a <= 0x00eaff89 && (a & 1) != 0) {  //スーパーバイザエリア設定ポート
  4591:          MainMemory.mmrM8[a] = (byte) d;  //読み出せるようにしておく(本来はライトオンリー)
  4592:          a = (a & 14) + 2 << 20;  //1,3,5,7,9→2,4,6,8,a
  4593:          for (int m = 1; m <= 128; m <<= 1) {
  4594:            if ((d & m) == 0) {  //ユーザエリア
  4595:              XEiJ.busUser ( MemoryMappedDevice.MMD_MMR, a, a + 0x00040000);
  4596:            } else {  //スーパーバイザエリア
  4597:              XEiJ.busSuper (MemoryMappedDevice.MMD_MMR, a, a + 0x00040000);
  4598:            }
  4599:            a += 0x00040000;
  4600:          }
  4601:          return;
  4602:        }
  4603:        if (XEiJ.bnkOn && a == 0x00eaff7f) {  //バンクメモリのページ番号
  4604:          XEiJ.bnkPageStart = (d & 0xff) << 17;
  4605:          return;
  4606:        }
  4607:        super.mmdWb (a, d);  //バスエラー
  4608:      }
  4609:   },  //MMD_XB2
  4610: 
  4611:   //--------------------------------------------------------------------------------
  4612:   //MMD_SPR スプライト画面
  4613:   //
  4614:   //  CRTCのR20の下位5ビットが%1xx1xでないとき
  4615:   //    $00EB0000-$00EB03FF  スプライトスクロールレジスタ(0~127)
  4616:   //    $00EB0400-$00EB07FF  $FF。256枚表示のときスプライトスクロールレジスタ(128~255)
  4617:   //    $00EB0800-$00EB0811  設定
  4618:   //    $00EB0812-$00EB7FFF  $FF
  4619:   //    $00EB8000-$00EBFFFF  スプライトPCG・テキストエリア
  4620:   //
  4621:   //  CRTCのR20の下位5ビットが%1xx1xのとき
  4622:   //    $00EB0000-$00EB03FF  バスエラー
  4623:   //    $00EB0400-$00EB07FF  バスエラー
  4624:   //    $00EB0800-$00EB0811  設定
  4625:   //    $00EB0812-$00EB7FFF  $FF
  4626:   //    $00EB8000-$00EBFFFF  バスエラー
  4627:   //
  4628:   //  メモ
  4629:   //    スプライトPCG・テキストエリアにバイトサイズで書き込むとデータが破壊される
  4630:   //
  4631:   MMD_SPR {
  4632:     @Override public String toString () {
  4633:       return Multilingual.mlnJapanese ? "スプライト画面" : "Sprite Screen";
  4634:     }
  4635:     //リード
  4636:     @Override protected byte mmdRbs (int a) throws M68kException {
  4637:        XEiJ.mpuClockTime += XEiJ.busWaitTime.sprc;
  4638:        return (byte) SpriteScreen.sprReadByte (a);
  4639:      }
  4640:     @Override protected int mmdRbz (int a) throws M68kException {
  4641:        XEiJ.mpuClockTime += XEiJ.busWaitTime.sprc;
  4642:        return SpriteScreen.sprReadByte (a);
  4643:      }
  4644:     @Override protected int mmdRws (int a) throws M68kException {
  4645:        XEiJ.mpuClockTime += XEiJ.busWaitTime.sprc;
  4646:        return (short) SpriteScreen.sprReadWord (a);
  4647:      }
  4648:     @Override protected int mmdRwz (int a) throws M68kException {
  4649:        XEiJ.mpuClockTime += XEiJ.busWaitTime.sprc;
  4650:        return SpriteScreen.sprReadWord (a);
  4651:      }
  4652:     @Override protected int mmdRls (int a) throws M68kException {
  4653:        XEiJ.mpuClockTime += XEiJ.busWaitTime.sprc * 2;
  4654:        return SpriteScreen.sprReadLong (a);
  4655:      }
  4656:     //ライト
  4657:     @Override protected void mmdWb (int a, int d) throws M68kException {
  4658:        XEiJ.mpuClockTime += XEiJ.busWaitTime.sprc;
  4659:        SpriteScreen.sprWriteByte (a, d);
  4660:      }
  4661:     @Override protected void mmdWw (int a, int d) throws M68kException {
  4662:        XEiJ.mpuClockTime += XEiJ.busWaitTime.sprc;
  4663:        SpriteScreen.sprWriteWord (a, d);
  4664:      }
  4665:     @Override protected void mmdWl (int a, int d) throws M68kException {
  4666:        XEiJ.mpuClockTime += XEiJ.busWaitTime.sprc * 2;
  4667:        SpriteScreen.sprWriteLong (a, d);
  4668:      }
  4669:   },  //MMD_SPR
  4670: 
  4671:   //--------------------------------------------------------------------------------
  4672:   //MMD_XB3 拡張ボード領域3
  4673:   //  $00EC0000~$00ECFFFF  64KB
  4674:   //  0x00ec0000  ユーザI/Oエリア
  4675:   //  0x00ec0000  Awesome
  4676:   //  0x00ec0000  Xellent30
  4677:   //  0x00ecc000  Mercury
  4678:   //  0x00ece000  Neptune
  4679:   //  0x00ecf000  Venus-X/030
  4680:   MMD_XB3 {
  4681:     @Override public String toString () {
  4682:       return Multilingual.mlnJapanese ? "拡張ボード領域 3" : "Expansion Board Area 3";
  4683:     }
  4684:     //リード
  4685:     @Override protected int mmdRbz (int a) throws M68kException {
  4686:        a &= XEiJ.BUS_MOTHER_MASK;
  4687:        if (XEiJ.currentAccelerator == XEiJ.ACCELERATOR_XELLENT30 &&
  4688:            XEiJ.xt3PortAddress <= a && a < XEiJ.xt3PortAddress + 0x4000) {  //Xellent30設定ポート
  4689:          return (a & 1) == 0 ? 0 : XEiJ.xt3PortRead ();
  4690:        }
  4691:        if (MercuryUnit.MU4_ON && MercuryUnit.mu4On &&
  4692:            (a & 0x00ffff80) == 0x00ecc080) {  //Mercury-Unit V4
  4693:          return MercuryUnit.mu4ReadByte (a);
  4694:        }
  4695:        return super.mmdRbz (a);  //バスエラー
  4696:      }
  4697:     @Override protected int mmdRwz (int a) throws M68kException {
  4698:        a &= XEiJ.BUS_MOTHER_MASK;
  4699:        if (XEiJ.currentAccelerator == XEiJ.ACCELERATOR_XELLENT30 &&
  4700:            XEiJ.xt3PortAddress <= a && a < XEiJ.xt3PortAddress + 0x4000) {  //Xellent30設定ポート
  4701:          return XEiJ.xt3PortRead ();
  4702:        }
  4703:        if (MercuryUnit.MU4_ON && MercuryUnit.mu4On &&
  4704:            (a & 0x00ffff80) == 0x00ecc080) {  //Mercury-Unit V4
  4705:          return MercuryUnit.mu4ReadWord (a);
  4706:        }
  4707:        return super.mmdRwz (a);  //バスエラー
  4708:      }
  4709:     @Override protected int mmdRls (int a) throws M68kException {
  4710:        a &= XEiJ.BUS_MOTHER_MASK;
  4711:        if (XEiJ.currentAccelerator == XEiJ.ACCELERATOR_XELLENT30 &&
  4712:            XEiJ.xt3PortAddress <= a && a < XEiJ.xt3PortAddress + 0x4000) {  //Xellent30設定ポート
  4713:          return XEiJ.xt3PortRead () << 16 | XEiJ.xt3PortRead ();
  4714:        }
  4715:        if (MercuryUnit.MU4_ON && MercuryUnit.mu4On &&
  4716:            (a & 0x00ffff80) == 0x00ecc080) {  //Mercury-Unit V4
  4717:          return MercuryUnit.mu4ReadWord (a) << 16 | MercuryUnit.mu4ReadWord (a + 2);
  4718:        }
  4719:        return super.mmdRls (a);  //バスエラー
  4720:      }
  4721:     @Override protected void mmdWb (int a, int d) throws M68kException {
  4722:        a &= XEiJ.BUS_MOTHER_MASK;
  4723:        if (XEiJ.currentAccelerator == XEiJ.ACCELERATOR_XELLENT30 &&
  4724:            XEiJ.xt3PortAddress <= a && a < XEiJ.xt3PortAddress + 0x4000) {  //Xellent30設定ポート
  4725:          if ((a & 1) == 0) {
  4726:          } else {
  4727:            XEiJ.xt3PortWrite (d);
  4728:          }
  4729:          return;
  4730:        }
  4731:        if (MercuryUnit.MU4_ON && MercuryUnit.mu4On &&
  4732:            (a & 0x00ffff80) == 0x00ecc080) {  //Mercury-Unit V4
  4733:          MercuryUnit.mu4WriteByte (a, d);
  4734:          return;
  4735:        }
  4736:        super.mmdWb (a, d);  //バスエラー
  4737:      }
  4738:     @Override protected void mmdWw (int a, int d) throws M68kException {
  4739:        a &= XEiJ.BUS_MOTHER_MASK;
  4740:        if (XEiJ.currentAccelerator == XEiJ.ACCELERATOR_XELLENT30 &&
  4741:            XEiJ.xt3PortAddress <= a && a < XEiJ.xt3PortAddress + 0x4000) {  //Xellent30設定ポート
  4742:          XEiJ.xt3PortWrite (d);
  4743:          return;
  4744:        }
  4745:        if (MercuryUnit.MU4_ON && MercuryUnit.mu4On &&
  4746:            (a & 0x00ffff80) == 0x00ecc080) {  //Mercury-Unit V4
  4747:          MercuryUnit.mu4WriteWord (a, d);
  4748:          return;
  4749:        }
  4750:        super.mmdWw (a, d);  //バスエラー
  4751:      }
  4752:     @Override protected void mmdWl (int a, int d) throws M68kException {
  4753:        a &= XEiJ.BUS_MOTHER_MASK;
  4754:        if (XEiJ.currentAccelerator == XEiJ.ACCELERATOR_XELLENT30 &&
  4755:            XEiJ.xt3PortAddress <= a && a < XEiJ.xt3PortAddress + 0x4000) {  //Xellent30設定ポート
  4756:          XEiJ.xt3PortWrite (d >> 16);
  4757:          XEiJ.xt3PortWrite (d);
  4758:          return;
  4759:        }
  4760:        if (MercuryUnit.MU4_ON && MercuryUnit.mu4On &&
  4761:            (a & 0x00ffff80) == 0x00ecc080) {  //Mercury-Unit V4
  4762:          MercuryUnit.mu4WriteWord (a, d >> 16);
  4763:          MercuryUnit.mu4WriteWord (a + 2, d);
  4764:          return;
  4765:        }
  4766:        super.mmdWl (a, d);  //バスエラー
  4767:      }
  4768:   },  //MMD_XB3
  4769: 
  4770:   //--------------------------------------------------------------------------------
  4771:   //MMD_XTM Xellent30のSRAM
  4772:   MMD_XTM {
  4773:     @Override public String toString () {
  4774:       return Multilingual.mlnJapanese ? "Xellent30 の SRAM" : "SRAM on Xellent30";
  4775:     }
  4776:     //ピーク
  4777:     @Override protected byte mmdPbs (int a) {
  4778:       a -= XEiJ.xt3MemoryPosition;
  4779:       return XEiJ.xt3MemoryArray[a];
  4780:     }
  4781:     @Override protected int mmdPbz (int a) {
  4782:       a -= XEiJ.xt3MemoryPosition;
  4783:       return XEiJ.xt3MemoryArray[a] & 0xff;
  4784:     }
  4785:     @Override protected int mmdPws (int a) {
  4786:       a -= XEiJ.xt3MemoryPosition;
  4787:       return XEiJ.xt3MemoryArray[a] << 8 | (XEiJ.xt3MemoryArray[a + 1] & 0xff);
  4788:     }
  4789:     @Override protected int mmdPwz (int a) {
  4790:       a -= XEiJ.xt3MemoryPosition;
  4791:       return (char) (XEiJ.xt3MemoryArray[a] << 8 | (XEiJ.xt3MemoryArray[a + 1] & 0xff));
  4792:     }
  4793:     @Override protected int mmdPls (int a) {
  4794:       a -= XEiJ.xt3MemoryPosition;
  4795:       return XEiJ.xt3MemoryArray[a] << 24 | (XEiJ.xt3MemoryArray[a + 1] & 0xff) << 16 | (char) (XEiJ.xt3MemoryArray[a + 2] << 8 | (XEiJ.xt3MemoryArray[a + 3] & 0xff));
  4796:     }
  4797:     //リード
  4798:     @Override protected byte mmdRbs (int a) throws M68kException {
  4799:        a -= XEiJ.xt3MemoryPosition;
  4800:        return XEiJ.xt3MemoryArray[a];
  4801:      }
  4802:     @Override protected int mmdRbz (int a) throws M68kException {
  4803:        a -= XEiJ.xt3MemoryPosition;
  4804:        return XEiJ.xt3MemoryArray[a] & 0xff;
  4805:      }
  4806:     @Override protected int mmdRws (int a) throws M68kException {
  4807:        a -= XEiJ.xt3MemoryPosition;
  4808:        return XEiJ.xt3MemoryArray[a] << 8 | (XEiJ.xt3MemoryArray[a + 1] & 0xff);
  4809:      }
  4810:     @Override protected int mmdRwz (int a) throws M68kException {
  4811:        a -= XEiJ.xt3MemoryPosition;
  4812:        return (char) (XEiJ.xt3MemoryArray[a] << 8 | (XEiJ.xt3MemoryArray[a + 1] & 0xff));
  4813:      }
  4814:     @Override protected int mmdRls (int a) throws M68kException {
  4815:        a -= XEiJ.xt3MemoryPosition;
  4816:        return XEiJ.xt3MemoryArray[a] << 24 | (XEiJ.xt3MemoryArray[a + 1] & 0xff) << 16 | (char) (XEiJ.xt3MemoryArray[a + 2] << 8 | (XEiJ.xt3MemoryArray[a + 3] & 0xff));
  4817:      }
  4818:     //ライト
  4819:     @Override protected void mmdWb (int a, int d) throws M68kException {
  4820:        a -= XEiJ.xt3MemoryPosition;
  4821:        XEiJ.xt3MemoryArray[a    ] = (byte)  d;
  4822:      }
  4823:     @Override protected void mmdWw (int a, int d) throws M68kException {
  4824:        a -= XEiJ.xt3MemoryPosition;
  4825:        XEiJ.xt3MemoryArray[a    ] = (byte) (d >> 8);
  4826:        XEiJ.xt3MemoryArray[a + 1] = (byte)  d;
  4827:      }
  4828:     @Override protected void mmdWl (int a, int d) throws M68kException {
  4829:        a -= XEiJ.xt3MemoryPosition;
  4830:        XEiJ.xt3MemoryArray[a    ] = (byte) (d >> 24);
  4831:        XEiJ.xt3MemoryArray[a + 1] = (byte) (d >> 16);
  4832:        XEiJ.xt3MemoryArray[a + 2] = (byte) (d >> 8);
  4833:        XEiJ.xt3MemoryArray[a + 3] = (byte)  d;
  4834:      }
  4835:   },  //MMD_XTM
  4836: 
  4837:   //--------------------------------------------------------------------------------
  4838:   //MMD_SMR SRAM
  4839:   MMD_SMR {
  4840:     @Override public String toString () {
  4841:       return Multilingual.mlnJapanese ? "SRAM" : "SRAM";
  4842:     }
  4843:     //ピーク
  4844:     @Override protected byte mmdPbs (int a) {
  4845:       a &= XEiJ.BUS_MOTHER_MASK;
  4846:       return MainMemory.mmrM8[a];
  4847:     }
  4848:     @Override protected int mmdPbz (int a) {
  4849:       a &= XEiJ.BUS_MOTHER_MASK;
  4850:       return MainMemory.mmrM8[a] & 0xff;
  4851:     }
  4852:     @Override protected int mmdPws (int a) {
  4853:       a &= XEiJ.BUS_MOTHER_MASK;
  4854:       if (MainMemory.MMR_USE_BYTE_BUFFER) {
  4855:         return MainMemory.mmrBuffer.getShort (a);
  4856:       } else {
  4857:         return MainMemory.mmrM8[a] << 8 | (MainMemory.mmrM8[a + 1] & 0xff);
  4858:       }
  4859:     }
  4860:     @Override protected int mmdPwz (int a) {
  4861:       a &= XEiJ.BUS_MOTHER_MASK;
  4862:       if (MainMemory.MMR_USE_BYTE_BUFFER) {
  4863:         return MainMemory.mmrBuffer.getChar (a);
  4864:       } else {
  4865:         return (char) (MainMemory.mmrM8[a] << 8 | (MainMemory.mmrM8[a + 1] & 0xff));
  4866:       }
  4867:     }
  4868:     @Override protected int mmdPls (int a) {
  4869:       a &= XEiJ.BUS_MOTHER_MASK;
  4870:       if (MainMemory.MMR_USE_BYTE_BUFFER) {
  4871:         return MainMemory.mmrBuffer.getInt (a);
  4872:       } else {
  4873:         return MainMemory.mmrM8[a] << 24 | (MainMemory.mmrM8[a + 1] & 0xff) << 16 | (char) (MainMemory.mmrM8[a + 2] << 8 | (MainMemory.mmrM8[a + 3] & 0xff));
  4874:       }
  4875:     }
  4876:     //リード
  4877:     @Override protected byte mmdRbs (int a) throws M68kException {
  4878:        XEiJ.mpuClockTime += XEiJ.busWaitTime.sram;
  4879:        a &= XEiJ.BUS_MOTHER_MASK;
  4880:        XEiJ.mpuClockTime += XEiJ.busWaitTime.sram;
  4881:        return MainMemory.mmrM8[a];
  4882:      }
  4883:     @Override protected int mmdRbz (int a) throws M68kException {
  4884:        XEiJ.mpuClockTime += XEiJ.busWaitTime.sram;
  4885:        a &= XEiJ.BUS_MOTHER_MASK;
  4886:        XEiJ.mpuClockTime += XEiJ.busWaitTime.sram;
  4887:        return MainMemory.mmrM8[a] & 0xff;
  4888:      }
  4889:     @Override protected int mmdRws (int a) throws M68kException {
  4890:        return (short) mmdRwz (a);
  4891:      }
  4892:     @Override protected int mmdRwz (int a) throws M68kException {
  4893:        XEiJ.mpuClockTime += XEiJ.busWaitTime.sram;
  4894:        a &= XEiJ.BUS_MOTHER_MASK;
  4895:        XEiJ.mpuClockTime += XEiJ.busWaitTime.sram;
  4896:        int d;
  4897:        if (MainMemory.MMR_USE_BYTE_BUFFER) {
  4898:          d = MainMemory.mmrBuffer.getChar (a);
  4899:        } else {
  4900:          d = (char) (MainMemory.mmrM8[a] << 8 | (MainMemory.mmrM8[a + 1] & 0xff));
  4901:        }
  4902:        return d;
  4903:      }
  4904:     @Override protected int mmdRls (int a) throws M68kException {
  4905:        XEiJ.mpuClockTime += XEiJ.busWaitTime.sram * 2;
  4906:        a &= XEiJ.BUS_MOTHER_MASK;
  4907:        XEiJ.mpuClockTime += XEiJ.busWaitTime.sram * 2;
  4908:        int d;
  4909:        if (MainMemory.MMR_USE_BYTE_BUFFER) {
  4910:          d = MainMemory.mmrBuffer.getInt (a);
  4911:        } else {
  4912:          d = MainMemory.mmrM8[a] << 24 | (MainMemory.mmrM8[a + 1] & 0xff) << 16 | (char) (MainMemory.mmrM8[a + 2] << 8 | (MainMemory.mmrM8[a + 3] & 0xff));
  4913:        }
  4914:        return d;
  4915:      }
  4916:     //ライト
  4917:     @Override protected void mmdWb (int a, int d) throws M68kException {
  4918:        XEiJ.mpuClockTime += XEiJ.busWaitTime.sram;
  4919:        if (SRAM.smrWriteEnableOn) {
  4920:          a &= XEiJ.BUS_MOTHER_MASK;
  4921:          XEiJ.mpuClockTime += XEiJ.busWaitTime.sram;
  4922:          MainMemory.mmrM8[a] = (byte) d;
  4923:          if (a == 0x00ed002b || a == 0x00ed0059) {  //キーボードの配列または字体が変化した
  4924:            Keyboard.kbdRepaint ();  //キーボードが表示されているときkbdImageを作り直して再描画する
  4925:          } else if (a == 0x00ed005a) {  //HDMAX
  4926:            if (0x00fe0000 <= XEiJ.regPC0 && XEiJ.regPC0 <= 0x00ffffff) {  //IPLROMがSRAMのHDMAXを書き換えようとしている 
  4927:              SRAM.smrOverride ();  //SRAMの設定を上書きする
  4928:            }
  4929:          }
  4930:        } else {
  4931:          System.out.printf ("%08X writing $%02X to $%08X in a write-protected state\n", XEiJ.regPC0, d & 0xff, a);
  4932:          if (SRAM.smrSRAMBusErrorOn) {
  4933:            super.mmdWb (a, d);  //バスエラー
  4934:          }
  4935:        }
  4936:      }
  4937:     @Override protected void mmdWw (int a, int d) throws M68kException {
  4938:        XEiJ.mpuClockTime += XEiJ.busWaitTime.sram;
  4939:        if (SRAM.smrWriteEnableOn) {
  4940:          a &= XEiJ.BUS_MOTHER_MASK;
  4941:          XEiJ.mpuClockTime += XEiJ.busWaitTime.sram;
  4942:          MainMemory.mmrM8[a    ] = (byte) (d >> 8);
  4943:          MainMemory.mmrM8[a + 1] = (byte)  d;
  4944:          if (a == (0x00ed002b & -2) || a == (0x00ed0059 & -2)) {  //キーボードの配列または字体が変化した
  4945:            Keyboard.kbdRepaint ();  //キーボードが表示されているときkbdImageを作り直して再描画する
  4946:          }
  4947:        } else {
  4948:          System.out.printf ("%08X writing $%04X to $%08X in a write-protected state\n", XEiJ.regPC0, d & 0xffff, a);
  4949:          if (SRAM.smrSRAMBusErrorOn) {
  4950:            super.mmdWw (a, d);  //バスエラー
  4951:          }
  4952:        }
  4953:      }
  4954:     @Override protected void mmdWl (int a, int d) throws M68kException {
  4955:        if (SRAM.smrWriteEnableOn) {
  4956:          mmdWw (a    , d >> 16);
  4957:          mmdWw (a + 2, d      );
  4958:        } else {
  4959:          System.out.printf ("%08X writing $%08X to $%08X in a write-protected state\n", XEiJ.regPC0, d, a);
  4960:          if (SRAM.smrSRAMBusErrorOn) {
  4961:            super.mmdWl (a, d);  //バスエラー
  4962:          }
  4963:        }
  4964:      }
  4965:   },  //MMD_SMR
  4966: 
  4967:   //--------------------------------------------------------------------------------
  4968:   //MMD_XB4 拡張ボード領域4
  4969:   //  $00EE0000~$00EFFFFF  バンクメモリ
  4970:   MMD_XB4 {
  4971:     @Override public String toString () {
  4972:       return Multilingual.mlnJapanese ? "拡張ボード領域 4" : "Expansion Board Area 4";
  4973:     }
  4974:     //リード
  4975:     @Override protected byte mmdRbs (int a) throws M68kException {
  4976:        if (XEiJ.bnkOn) {
  4977:          a &= XEiJ.BUS_MOTHER_MASK;
  4978:          a = XEiJ.bnkPageStart + (a - 0x00ee0000);
  4979:          return XEiJ.bnkMemory[a];
  4980:        }
  4981:        return super.mmdRbs (a);  //バスエラー
  4982:      }
  4983:     @Override protected int mmdRbz (int a) throws M68kException {
  4984:        if (XEiJ.bnkOn) {
  4985:          a &= XEiJ.BUS_MOTHER_MASK;
  4986:          a = XEiJ.bnkPageStart + (a - 0x00ee0000);
  4987:          return XEiJ.bnkMemory[a] & 0xff;
  4988:        }
  4989:        return super.mmdRbz (a);  //バスエラー
  4990:      }
  4991:     @Override protected int mmdRws (int a) throws M68kException {
  4992:        if (XEiJ.bnkOn) {
  4993:          a &= XEiJ.BUS_MOTHER_MASK;
  4994:          a = XEiJ.bnkPageStart + (a - 0x00ee0000);
  4995:          return ((XEiJ.bnkMemory[a    ]       ) << 8 |
  4996:                  (XEiJ.bnkMemory[a + 1] & 0xff));
  4997:        }
  4998:        return super.mmdRws (a);  //バスエラー
  4999:      }
  5000:     @Override protected int mmdRwz (int a) throws M68kException {
  5001:        if (XEiJ.bnkOn) {
  5002:          a &= XEiJ.BUS_MOTHER_MASK;
  5003:          a = XEiJ.bnkPageStart + (a - 0x00ee0000);
  5004:          return ((XEiJ.bnkMemory[a    ] & 0xff) << 8 |
  5005:                  (XEiJ.bnkMemory[a + 1] & 0xff));
  5006:        }
  5007:        return super.mmdRwz (a);  //バスエラー
  5008:      }
  5009:     @Override protected int mmdRls (int a) throws M68kException {
  5010:        if (XEiJ.bnkOn) {
  5011:          a &= XEiJ.BUS_MOTHER_MASK;
  5012:          a = XEiJ.bnkPageStart + (a - 0x00ee0000);
  5013:          return ((XEiJ.bnkMemory[a    ]       ) << 24 |
  5014:                  (XEiJ.bnkMemory[a + 1] & 0xff) << 16 |
  5015:                  (XEiJ.bnkMemory[a + 2] & 0xff) <<  8 |
  5016:                  (XEiJ.bnkMemory[a + 3] & 0xff));
  5017:        }
  5018:        return super.mmdRls (a);  //バスエラー
  5019:      }
  5020:     //ライト
  5021:     @Override protected void mmdWb (int a, int d) throws M68kException {
  5022:        if (XEiJ.bnkOn) {
  5023:          a &= XEiJ.BUS_MOTHER_MASK;
  5024:          a = XEiJ.bnkPageStart + (a - 0x00ee0000);
  5025:          XEiJ.bnkMemory[a] = (byte) d;
  5026:          return;
  5027:        }
  5028:        super.mmdWb (a, d);  //バスエラー
  5029:      }
  5030:     @Override protected void mmdWw (int a, int d) throws M68kException {
  5031:        if (XEiJ.bnkOn) {
  5032:          a &= XEiJ.BUS_MOTHER_MASK;
  5033:          a = XEiJ.bnkPageStart + (a - 0x00ee0000);
  5034:          XEiJ.bnkMemory[a    ] = (byte) (d >> 8);
  5035:          XEiJ.bnkMemory[a + 1] = (byte)  d;
  5036:          return;
  5037:        }
  5038:        super.mmdWw (a, d);  //バスエラー
  5039:      }
  5040:     @Override protected void mmdWl (int a, int d) throws M68kException {
  5041:        if (XEiJ.bnkOn) {
  5042:          a &= XEiJ.BUS_MOTHER_MASK;
  5043:          a = XEiJ.bnkPageStart + (a - 0x00ee0000);
  5044:          XEiJ.bnkMemory[a    ] = (byte) (d >> 24);
  5045:          XEiJ.bnkMemory[a + 1] = (byte) (d >> 16);
  5046:          XEiJ.bnkMemory[a + 2] = (byte) (d >>  8);
  5047:          XEiJ.bnkMemory[a + 3] = (byte)  d;
  5048:          return;
  5049:        }
  5050:        super.mmdWl (a, d);  //バスエラー
  5051:      }
  5052:   },  //MMD_XB4
  5053: 
  5054:   //--------------------------------------------------------------------------------
  5055:   //MMD_ROM ROM
  5056:   MMD_ROM {
  5057:     @Override public String toString () {
  5058:       return Multilingual.mlnJapanese ? "ROM" : "ROM";
  5059:     }
  5060:     //ピーク
  5061:     @Override protected byte mmdPbs (int a) {
  5062:       a &= XEiJ.BUS_MOTHER_MASK;
  5063:       return MainMemory.mmrM8[a];
  5064:     }
  5065:     @Override protected int mmdPbz (int a) {
  5066:       a &= XEiJ.BUS_MOTHER_MASK;
  5067:       return MainMemory.mmrM8[a] & 0xff;
  5068:     }
  5069:     @Override protected int mmdPws (int a) {
  5070:       a &= XEiJ.BUS_MOTHER_MASK;
  5071:       if (MainMemory.MMR_USE_BYTE_BUFFER) {
  5072:         return MainMemory.mmrBuffer.getShort (a);
  5073:       } else {
  5074:         return MainMemory.mmrM8[a] << 8 | (MainMemory.mmrM8[a + 1] & 0xff);
  5075:       }
  5076:     }
  5077:     @Override protected int mmdPwz (int a) {
  5078:       a &= XEiJ.BUS_MOTHER_MASK;
  5079:       if (MainMemory.MMR_USE_BYTE_BUFFER) {
  5080:         return MainMemory.mmrBuffer.getChar (a);
  5081:       } else {
  5082:         return (char) (MainMemory.mmrM8[a] << 8 | (MainMemory.mmrM8[a + 1] & 0xff));
  5083:       }
  5084:     }
  5085:     @Override protected int mmdPls (int a) {
  5086:       a &= XEiJ.BUS_MOTHER_MASK;
  5087:       if (MainMemory.MMR_USE_BYTE_BUFFER) {
  5088:         return MainMemory.mmrBuffer.getInt (a);
  5089:       } else {
  5090:         return MainMemory.mmrM8[a] << 24 | (MainMemory.mmrM8[a + 1] & 0xff) << 16 | (char) (MainMemory.mmrM8[a + 2] << 8 | (MainMemory.mmrM8[a + 3] & 0xff));
  5091:       }
  5092:     }
  5093:     //リード
  5094:     @Override protected byte mmdRbs (int a) throws M68kException {
  5095:        XEiJ.mpuClockTime += XEiJ.busWaitTime.rom;
  5096:        a &= XEiJ.BUS_MOTHER_MASK;
  5097:        return MainMemory.mmrM8[a];
  5098:      }
  5099:     @Override protected int mmdRbz (int a) throws M68kException {
  5100:        XEiJ.mpuClockTime += XEiJ.busWaitTime.rom;
  5101:        a &= XEiJ.BUS_MOTHER_MASK;
  5102:        return MainMemory.mmrM8[a] & 0xff;
  5103:      }
  5104:     @Override protected int mmdRws (int a) throws M68kException {
  5105:        XEiJ.mpuClockTime += XEiJ.busWaitTime.rom;
  5106:        a &= XEiJ.BUS_MOTHER_MASK;
  5107:        if (MainMemory.MMR_USE_BYTE_BUFFER) {
  5108:          return MainMemory.mmrBuffer.getShort (a);
  5109:        } else {
  5110:          return MainMemory.mmrM8[a] << 8 | (MainMemory.mmrM8[a + 1] & 0xff);
  5111:        }
  5112:      }
  5113:     @Override protected int mmdRwz (int a) throws M68kException {
  5114:        XEiJ.mpuClockTime += XEiJ.busWaitTime.rom;
  5115:        a &= XEiJ.BUS_MOTHER_MASK;
  5116:        if (MainMemory.MMR_USE_BYTE_BUFFER) {
  5117:          return MainMemory.mmrBuffer.getChar (a);
  5118:        } else {
  5119:          return (char) (MainMemory.mmrM8[a] << 8 | (MainMemory.mmrM8[a + 1] & 0xff));
  5120:        }
  5121:      }
  5122:     @Override protected int mmdRls (int a) throws M68kException {
  5123:        XEiJ.mpuClockTime += XEiJ.busWaitTime.romlong;
  5124:        a &= XEiJ.BUS_MOTHER_MASK;
  5125:        if (MainMemory.MMR_USE_BYTE_BUFFER) {
  5126:          return MainMemory.mmrBuffer.getInt (a);
  5127:        } else {
  5128:          return MainMemory.mmrM8[a] << 24 | (MainMemory.mmrM8[a + 1] & 0xff) << 16 | (char) (MainMemory.mmrM8[a + 2] << 8 | (MainMemory.mmrM8[a + 3] & 0xff));
  5129:        }
  5130:      }
  5131:   },  //MMD_ROM
  5132: 
  5133:   MMD_RO6 {
  5134:     @Override public String toString () {
  5135:       return Multilingual.mlnJapanese ? "ROM (68060)" : "ROM (68060)";
  5136:     }
  5137:     //ピーク
  5138:     @Override protected byte mmdPbs (int a) {
  5139:       a &= XEiJ.BUS_MOTHER_MASK;
  5140:       return MainMemory.mmrM8[a];
  5141:     }
  5142:     @Override protected int mmdPbz (int a) {
  5143:       a &= XEiJ.BUS_MOTHER_MASK;
  5144:       return MainMemory.mmrM8[a] & 0xff;
  5145:     }
  5146:     @Override protected int mmdPws (int a) {
  5147:       a &= XEiJ.BUS_MOTHER_MASK;
  5148:       if (MainMemory.MMR_USE_BYTE_BUFFER) {
  5149:         return MainMemory.mmrBuffer.getShort (a);
  5150:       } else {
  5151:         return MainMemory.mmrM8[a] << 8 | (MainMemory.mmrM8[a + 1] & 0xff);
  5152:       }
  5153:     }
  5154:     @Override protected int mmdPwz (int a) {
  5155:       a &= XEiJ.BUS_MOTHER_MASK;
  5156:       if (MainMemory.MMR_USE_BYTE_BUFFER) {
  5157:         return MainMemory.mmrBuffer.getChar (a);
  5158:       } else {
  5159:         return (char) (MainMemory.mmrM8[a] << 8 | (MainMemory.mmrM8[a + 1] & 0xff));
  5160:       }
  5161:     }
  5162:     @Override protected int mmdPls (int a) {
  5163:       a &= XEiJ.BUS_MOTHER_MASK;
  5164:       if (MainMemory.MMR_USE_BYTE_BUFFER) {
  5165:         return MainMemory.mmrBuffer.getInt (a);
  5166:       } else {
  5167:         return MainMemory.mmrM8[a] << 24 | (MainMemory.mmrM8[a + 1] & 0xff) << 16 | (char) (MainMemory.mmrM8[a + 2] << 8 | (MainMemory.mmrM8[a + 3] & 0xff));
  5168:       }
  5169:     }
  5170:     //リード
  5171:     @Override protected byte mmdRbs (int a) throws M68kException {
  5172:        if (MC68060.CAT_ON &&
  5173:            !XEiJ.busWaitTime.isDma) {
  5174:          MC68060.catReadMainROM (a);
  5175:        } else {
  5176:          XEiJ.mpuClockTime += XEiJ.busWaitTime.rom;
  5177:        }
  5178:        a &= XEiJ.BUS_MOTHER_MASK;
  5179:        return MainMemory.mmrM8[a];
  5180:      }
  5181:     @Override protected int mmdRbz (int a) throws M68kException {
  5182:        if (MC68060.CAT_ON &&
  5183:            !XEiJ.busWaitTime.isDma) {
  5184:          MC68060.catReadMainROM (a);
  5185:        } else {
  5186:          XEiJ.mpuClockTime += XEiJ.busWaitTime.rom;
  5187:        }
  5188:        a &= XEiJ.BUS_MOTHER_MASK;
  5189:        return MainMemory.mmrM8[a] & 0xff;
  5190:      }
  5191:     @Override protected int mmdRws (int a) throws M68kException {
  5192:        if (MC68060.CAT_ON &&
  5193:            !XEiJ.busWaitTime.isDma) {
  5194:          MC68060.catReadMainROM (a);
  5195:        } else {
  5196:          XEiJ.mpuClockTime += XEiJ.busWaitTime.rom;
  5197:        }
  5198:        a &= XEiJ.BUS_MOTHER_MASK;
  5199:        if (MainMemory.MMR_USE_BYTE_BUFFER) {
  5200:          return MainMemory.mmrBuffer.getShort (a);
  5201:        } else {
  5202:          return MainMemory.mmrM8[a] << 8 | (MainMemory.mmrM8[a + 1] & 0xff);
  5203:        }
  5204:      }
  5205:     @Override protected int mmdRwz (int a) throws M68kException {
  5206:        if (MC68060.CAT_ON &&
  5207:            !XEiJ.busWaitTime.isDma) {
  5208:          MC68060.catReadMainROM (a);
  5209:        } else {
  5210:          XEiJ.mpuClockTime += XEiJ.busWaitTime.rom;
  5211:        }
  5212:        a &= XEiJ.BUS_MOTHER_MASK;
  5213:        if (MainMemory.MMR_USE_BYTE_BUFFER) {
  5214:          return MainMemory.mmrBuffer.getChar (a);
  5215:        } else {
  5216:          return (char) (MainMemory.mmrM8[a] << 8 | (MainMemory.mmrM8[a + 1] & 0xff));
  5217:        }
  5218:      }
  5219:     @Override protected int mmdRls (int a) throws M68kException {
  5220:        if (MC68060.CAT_ON &&
  5221:            !XEiJ.busWaitTime.isDma) {
  5222:          MC68060.catReadMainROM (a);
  5223:        } else {
  5224:          XEiJ.mpuClockTime += XEiJ.busWaitTime.romlong;
  5225:        }
  5226:        a &= XEiJ.BUS_MOTHER_MASK;
  5227:        if (MainMemory.MMR_USE_BYTE_BUFFER) {
  5228:          return MainMemory.mmrBuffer.getInt (a);
  5229:        } else {
  5230:          return MainMemory.mmrM8[a] << 24 | (MainMemory.mmrM8[a + 1] & 0xff) << 16 | (char) (MainMemory.mmrM8[a + 2] << 8 | (MainMemory.mmrM8[a + 3] & 0xff));
  5231:        }
  5232:      }
  5233:   },  //MMD_RO6
  5234: 
  5235:   //--------------------------------------------------------------------------------
  5236:   //MMD_IBP 命令ブレークポイント
  5237:   MMD_IBP {
  5238:     @Override public String toString () {
  5239:       return Multilingual.mlnJapanese ? "命令ブレークポイント" : "Instruction Break Point";
  5240:     }
  5241:     @Override protected int mmdRwz (int a) throws M68kException {
  5242:        if (InstructionBreakPoint.IBP_ON) {
  5243:          InstructionBreakPoint.InstructionBreakRecord[] hashTable = InstructionBreakPoint.ibpHashTable;
  5244:          for (InstructionBreakPoint.InstructionBreakRecord r = hashTable[a >> 1 & InstructionBreakPoint.IBP_HASH_MASK];
  5245:               r != null;
  5246:               r = r.ibrNext) {  //同じ物理ハッシュコードを持つ命令ブレークポイントについて
  5247:            if (r.ibrPhysicalAddress == a) {  //命令ブレークポイントが設定されているとき
  5248:              if (r.ibrValue == r.ibrTarget) {  //現在値が目標値と一致しているとき
  5249:                if (r.ibrThreshold < 0) {  //インスタントのとき
  5250:                  InstructionBreakPoint.ibpRemove (r.ibrLogicalAddress, XEiJ.regSRS);  //取り除く
  5251:                  XEiJ.mpuContinue = true;  //ステップ実行を継続する
  5252:                } else if (r.ibrTarget < r.ibrThreshold) {  //インスタント化しているとき
  5253:                  r.ibrTarget = r.ibrThreshold;  //目標値を閾値に戻す
  5254:                  XEiJ.mpuContinue = true;  //ステップ実行を継続する
  5255:                } else {  //インスタントでなくインスタント化していないとき
  5256:                  if (r.ibrScriptElement != null &&  //スクリプトが指定されていて
  5257:                      r.ibrScriptElement.exlEval (ExpressionEvaluator.EVM_EXPRESSION).exlFloatValue.iszero ()) {  //条件が成立していないとき
  5258:                    break;  //続行する
  5259:                  }
  5260:                  r.ibrTarget++;  //目標値を増やす
  5261:                  XEiJ.mpuContinue = false;  //ステップ実行を継続しない
  5262:                }
  5263:                M68kException.m6eNumber = M68kException.M6E_INSTRUCTION_BREAK_POINT;  //命令ブレークポイントによる停止。XEiJ.mpuContinueを設定すること
  5264:                throw M68kException.m6eSignal;  //停止する
  5265:              } else {  //現在値が目標値と一致していないとき
  5266:                if (r.ibrWaitInstruction != null) {  //待機ポイントがあるとき
  5267:                  WaitInstruction.instruction = r.ibrWaitInstruction;  //待機命令を設定して
  5268:                  return XEiJ.EMX_OPCODE_EMXWAIT;  //返す
  5269:                }
  5270:                r.ibrValue++;  //現在値を増やす
  5271:                break;  //続行する
  5272:              }
  5273:            }
  5274:          }
  5275:        }
  5276:        if (DataBreakPoint.DBP_ON) {
  5277:          return DataBreakPoint.dbpMemoryMap[a >>> XEiJ.BUS_PAGE_BITS].mmdRwz (a);
  5278:        } else {
  5279:          return XEiJ.busMemoryMap[a >>> XEiJ.BUS_PAGE_BITS].mmdRwz (a);
  5280:        }
  5281:      }
  5282:   },  //MMD_IBP
  5283: 
  5284:   //--------------------------------------------------------------------------------
  5285:   //MMD_DBP データブレークポイント
  5286:   MMD_DBP {
  5287:     @Override public String toString () {
  5288:       return Multilingual.mlnJapanese ? "データブレークポイント" : "Data Break Point";
  5289:     }
  5290:     //ピーク
  5291:     @Override protected byte mmdPbs (int a) {
  5292:       return (XEiJ.regSRS != 0 ? XEiJ.busSuperMap : XEiJ.busUserMap)[a >>> XEiJ.BUS_PAGE_BITS].mmdPbs (a);
  5293:     }
  5294:     @Override protected int mmdPbz (int a) {
  5295:       return (XEiJ.regSRS != 0 ? XEiJ.busSuperMap : XEiJ.busUserMap)[a >>> XEiJ.BUS_PAGE_BITS].mmdPbz (a);
  5296:     }
  5297:     @Override protected int mmdPws (int a) {
  5298:       return (XEiJ.regSRS != 0 ? XEiJ.busSuperMap : XEiJ.busUserMap)[a >>> XEiJ.BUS_PAGE_BITS].mmdPws (a);
  5299:     }
  5300:     @Override protected int mmdPwz (int a) {
  5301:       return (XEiJ.regSRS != 0 ? XEiJ.busSuperMap : XEiJ.busUserMap)[a >>> XEiJ.BUS_PAGE_BITS].mmdPwz (a);
  5302:     }
  5303:     @Override protected int mmdPls (int a) {
  5304:       return (XEiJ.regSRS != 0 ? XEiJ.busSuperMap : XEiJ.busUserMap)[a >>> XEiJ.BUS_PAGE_BITS].mmdPls (a);
  5305:     }
  5306:     //リード
  5307:     @Override protected byte mmdRbs (int a) throws M68kException {
  5308:        int d = (XEiJ.regSRS != 0 ? XEiJ.busSuperMap : XEiJ.busUserMap)[a >>> XEiJ.BUS_PAGE_BITS].mmdRbs (a);
  5309:        DataBreakPoint.dbpBreak (DataBreakPoint.DBP_BYTE, a, d, false);
  5310:        return (byte) d;
  5311:      }
  5312:     @Override protected int mmdRbz (int a) throws M68kException {
  5313:        int d = (XEiJ.regSRS != 0 ? XEiJ.busSuperMap : XEiJ.busUserMap)[a >>> XEiJ.BUS_PAGE_BITS].mmdRbz (a);
  5314:        DataBreakPoint.dbpBreak (DataBreakPoint.DBP_BYTE, a, d, false);
  5315:        return d;
  5316:      }
  5317:     @Override protected int mmdRws (int a) throws M68kException {
  5318:        int d = (XEiJ.regSRS != 0 ? XEiJ.busSuperMap : XEiJ.busUserMap)[a >>> XEiJ.BUS_PAGE_BITS].mmdRws (a);
  5319:        DataBreakPoint.dbpBreak (DataBreakPoint.DBP_WORD, a, d, false);
  5320:        return d;
  5321:      }
  5322:     @Override protected int mmdRwz (int a) throws M68kException {
  5323:        int d = (XEiJ.regSRS != 0 ? XEiJ.busSuperMap : XEiJ.busUserMap)[a >>> XEiJ.BUS_PAGE_BITS].mmdRwz (a);
  5324:        DataBreakPoint.dbpBreak (DataBreakPoint.DBP_WORD, a, d, false);
  5325:        return d;
  5326:      }
  5327:     @Override protected int mmdRls (int a) throws M68kException {
  5328:        int d = (XEiJ.regSRS != 0 ? XEiJ.busSuperMap : XEiJ.busUserMap)[a >>> XEiJ.BUS_PAGE_BITS].mmdRls (a);
  5329:        DataBreakPoint.dbpBreak (DataBreakPoint.DBP_LONG, a, d, false);
  5330:        return d;
  5331:      }
  5332:     //ライト
  5333:     @Override protected void mmdWb (int a, int d) throws M68kException {
  5334:        (XEiJ.regSRS != 0 ? XEiJ.busSuperMap : XEiJ.busUserMap)[a >>> XEiJ.BUS_PAGE_BITS].mmdWb (a, d);
  5335:        DataBreakPoint.dbpBreak (DataBreakPoint.DBP_BYTE, a, d, true);
  5336:      }
  5337:     @Override protected void mmdWw (int a, int d) throws M68kException {
  5338:        (XEiJ.regSRS != 0 ? XEiJ.busSuperMap : XEiJ.busUserMap)[a >>> XEiJ.BUS_PAGE_BITS].mmdWw (a, d);
  5339:        DataBreakPoint.dbpBreak (DataBreakPoint.DBP_WORD, a, d, true);
  5340:      }
  5341:     @Override protected void mmdWl (int a, int d) throws M68kException {
  5342:        (XEiJ.regSRS != 0 ? XEiJ.busSuperMap : XEiJ.busUserMap)[a >>> XEiJ.BUS_PAGE_BITS].mmdWl (a, d);
  5343:        DataBreakPoint.dbpBreak (DataBreakPoint.DBP_LONG, a, d, true);
  5344:      }
  5345:   },  //MMD_DBP
  5346: 
  5347:   //--------------------------------------------------------------------------------
  5348:   //MMD_NUL ヌルデバイス
  5349:   MMD_NUL {
  5350:     @Override public String toString () {
  5351:       return Multilingual.mlnJapanese ? "ヌルデバイス" : "Null Device";
  5352:     }
  5353:   };  //MMD_NUL
  5354: 
  5355:   //--------------------------------------------------------------------------------
  5356:   //ピークのデフォルト
  5357:   //  エラーや副作用なしでリードする
  5358:   //  バスエラーのときは-1をキャストした値を返す
  5359:   //  リードがデバイスの状態を変化させる可能性がある場合は個別に処理すること
  5360:   protected byte mmdPbs (int a) {
  5361:     return (byte) mmdPbz (a);
  5362:   }
  5363:   protected int mmdPbz (int a) {
  5364:     try {
  5365:       return mmdRbz (a);
  5366:     } catch (M68kException e) {
  5367:     }
  5368:     return 0xff;
  5369:   }
  5370:   protected int mmdPws (int a) {
  5371:     return (short) mmdPwz (a);
  5372:   }
  5373:   protected int mmdPwz (int a) {
  5374:     try {
  5375:       return mmdRwz (a);
  5376:     } catch (M68kException e) {
  5377:     }
  5378:     return 0xffff;
  5379:   }
  5380:   protected int mmdPls (int a) {
  5381:     try {
  5382:       return mmdRls (a);
  5383:     } catch (M68kException e) {
  5384:     }
  5385:     return -1;
  5386:   }
  5387:   //リードのデフォルト
  5388:   //  バイトとワードの符号拡張はゼロ拡張を呼び出す
  5389:   //  符号なしとロングはバスエラー
  5390:   protected byte mmdRbs (int a) throws M68kException {
  5391:     return (byte) mmdRbz (a);
  5392:   }
  5393:   protected int mmdRbz (int a) throws M68kException {
  5394:     MC68060.m60BusErrorOnRead ();
  5395:     M68kException.m6eNumber = M68kException.M6E_ACCESS_FAULT;
  5396:     M68kException.m6eAddress = a;
  5397:     M68kException.m6eDirection = XEiJ.MPU_WR_READ;
  5398:     M68kException.m6eSize = XEiJ.MPU_SS_BYTE;
  5399:     throw M68kException.m6eSignal;
  5400:   }
  5401:   protected int mmdRws (int a) throws M68kException {
  5402:     return (short) mmdRwz (a);
  5403:   }
  5404:   protected int mmdRwz (int a) throws M68kException {
  5405:     MC68060.m60BusErrorOnRead ();
  5406:     M68kException.m6eNumber = M68kException.M6E_ACCESS_FAULT;
  5407:     M68kException.m6eAddress = a;
  5408:     M68kException.m6eDirection = XEiJ.MPU_WR_READ;
  5409:     M68kException.m6eSize = XEiJ.MPU_SS_WORD;
  5410:     throw M68kException.m6eSignal;
  5411:   }
  5412:   protected int mmdRls (int a) throws M68kException {
  5413:     MC68060.m60BusErrorOnRead ();
  5414:     M68kException.m6eNumber = M68kException.M6E_ACCESS_FAULT;
  5415:     M68kException.m6eAddress = a;
  5416:     M68kException.m6eDirection = XEiJ.MPU_WR_READ;
  5417:     M68kException.m6eSize = XEiJ.MPU_SS_LONG;
  5418:     throw M68kException.m6eSignal;
  5419:   }
  5420:   //ポークのデフォルト
  5421:   //  エラーや副作用なしでライトする
  5422:   //  ライトがデバイスの状態を変化させる可能性がある場合は個別に処理すること
  5423:   protected void mmdVb (int a, int d) {
  5424:     try {
  5425:       mmdWb (a, d);
  5426:     } catch (M68kException e) {
  5427:     }
  5428:   }
  5429:   protected void mmdVw (int a, int d) {
  5430:     try {
  5431:       mmdWw (a, d);
  5432:     } catch (M68kException e) {
  5433:     }
  5434:   }
  5435:   protected void mmdVl (int a, int d) {
  5436:     try {
  5437:       mmdWl (a, d);
  5438:     } catch (M68kException e) {
  5439:     }
  5440:   }
  5441:   //ライトのデフォルト
  5442:   //  すべてバスエラー
  5443:   protected void mmdWb (int a, int d) throws M68kException {
  5444:     MC68060.m60BusErrorOnWrite ();
  5445:     M68kException.m6eNumber = M68kException.M6E_ACCESS_FAULT;
  5446:     M68kException.m6eAddress = a;
  5447:     M68kException.m6eDirection = XEiJ.MPU_WR_WRITE;
  5448:     M68kException.m6eSize = XEiJ.MPU_SS_BYTE;
  5449:     throw M68kException.m6eSignal;
  5450:   }
  5451:   protected void mmdWw (int a, int d) throws M68kException {
  5452:     MC68060.m60BusErrorOnWrite ();
  5453:     M68kException.m6eNumber = M68kException.M6E_ACCESS_FAULT;
  5454:     M68kException.m6eAddress = a;
  5455:     M68kException.m6eDirection = XEiJ.MPU_WR_WRITE;
  5456:     M68kException.m6eSize = XEiJ.MPU_SS_WORD;
  5457:     throw M68kException.m6eSignal;
  5458:   }
  5459:   protected void mmdWl (int a, int d) throws M68kException {
  5460:     MC68060.m60BusErrorOnWrite ();
  5461:     M68kException.m6eNumber = M68kException.M6E_ACCESS_FAULT;
  5462:     M68kException.m6eAddress = a;
  5463:     M68kException.m6eDirection = XEiJ.MPU_WR_WRITE;
  5464:     M68kException.m6eSize = XEiJ.MPU_SS_LONG;
  5465:     throw M68kException.m6eSignal;
  5466:   }
  5467: }  //enum MemoryMappedDevice
  5468: 
  5469: 
  5470: