MainMemory.java
     1: //========================================================================================
     2: //  MainMemory.java
     3: //    en:Main memory
     4: //    ja:メインメモリ
     5: //  Copyright (C) 2003-2017 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: //  http://stdkmd.com/xeij/
    11: //========================================================================================
    12: 
    13: //----------------------------------------------------------------------------------------
    14: //データの格納単位
    15: //  配列の1要素に何バイトずつ格納するのが効率的か
    16: //    1バイトずつの場合
    17: //      + インデックスとアドレスが一致するので扱いやすい
    18: //      - ワードアクセスとロングアクセスの配列参照の回数が増えるのでインデックスの範囲チェックのオーバーヘッドが大きくなる
    19: //    2バイトずつの場合
    20: //      + アラインメントの合っているワードアクセスとロングアクセスの配列参照の回数が減る
    21: //      - ライトバイトはリードも必要になるので配列参照の回数が増える
    22: //      - インデックスを求めるときにアドレスをシフトしなければならない
    23: //      ? テキスト画面はアクセスマスクが16ビットだがCRTCのキャラクタが8ビット単位なので端数が生じることに変わりはない
    24: //      ? グラフィックス画面は1ピクセルが16ビットだがパレットが8ビット単位なので8ビットずつ分解しなければならないことに変わりはない
    25: //    4バイトずつの場合
    26: //      + アラインメントの合っているロングアクセスの配列参照の回数が減る
    27: //      - ライトバイトとライドワードはリードも必要になるので配列参照の回数が増える
    28: //      - インデックスを求めるときにアドレスをシフトしなければならない
    29: //----------------------------------------------------------------------------------------
    30: 
    31: package xeij;
    32: 
    33: import java.lang.*;  //Boolean,Character,Class,Comparable,Double,Exception,Float,IllegalArgumentException,Integer,Long,Math,Number,Object,Runnable,SecurityException,String,StringBuilder,System
    34: import java.nio.*;  //ByteBuffer,ByteOrder
    35: import java.util.*;  //ArrayList,Arrays,Calendar,GregorianCalendar,HashMap,Map,Map.Entry,Timer,TimerTask,TreeMap
    36: 
    37: public class MainMemory {
    38: 
    39:   public static final boolean MMR_USE_BYTE_BUFFER = false;  //true=ワードとロングのアクセスにバイトバッファを使う。遅くなる
    40: 
    41:   //メインメモリ
    42:   public static final byte[] mmrM8 = new byte[XEiJ.BUS_ARRAY_SIZE];
    43:   public static ByteBuffer mmrBuffer;  //mmrM8をラップしたバイトバッファ
    44: 
    45:   public static int mmrHumanVersion;  //Human68kのバージョン。-1=Human68kではない,0=未確認,0x0100/0x0101/0x0200/0x0201/0x0202/0x0203/0x020f/0x0301/0x0302=バージョン
    46:   public static boolean mmrFEfuncActivated;  //true=FEファンクション命令が有効になった
    47: 
    48:   //TwentyOne.xのオプション
    49:   public static int mmrTwentyOneOptionAddress;  //TwentyOne.xのオプションのアドレス,-1=非対応,0=未確認
    50: 
    51:   //メインメモリのサイズ
    52:   //  0x00100000  1MB
    53:   //  0x00200000  2MB
    54:   //  0x00400000  4MB
    55:   //  0x00600000  6MB
    56:   //  0x00800000  8MB
    57:   //  0x00a00000  10MB
    58:   //  0x00c00000  12MB
    59:   //  のいずれか
    60:   public static int mmrMemorySizeRequest;  //次回のリセット後のメインメモリのサイズ。メニューで設定を変更してからリセットするまでの間、現在のメインメモリのサイズと区別する必要がある
    61:   public static int mmrMemorySizeCurrent;  //現在のメインメモリのサイズ
    62: 
    63:   //  メインメモリの内容を保存する
    64:   //  レジュームできるわけではないがRAMディスクの内容を保存せずにエミュレータを終了しまったときに役立つ
    65:   //  設定ファイルが大きくなるので起動と終了がややもたつく
    66:   public static final boolean MMR_SAVE = true;  //true=メインメモリの内容を保存する
    67:   public static boolean mmrMemorySaveOn;  //true=メインメモリの内容を保存する。ローカルのときだけ有効
    68:   public static String mmrMemoryData;  //メインメモリの内容。-memorydata=gzip+base64
    69: 
    70:   //mmrInit ()
    71:   //  メインメモリを初期化する
    72:   public static void mmrInit () {
    73:     mmrMemorySizeCurrent = mmrMemorySizeRequest;
    74:     //mmrM8 = new byte[XEiJ.BUS_MOTHOR_SIZE];
    75:     if (MMR_USE_BYTE_BUFFER) {
    76:       mmrBuffer = ByteBuffer.wrap (mmrM8);
    77:       mmrBuffer.order (ByteOrder.BIG_ENDIAN);
    78:     }
    79:     XEiJ.busUser (MemoryMappedDevice.MMD_MMR, 0x00002000, mmrMemorySizeCurrent);
    80:     XEiJ.busUser (MemoryMappedDevice.MMD_NUL, mmrMemorySizeCurrent, 0x00c00000);
    81:     mmrHumanVersion = 0;
    82:     mmrFEfuncActivated = false;
    83:     if (HFS.HFS_USE_TWENTY_ONE) {
    84:       mmrTwentyOneOptionAddress = 0;
    85:     }
    86:     if (MMR_SAVE) {
    87:       if (mmrMemoryData != null && mmrMemoryData.length () != 0) {  //-memorysave=on -memorydata=gzip+base64が指定されたとき
    88:         if ("zero".equalsIgnoreCase (mmrMemoryData)) {
    89:           //ゼロクリアする
    90:           Arrays.fill (mmrM8, 0x00000000, 0x00c00000, (byte) 0);
    91:         } else {
    92:           //gzip+base64を解凍する
    93:           byte[] bb = ByteArray.byaDecodeGzip (ByteArray.byaDecodeBase64 (mmrMemoryData));
    94:           System.arraycopy (bb, 0, mmrM8, 0x00000000, Math.min (bb.length, mmrMemorySizeCurrent));
    95:         }
    96:       }
    97:     }
    98:   }  //mmrInit()
    99: 
   100:   public static void mmrReset () {
   101:     mmrMemorySizeCurrent = mmrMemorySizeRequest;
   102:     mmrHumanVersion = 0;
   103:     mmrFEfuncActivated = false;
   104:     if (HFS.HFS_USE_TWENTY_ONE) {
   105:       mmrTwentyOneOptionAddress = 0;
   106:     }
   107:   }  //mmrReset()
   108: 
   109:   //d = mmrRbs (a)
   110:   //  メモリリードバイト符号拡張
   111:   public static byte mmrRbs (int a) {
   112:     //byteの配列からbyteのデータを読み出す
   113:     //       a
   114:     //    +-----+
   115:     //    |  a  |
   116:     //    +-----+
   117:     //    |  d  |
   118:     //    +-----+
   119:     return mmrM8[a & XEiJ.BUS_MOTHER_MASK];
   120:   }  //mmrRbs(int)
   121: 
   122:   //d = mmrRbz (a)
   123:   //  メモリリードバイトゼロ拡張
   124:   public static int mmrRbz (int a) {
   125:     //byteの配列からbyteのデータを読み出す
   126:     //       a
   127:     //    +-----+
   128:     //    |  a  |
   129:     //    +-----+
   130:     //    |  d  |
   131:     //    +-----+
   132:     return mmrM8[a & XEiJ.BUS_MOTHER_MASK] & 255;
   133:   }  //mmrRbz(int)
   134: 
   135:   //d = mmrRws (a)
   136:   //  メモリリードワード符号拡張
   137:   public static int mmrRws (int a) {
   138:     if (MMR_USE_BYTE_BUFFER) {
   139:       return mmrBuffer.getShort (a & XEiJ.BUS_MOTHER_MASK);
   140:     } else {
   141:       //byteの配列からshortのデータを読み出す
   142:       //       a    a+1
   143:       //    +-----+-----+
   144:       //    |  a  | a+1 |
   145:       //    +-----+-----+
   146:       //    |     d     |
   147:       //    +-----+-----+
   148:       return mmrM8[a & XEiJ.BUS_MOTHER_MASK] << 8 | mmrM8[a + 1 & XEiJ.BUS_MOTHER_MASK] & 255;
   149:     }
   150:   }  //mmrRws(int)
   151: 
   152:   //d = mmrRwz (a)
   153:   //  メモリリードワードゼロ拡張
   154:   public static int mmrRwz (int a) {
   155:     if (MMR_USE_BYTE_BUFFER) {
   156:       return mmrBuffer.getChar (a & XEiJ.BUS_MOTHER_MASK);
   157:     } else {
   158:       //byteの配列からunsigned shortのデータを読み出す
   159:       //       a    a+1
   160:       //    +-----+-----+
   161:       //    |  a  | a+1 |
   162:       //    +-----+-----+
   163:       //    |     d     |
   164:       //    +-----+-----+
   165:       return (char) (mmrM8[a & XEiJ.BUS_MOTHER_MASK] << 8 | mmrM8[a + 1 & XEiJ.BUS_MOTHER_MASK] & 255);
   166:     }
   167:   }  //mmrRwz(int)
   168: 
   169:   //d = mmrRls (a)
   170:   //  メモリリードロング符号拡張
   171:   public static int mmrRls (int a) {
   172:     if (MMR_USE_BYTE_BUFFER) {
   173:       return mmrBuffer.getInt (a & XEiJ.BUS_MOTHER_MASK);
   174:     } else {
   175:       //byteの配列からintのデータを読み出す
   176:       //       a    a+1   a+2   a+3
   177:       //    +-----+-----+-----+-----+
   178:       //    |  a  | a+1 | a+2 | a+3 |
   179:       //    +-----+-----+-----+-----+
   180:       //    |           d           |
   181:       //    +-----+-----+-----+-----+
   182:       return mmrM8[a & XEiJ.BUS_MOTHER_MASK] << 24 | (mmrM8[a + 1 & XEiJ.BUS_MOTHER_MASK] & 255) << 16 | (char) (mmrM8[a + 2 & XEiJ.BUS_MOTHER_MASK] << 8 | mmrM8[a + 3 & XEiJ.BUS_MOTHER_MASK] & 255);
   183:     }
   184:   }  //mmrRls(int)
   185: 
   186:   //d = mmrRqs (a)
   187:   //  メモリリードクワッド符号拡張
   188:   public static long mmrRqs (int a) {
   189:     if (MMR_USE_BYTE_BUFFER) {
   190:       return mmrBuffer.getLong (a & XEiJ.BUS_MOTHER_MASK);
   191:     } else {
   192:       return ((long) (mmrM8[a     & XEiJ.BUS_MOTHER_MASK] << 24 |
   193:                       mmrM8[a + 1 & XEiJ.BUS_MOTHER_MASK] << 16 & 0x00ff0000 |
   194:                       mmrM8[a + 2 & XEiJ.BUS_MOTHER_MASK] <<  8 & 0x0000ff00 |
   195:                       mmrM8[a + 3 & XEiJ.BUS_MOTHER_MASK]       & 0x000000ff) << 32 |
   196:               (long) (mmrM8[a + 4 & XEiJ.BUS_MOTHER_MASK] << 24 |
   197:                       mmrM8[a + 5 & XEiJ.BUS_MOTHER_MASK] << 16 & 0x00ff0000 |
   198:                       mmrM8[a + 6 & XEiJ.BUS_MOTHER_MASK] <<  8 & 0x0000ff00 |
   199:                       mmrM8[a + 7 & XEiJ.BUS_MOTHER_MASK]       & 0x000000ff) & 0x00000000ffffffffL);
   200:     }
   201:   }  //mmrRqs(int)
   202: 
   203:   //mmrWb (a, d)
   204:   //  メモリライトバイト
   205:   public static void mmrWb (int a, int d) {
   206:     //byteの配列にbyteのデータを書き込む
   207:     //       a
   208:     //    +-----+
   209:     //    |  d  |
   210:     //    +-----+
   211:     //    |  a  |
   212:     //    +-----+
   213:     mmrM8[a & XEiJ.BUS_MOTHER_MASK] = (byte) d;
   214:   }  //mmrWb(int,int)
   215: 
   216:   //mmrWw (a, d)
   217:   //  メモリライトワード
   218:   public static void mmrWw (int a, int d) {
   219:     if (MMR_USE_BYTE_BUFFER) {
   220:       mmrBuffer.putShort (a & XEiJ.BUS_MOTHER_MASK, (short) d);
   221:     } else {
   222:       //byteの配列にshortのデータを書き込む
   223:       //       a    a+1
   224:       //    +-----+-----+
   225:       //    |     d     |
   226:       //    +-----+-----+
   227:       //    |  a  | a+1 |
   228:       //    +-----+-----+
   229:       mmrM8[a     & XEiJ.BUS_MOTHER_MASK] = (byte) (d >> 8);
   230:       mmrM8[a + 1 & XEiJ.BUS_MOTHER_MASK] = (byte)  d;
   231:     }
   232:   }  //mmrWw(int,int)
   233: 
   234:   //a = mmrWl (a, d)
   235:   //  メモリライトロング
   236:   public static void mmrWl (int a, int d) {
   237:     if (MMR_USE_BYTE_BUFFER) {
   238:       mmrBuffer.putInt (a & XEiJ.BUS_MOTHER_MASK, d);
   239:     } else {
   240:       //byteの配列にintのデータを書き込む
   241:       //       a    a+1   a+2   a+3
   242:       //    +-----+-----+-----+-----+
   243:       //    |           d           |
   244:       //    +-----+-----+-----+-----+
   245:       //    |  a  | a+1 | a+2 | a+3 |
   246:       //    +-----+-----+-----+-----+
   247:       mmrM8[a     & XEiJ.BUS_MOTHER_MASK] = (byte) (d >> 24);
   248:       mmrM8[a + 1 & XEiJ.BUS_MOTHER_MASK] = (byte) (d >> 16);
   249:       mmrM8[a + 2 & XEiJ.BUS_MOTHER_MASK] = (byte) (d >> 8);
   250:       mmrM8[a + 3 & XEiJ.BUS_MOTHER_MASK] = (byte)  d;
   251:     }
   252:   }  //mmrWl(int,int)
   253: 
   254:   //a = mmrWq (a, d)
   255:   //  メモリライトクワッド
   256:   public static void mmrWq (int a, long d) {
   257:     if (MMR_USE_BYTE_BUFFER) {
   258:       mmrBuffer.putLong (a & XEiJ.BUS_MOTHER_MASK, d);
   259:     } else {
   260:       mmrM8[a     & XEiJ.BUS_MOTHER_MASK] = (byte) (d >> 56);
   261:       mmrM8[a + 1 & XEiJ.BUS_MOTHER_MASK] = (byte) (d >> 48);
   262:       mmrM8[a + 2 & XEiJ.BUS_MOTHER_MASK] = (byte) (d >> 40);
   263:       mmrM8[a + 3 & XEiJ.BUS_MOTHER_MASK] = (byte) (d >> 32);
   264:       mmrM8[a + 4 & XEiJ.BUS_MOTHER_MASK] = (byte) (d >> 24);
   265:       mmrM8[a + 5 & XEiJ.BUS_MOTHER_MASK] = (byte) (d >> 16);
   266:       mmrM8[a + 6 & XEiJ.BUS_MOTHER_MASK] = (byte) (d >> 8);
   267:       mmrM8[a + 7 & XEiJ.BUS_MOTHER_MASK] = (byte)  d;
   268:     }
   269:   }  //mmrWq(int,long)
   270: 
   271:   //mmrWba (a, d, ...)
   272:   //  メモリライトバイトアレイ
   273:   public static void mmrWba (int a, int... da) {
   274:     for (int d : da) {
   275:       mmrWb (a, d);
   276:       a++;
   277:     }
   278:   }  //mmrWba(int,int...)
   279: 
   280:   //mmrWwa (a, d, ...)
   281:   //  メモリライトワードアレイ
   282:   public static void mmrWwa (int a, int... da) {
   283:     for (int d : da) {
   284:       mmrWw (a, d);
   285:       a += 2;
   286:     }
   287:   }  //mmrWwa(int,int...)
   288: 
   289:   //a = mmrWla (a, d, ...)
   290:   //  メモリライトロングアレイ
   291:   public static void mmrWla (int a, int... da) {
   292:     for (int d : da) {
   293:       mmrWl (a, d);
   294:       a += 4;
   295:     }
   296:   }  //mmrWla(int,int...)
   297: 
   298:   //len = mmrStrlen (a, l)
   299:   public static int mmrStrlen (int a, int l) {
   300:     for (int i = 0; i < l; i++) {
   301:       if (mmrM8[a + i] == 0) {
   302:         return i;
   303:       }
   304:     }
   305:     return l;
   306:   }  //mmrStrlen(int,int)
   307: 
   308:   //s = mmrRstr (a, l)
   309:   //sb = mmrRstr (sb, a, l)
   310:   //  メモリリードストリング
   311:   //  文字列を読み出す
   312:   //  対応する文字がないときは'.'または'※'になる
   313:   //  制御コードは'.'になる
   314:   public static String mmrRstr (int a, int l) {
   315:     return mmrRstr (new StringBuilder (), a, l).toString ();
   316:   }  //mmrRstr(int,int)
   317:   public static StringBuilder mmrRstr (StringBuilder sb, int a, int l) {
   318:     for (int i = 0; i < l; i++) {
   319:       int s = mmrRbz (a + i);
   320:       char c;
   321:       if (0x81 <= s && s <= 0x9f || 0xe0 <= s && s <= 0xef) {  //SJISの2バイトコードの1バイト目
   322:         int t = i + 1 < l ? mmrRbz (a + i + 1) : 0;
   323:         if (0x40 <= t && t != 0x7f && t <= 0xfc) {  //SJISの2バイトコードの2バイト目
   324:           c = CharacterCode.chrSJISToChar[s << 8 | t];  //2バイトで変換する
   325:           if (c == 0) {  //対応する文字がない
   326:             c = '※';
   327:           }
   328:           i++;
   329:         } else {  //SJISの2バイトコードの2バイト目ではない
   330:           c = '.';  //SJISの2バイトコードの1バイト目ではなかった
   331:         }
   332:       } else {  //SJISの2バイトコードの1バイト目ではない
   333:         c = CharacterCode.chrSJISToChar[s];  //1バイトで変換する
   334:         if (c < 0x20 || c == 0x7f) {  //対応する文字がないまたは制御コード
   335:           c = '.';
   336:         }
   337:       }
   338:       sb.append (c);
   339:     }
   340:     return sb;
   341:   }  //mmrRstr(StringBuilder,int,int)
   342: 
   343:   //a = mmrWstr (a, s)
   344:   //  メモリライトストリング
   345:   //  文字列をSJISに変換しながら書き込む
   346:   //  SJISに変換できない文字は'※'になる
   347:   //  文字列の直後のアドレス(マスク済み)を返す
   348:   public static void mmrWstr (int a, String s) {
   349:     int l = s.length ();
   350:     for (int i = 0; i < l; i++) {
   351:       int c = CharacterCode.chrCharToSJIS[s.charAt (i)];
   352:       if (c == 0 && s.charAt (i) != '\0') {  //SJISに変換できないとき'\0'でない文字が0になる
   353:         mmrWw (a, 0x81a6);  //※
   354:         a += 2;
   355:       } else if (c <= 0x00ff) {
   356:         mmrWb (a, c);
   357:         a++;
   358:       } else {
   359:         mmrWw (a, c);
   360:         a += 2;
   361:       }
   362:     }
   363:   }  //mmrWstr(int,String)
   364: 
   365:   //top = mmrHumanTop ()
   366:   //  Human68kのメモリ管理の先頭のアドレス(HUMAN.SYSのメモリ管理テーブルのアドレス)を返す
   367:   //  -1  Human68kが読み込まれていないか、未知のバージョン
   368:   //  Human68kのメモリ管理の先頭のアドレス。Human200以降は0x1c04に入っているものと同じ
   369:   //    human100 0x00010a10
   370:   //    human101 0x00010a1a
   371:   //    human200 0x00007dae
   372:   //    human201 0x00007dae
   373:   //    human202 0x00007dce
   374:   //    human203 0x00007d50
   375:   //    human215 0x0000841c
   376:   //    human301 0x000082d0
   377:   //    human302 0x00008372
   378:   public static int mmrHumanTop () {
   379:     return (mmrHumanVersion == 0x0302 ? 0x00008372 :
   380:             mmrHumanVersion == 0x0301 ? 0x000082d0 :
   381:             mmrHumanVersion == 0x020f ? 0x0000841c :
   382:             mmrHumanVersion == 0x0203 ? 0x00007d50 :
   383:             mmrHumanVersion == 0x0202 ? 0x00007dce :
   384:             mmrHumanVersion == 0x0201 ? 0x00007dae :
   385:             mmrHumanVersion == 0x0200 ? 0x00007dae :
   386:             mmrHumanVersion == 0x0101 ? 0x00010a1a :
   387:             mmrHumanVersion == 0x0100 ? 0x00010a10 :
   388:             -1);
   389:   }  //mmrHumanTop()
   390: 
   391:   //btm = mmrHumanBtm ()
   392:   //  Human68kのメモリ管理の末尾のアドレスを返す
   393:   //  -1  Human68kが読み込まれていないか、未知のバージョン
   394:   public static int mmrHumanBtm () {
   395:     return mmrHumanVersion > 0 ? MC68060.mmuPeekLongData (0x00001c00, 1) : -1;
   396:   }  //mmrHumanBtm()
   397: 
   398:   //pmm = mmrHumanPmm ()
   399:   //  Human68kの実行中のプロセスのメモリ管理テーブルのアドレス(GETPDB()-16)を返す
   400:   //  -1  Human68kが読み込まれていないか、未知のバージョン
   401:   //  実行中のプロセスのメモリ管理テーブルのアドレス
   402:   //    human100 [0x00008a98]
   403:   //    human101 [0x00008a92]
   404:   //    human200 [0x00012d88]
   405:   //    human201 [0x00012d88]
   406:   //    human202 [0x00012dc8]
   407:   //    human203 [0x00012b54]
   408:   //    human215 [0x00013c9c]
   409:   //    human301 [0x00013bf4]
   410:   //    human302 [0x00013d0a]
   411:   public static int mmrHumanPmm () {
   412:     return (mmrHumanVersion == 0x0302 ? MC68060.mmuPeekLongData (0x00013d0a, 1) :
   413:             mmrHumanVersion == 0x0301 ? MC68060.mmuPeekLongData (0x00013bf4, 1) :
   414:             mmrHumanVersion == 0x020f ? MC68060.mmuPeekLongData (0x00013c9c, 1) :
   415:             mmrHumanVersion == 0x0203 ? MC68060.mmuPeekLongData (0x00012b54, 1) :
   416:             mmrHumanVersion == 0x0202 ? MC68060.mmuPeekLongData (0x00012dc8, 1) :
   417:             mmrHumanVersion == 0x0201 ? MC68060.mmuPeekLongData (0x00012d88, 1) :
   418:             mmrHumanVersion == 0x0200 ? MC68060.mmuPeekLongData (0x00012d88, 1) :
   419:             mmrHumanVersion == 0x0101 ? MC68060.mmuPeekLongData (0x00008a92, 1) :
   420:             mmrHumanVersion == 0x0100 ? MC68060.mmuPeekLongData (0x00008a98, 1) :
   421:             -1);
   422:   }  //mmrHumanPmm()
   423: 
   424:   //nul = mmrHumanNul ()
   425:   //  Human68kのNULデバイスドライバのアドレスを返す
   426:   //  -1  Human68kが読み込まれていないか、未知のバージョンか、NULデバイスドライバが見つからない
   427:   //  NULデバイスドライバのアドレス
   428:   //    human100 0x0000b83e
   429:   //    human101 0x0000b84c
   430:   //    human200 0x0000ece6
   431:   //    human201 0x0000ece6
   432:   //    human202 0x0000ed36
   433:   //    human203 0x0000eac2
   434:   //    human215 0x0000fa04
   435:   //    human301 0x0000f93a
   436:   //    human302 0x0000fa50
   437:   public static int mmrHumanNul () {
   438:     int a = (mmrHumanVersion == 0x0302 ? 0x0000fa50 :
   439:              mmrHumanVersion == 0x0301 ? 0x0000f93a :
   440:              mmrHumanVersion == 0x020f ? 0x0000fa04 :
   441:              mmrHumanVersion == 0x0203 ? 0x0000eac2 :
   442:              mmrHumanVersion == 0x0202 ? 0x0000ed36 :
   443:              mmrHumanVersion == 0x0201 ? 0x0000ece6 :
   444:              mmrHumanVersion == 0x0200 ? 0x0000ece6 :
   445:              mmrHumanVersion == 0x0101 ? 0x0000b84c :
   446:              mmrHumanVersion == 0x0100 ? 0x0000b83e :
   447:              -1);
   448:     return (a >= 0 &&
   449:             MC68060.mmuPeekLongData (a + 14, 1) == ('N' << 24 | 'U' << 16 | 'L' << 8 | ' ') &&
   450:             MC68060.mmuPeekLongData (a + 18, 1) == (' ' << 24 | ' ' << 16 | ' ' << 8 | ' ') ? a : -1);
   451:   }  //mmrHumanNul()
   452: 
   453:   //dev = mmrHumanDev (name1, name2)
   454:   //  Human68kに組み込まれている指定された名前のデバイスドライバのアドレスを返す
   455:   //  同じ名前のデバイスドライバが複数組み込まれているときは最後に見つかったものを返す
   456:   //  最初の100個までに見つからなかったら諦める
   457:   //  -1  Human68kが読み込まれていないか、未知のバージョンか、指定された名前のデバイスドライバが見つからない
   458:   //  CONデバイスの場合
   459:   //    con = mmrHumanDev ('C' << 24 | 'O' << 16 | 'N' << 8 | ' ', ' ' << 24 | ' ' << 16 | ' ' << 8 | ' ');
   460:   public static int mmrHumanDev (int name1, int name2) {
   461:     int dev = -1;
   462:     for (int a = mmrHumanNul (), i = 0; a >= 0 && i < 100; a = MC68060.mmuPeekLongData (a, 1), i++) {
   463:       //!!! ローカルメモリまで辿れない
   464:       if (MC68060.mmuPeekLongData (a + 14, 1) == name1 && MC68060.mmuPeekLongData (a + 18, 1) == name2) {  //見つかった
   465:         dev = a;
   466:         //最後に見つかったものを返すので見つかっても続ける
   467:       }
   468:     }
   469:     return dev;  //最後に見つかったデバイスドライバ
   470:   }  //mmrHumanDev(int,int)
   471: 
   472:   //mmrCheckHuman ()
   473:   //  Human68kのバージョンを確認してパッチをあてる
   474:   //  IOCS _BOOTINFで呼び出される
   475:   public static void mmrCheckHuman () {
   476:     if (mmrHumanVersion != 0) {  //確認済み
   477:       return;
   478:     }
   479:     //Human68kが起動デバイスを確認するときに呼び出した_BOOTINFであることを確認する
   480:     if (!(MC68060.mmuPeekLongData (0x00001c00, 1) != 0 &&  //_MALLOCできるメモリ空間の末尾アドレス+1が設定されていて
   481:           MC68060.mmuPeekLongData (0x00001c1c, 1) == 0)) {  //最後のデバイスドライバがまだ設定されていない
   482:       return;
   483:     }
   484:     //Human68kのバージョンを確認する
   485:     //  タイトルメッセージの領域はスタックエリアになって$FFで充填されているのでシェル起動後は確認できない
   486:     //  _VERNUMのコードを直接読み出す
   487:     //    human100  0x00009ae4  0x0100
   488:     //    human101  0x00009aee  0x0101
   489:     //    human200  0x00009ee4  0x0200
   490:     //    human201  0x00009ee4  0x0201
   491:     //    human202  0x00009ed6  0x0202
   492:     //    human203  0x00009d7e  0x0203
   493:     //    human215  0x0000a4fa  0x020f  //0x0215ではない
   494:     //    human301  0x0000a3c6  0x0301
   495:     //    human302  0x0000a4ac  0x0302
   496:     //  0000A4AC  303C3638      move.w  #$3638,d0
   497:     //  0000A4B0  4840          swap.w  d0
   498:     //  0000A4B2  303C0302      move.w  #$0302,d0
   499:     //  0000A4B6  4E75          rts
   500:     mmrHumanVersion = (MC68060.mmuPeekWordZeroData (0x0000a4ac + 8, 1) == 0x0302 ? 0x0302 :
   501:                        MC68060.mmuPeekWordZeroData (0x0000a3c6 + 8, 1) == 0x0301 ? 0x0301 :
   502:                        MC68060.mmuPeekWordZeroData (0x0000a4fa + 8, 1) == 0x020f ? 0x020f :  //0x0215ではない
   503:                        MC68060.mmuPeekWordZeroData (0x00009d7e + 8, 1) == 0x0203 ? 0x0203 :
   504:                        MC68060.mmuPeekWordZeroData (0x00009ed6 + 8, 1) == 0x0202 ? 0x0202 :
   505:                        MC68060.mmuPeekWordZeroData (0x00009ee4 + 8, 1) == 0x0201 ? 0x0201 :
   506:                        MC68060.mmuPeekWordZeroData (0x00009ee4 + 8, 1) == 0x0200 ? 0x0200 :
   507:                        MC68060.mmuPeekWordZeroData (0x00009aee + 8, 1) == 0x0101 ? 0x0101 :
   508:                        MC68060.mmuPeekWordZeroData (0x00009ae4 + 8, 1) == 0x0100 ? 0x0100 :
   509:                        -1);  //Human68kが読み込まれていないか、未知のバージョン
   510:     if (mmrHumanVersion < 0) {  //Human68kが読み込まれていないか、未知のバージョン
   511:       return;
   512:     }
   513:     //Human68kにパッチをあてる
   514:     int patched = 0;
   515:     int failed = 0;
   516:     switch (mmrHumanVersion) {
   517:     case 0x0215:
   518:       //RAMまたはROMから起動してDISK2HDを初期化するときリクエストヘッダの初期化コマンドを設定していない(human215,human301,human302)
   519:       //
   520:       //                                                   →                          sf.b    ($0002,a5)
   521:       //  0000802E  61005F74      bsr.w   ~00DEFA
   522:       //  00008032  082900070004  btst.b  #$07,($0004,a1)  →                          tst.b   ($0004,a1)
   523:       //  00008038  6618          bne.s   $00008052        →                          bmi.s   $00008052
   524:       //
   525:       //x形式のヘッダのメモリアロケーションモードが必要最小ブロックからかどうかをテストするbit番号が間違っている(human215,human301,human302)
   526:       //
   527:       //  00009A5A  08010001      btst.l  #$01,d1          →  00009A5A  08010000      btst.l  #$00,d1
   528:       if (MC68060.mmuPeekLongData (0x00009a5a, 1) == 0x08010001) {
   529:         MC68060.mmuPokeByteData (0x00009a5a + 3, 0x00, 1);
   530:         patched++;
   531:       } else {
   532:         failed++;
   533:       }
   534:       //
   535:       //ディレクトリを延長するときルートディレクトリかどうかを判断するためにセクタ番号をデータ部の先頭セクタ番号と比較するとき上位ワードを無視している(human215,human301,human302)
   536:       //
   537:       //                                                   →            7000          moveq.l #$00,d0
   538:       //  0000B900  30280014      move.w  ($0014,a0),d0
   539:       //  0000B904  B240          cmp.w   d0,d1            →            B280          cmp.l   d0,d1
   540:       //  0000B906  6406          bcc.s   $0000B90E
   541:       //  0000B908  5241          addq.w  #$01,d1
   542:       //  0000B90A  B240          cmp.w   d0,d1
   543:       //  0000B90C  4E75          rts
   544:       //  0000B90E
   545:       //
   546:       //FILESのバッファのアドレスのbit31がセットされているとき拡張部分をコピーするループのループカウンタのレジスタが間違っている(human215)
   547:       //
   548:       //  0000BC3E  7255          moveq.l #$55,d1
   549:       //  0000BC40  12D8          move.b  (a0)+,(a1)+
   550:       //  0000BC42  51C8FFFC      dbra.w  d0,$0000BC40     →  0000BC42  51C9FFFC      dbra.w  d1,$0000BC40
   551:       if (MC68060.mmuPeekWordZeroData (0x0000bc42, 1) == 0x51c8) {
   552:         MC68060.mmuPokeByteData (0x0000bc42 + 1, 0xc9, 1);
   553:         patched++;
   554:       } else {
   555:         failed++;
   556:       }
   557:       //
   558:       //リモートデバイスに対するchmodコマンドのコマンド番号が間違っている(human215)
   559:       //
   560:       //  0000D848  7057          moveq.l #$57,d0          →  0000D848  7046          moveq.l #$46,d0
   561:       if (MC68060.mmuPeekWordZeroData (0x0000d848, 1) == 0x7057) {
   562:         MC68060.mmuPokeByteData (0x0000d848 + 1, 0x46, 1);
   563:         patched++;
   564:       } else {
   565:         failed++;
   566:       }
   567:       //
   568:       //サブのメモリ空間を削除するときサブの管理下で常駐したブロックをメインのメモリ空間からサブのメモリ空間に入る方向に繋いでいない(human215,human301,human302)
   569:       //
   570:       //スレッドを切り替えるためのTimer-D割り込みルーチンがMC68030のコプロセッサ命令途中割り込みに対応していない(human215,human301,human302)
   571:       //
   572:       //IOCTRL(19,1)でBPBテーブルをコピーする長さとPDAとイジェクトフラグを書き込む位置が間違っている(human215,human301,human302)
   573:       //
   574:       //  00010AE8  700B          moveq.l #$0B,d0          →  00010AE8  700F          moveq.l #$0F,d0
   575:       //  00010AEA  10DE          move.b  (a6)+,(a0)+
   576:       //  00010AEC  51C8FFFC      dbra.w  d0,$00010AEA
   577:       if (MC68060.mmuPeekWordZeroData (0x00010ae8, 1) == 0x700b) {
   578:         MC68060.mmuPokeByteData (0x00010ae8 + 1, 0x0f, 1);
   579:         patched++;
   580:       } else {
   581:         failed++;
   582:       }
   583:       //
   584:       //IOCTRL(19,0)でBPBテーブルのハンドルをBPBテーブルのアドレスとして参照しようとしている(human215)
   585:       //
   586:       //  00FCA520  61000084      bsr.w   $00FCA5A6
   587:       //  00FCA524  206D000E      movea.l $000E(a5),a0
   588:       //  ;BPBテーブルのハンドルを求めるときにd0.w=(d0.w&3)*4を計算しているのでd0.wの上位バイトは既に0になっている
   589:       //  00FCA528  4240          clr.w   d0               →  00FCA528  2C56          movea.l (a6),a6
   590:       //  00FCA52A  102E000A      move.b  $000A(a6),d0
   591:       //  00FCA52E  3080          move.w  d0,(a0)
   592:       //
   593:       break;
   594:     case 0x0301:
   595:       //RAMまたはROMから起動してDISK2HDを初期化するときリクエストヘッダの初期化コマンドを設定していない(human215,human301,human302)
   596:       //
   597:       //                                                   →                          sf.b    ($0002,a5)
   598:       //  00007EE2  61005F74      bsr.w   ~00DEFA
   599:       //  00007EE6  082900070004  btst.b  #$07,($0004,a1)  →                          tst.b   ($0004,a1)
   600:       //  00007EEC  6618          bne.s   $00007F06        →                          bmi.s   $00007F06
   601:       //
   602:       //x形式のヘッダのメモリアロケーションモードが必要最小ブロックからかどうかをテストするbit番号が間違っている(human215,human301,human302)
   603:       //
   604:       //  00009926  08010001      btst.l  #$01,d1          →  00009926  08010000      btst.l  #$00,d1
   605:       if (MC68060.mmuPeekWordZeroData (0x00009926 + 2, 1) == 0x0001) {
   606:         MC68060.mmuPokeByteData (0x00009926 + 3, 0x00, 1);
   607:         patched++;
   608:       } else {
   609:         failed++;
   610:       }
   611:       //
   612:       //ディレクトリを延長するときルートディレクトリかどうかを判断するためにセクタ番号をデータ部の先頭セクタ番号と比較するとき上位ワードを無視している(human215,human301,human302)
   613:       //
   614:       //サブのメモリ空間を削除するときサブの管理下で常駐したブロックをメインのメモリ空間からサブのメモリ空間に入る方向に繋いでいない(human215,human301,human302)
   615:       //
   616:       //スレッドを切り替えるためのTimer-D割り込みルーチンがMC68030のコプロセッサ命令途中割り込みに対応していない(human215,human301,human302)
   617:       //
   618:       //IOCTRL(19,1)でBPBテーブルをコピーする長さとPDAとイジェクトフラグを書き込む位置が間違っている(human215,human301,human302)
   619:       //
   620:       //  00010A22  700B          moveq.l #$0B,d0          →  00010A22  700F          moveq.l #$0F,d0
   621:       //  00010A24  10DE          move.b  (a6)+,(a0)+
   622:       //  00010A26  51C8FFFC      dbra.w  d0,$00010A24
   623:       if (MC68060.mmuPeekWordZeroData (0x00010a22, 1) == 0x700b) {
   624:         MC68060.mmuPokeByteData (0x00010a22 + 1, 0x0f, 1);
   625:         patched++;
   626:       } else {
   627:         failed++;
   628:       }
   629:       //
   630:       break;
   631:     case 0x0302:
   632:       //デバイスドライバを初期化する直前と初期化した直後
   633:       //<a1.l:初期化されたデバイスドライバのデバイスヘッダのアドレス
   634:       //  00007140  1B7C00160000  move.b  #$16,$0000(a5)  →  00007140  4E04          emxnop
   635:       //                                                  →  00007142  2209          move.l  a1,d1
   636:       //                                                  →  00007144  1ABC0016      move.b  #$16,(a5)
   637:       //  00007146  1B7C00000002  move.b  #$00,$0002(a5)  →
   638:       //                                                  →  00007148  51ED0002      sf.b    $0002(a5)
   639:       //  0000714C  082900050004  btst.b  #$05,$0004(a1)
   640:       //  00007152  6706          beq.s   $0000715A
   641:       //  00007154  1B7C00400002  move.b  #$40,$0002(a5)
   642:       //  0000715A  2B400012      move.l  d0,$0012(a5)
   643:       //  0000715E  10381C75      move.b  $1C75.w,d0
   644:       //  00007162  5200          addq.b  #$01,d0
   645:       //  00007164  1B400016      move.b  d0,$0016(a5)
   646:       //  00007168  2209          move.l  a1,d1           →  00007168  61006D90      bsr.w   $0000DEFA
   647:       //  0000716A  2241          movea.l d1,a1           →
   648:       //  0000716C  60006D8C      bra.w   $0000DEFA       →  0000716C  4E04          emxnop
   649:       //                                                  →  0000716E  4E75          rts
   650:       if (MC68060.mmuPeekLongData (0x00007140, 1) == 0x1b7c0016) {
   651:         MC68060.mmuPokeLongData (0x00007140, XEiJ.EMX_OPCODE_EMXNOP << 16 | 0x2209, 1);
   652:         MC68060.mmuPokeLongData (0x00007144, 0x1abc0016, 1);
   653:         MC68060.mmuPokeLongData (0x00007148, 0x51ed0002, 1);
   654:         MC68060.mmuPokeLongData (0x00007168, 0x61006d90, 1);
   655:         MC68060.mmuPokeLongData (0x0000716c, XEiJ.EMX_OPCODE_EMXNOP << 16 | 0x4e75, 1);
   656:         patched++;
   657:       } else {
   658:         failed++;
   659:       }
   660:       //プロセスを起動する直前
   661:       //  0000971E  2B48001C      move.l  a0,$001C(a5)    →  0000971E  48ED1F00001C  movem.l a0-a4,$001C(a5)
   662:       //  00009722  2B490020      move.l  a1,$0020(a5)    →
   663:       //                                                      00009724  200C          move.l  a4,d0
   664:       //  00009726  2B4A0024      move.l  a2,$0024(a5)    →  00009726  4A41          tst.w   d1
   665:       //                                                      00009728  6600FE30      bne.w   $0000955A
   666:       //  0000972A  2B4B0028      move.l  a3,$0028(a5)    →
   667:       //                                                      0000972C  4E04          emxnop
   668:       //  0000972E  2B4C002C      move.l  a4,$002C(a5)    →  0000972E  600A          bra.s   $0000973A
   669:       //  00009732  200C          move.l  a4,d0           →
   670:       //  00009734  4A41          tst.w   d1              →
   671:       //  00009736  6600FE22      bne.w   $0000955A       →
   672:       if (MC68060.mmuPeekLongData (0x0000971e, 1) == 0x2b48001c) {
   673:         MC68060.mmuPokeWordData (0x0000971e, 0x48ed, 1);
   674:         MC68060.mmuPokeLongData (0x00009720, 0x1f00001c, 1);
   675:         MC68060.mmuPokeLongData (0x00009724, 0x200c4a41, 1);
   676:         MC68060.mmuPokeLongData (0x00009728, 0x6600fe30, 1);
   677:         MC68060.mmuPokeLongData (0x0000972c, XEiJ.EMX_OPCODE_EMXNOP << 16 | 0x600a, 1);
   678:         patched++;
   679:       } else {
   680:         failed++;
   681:       }
   682:       //プロセスが常駐した直後
   683:       //<a0.l:常駐したプロセスのメモリ管理テーブルのアドレス
   684:       //  0000A088  4A380CBC      tst.b   $0CBC.w
   685:       //  0000A08C  6704          beq.s   $0000A092       →  0000A08C  6702          beq.s   $0000A090
   686:       //  0000A08E  3F3C0000      move.w  #$0000,-(sp)    →  0000A08E  4267          clr.w   -(sp)
   687:       //                                                  →  0000A090  4E04          emxnop
   688:       //  0000A092
   689:       if (MC68060.mmuPeekWordZeroData (0x0000a08c, 1) == 0x6704 &&
   690:           MC68060.mmuPeekLongData (0x0000a08e, 1) == 0x3f3c0000) {
   691:         MC68060.mmuPokeLongData (0x0000a08c, 0x67024267, 1);
   692:         MC68060.mmuPokeWordData (0x0000a090, XEiJ.EMX_OPCODE_EMXNOP, 1);
   693:         patched++;
   694:       } else {
   695:         failed++;
   696:       }
   697:       //RAMまたはROMから起動してDISK2HDを初期化するときリクエストヘッダの初期化コマンドを設定していない(human215,human301,human302)
   698:       //
   699:       //                                                   →                          sf.b    ($0002,a5)
   700:       //  00007F84  61005F74      bsr.w   ~00DEFA
   701:       //  00007F88  082900070004  btst.b  #$07,($0004,a1)  →                          tst.b   ($0004,a1)
   702:       //  00007F8E  6618          bne.s   $00007FA8        →                          bmi.s   $00007FA8
   703:       //
   704:       //x形式のヘッダのメモリアロケーションモードが必要最小ブロックからかどうかをテストするbit番号が間違っている(human215,human301,human302)
   705:       //
   706:       //  000099C4  08010001      btst.l  #$01,d1          →  000099C4  08010000      btst.l  #$00,d1
   707:       if (XEiJ.mpuCoreType != 6) {  //060turbo.sysのパッチと衝突する
   708:         if (MC68060.mmuPeekWordZeroData (0x000099c4 + 2, 1) == 0x0001) {
   709:           MC68060.mmuPokeByteData (0x000099c4 + 3, 0x00, 1);
   710:           patched++;
   711:         } else {
   712:           failed++;
   713:         }
   714:       }
   715:       //
   716:       //仮想ディレクトリを展開して実体のドライブに移るときドライブ管理テーブルのアドレスを変更する命令のオペレーションサイズが間違っている(human302)
   717:       //
   718:       //  0000B2EA  324C          movea.w a4,a1            →  0000B2EA  224C          movea.l a4,a1
   719:       if (MC68060.mmuPeekWordZeroData (0x0000b2ea, 1) == 0x324c) {
   720:         MC68060.mmuPokeByteData (0x0000b2ea + 0, 0x22, 1);
   721:         patched++;
   722:       } else {
   723:         failed++;
   724:       }
   725:       //
   726:       //ディレクトリを延長するときルートディレクトリかどうかを判断するためにセクタ番号をデータ部の先頭セクタ番号と比較するとき上位ワードを無視している(human215,human301,human302)
   727:       //
   728:       //                                                   →            7000          moveq.l #$00,d0
   729:       //  0000B8E2  30280014      move.w  ($0014,a0),d0
   730:       //  0000B8E6  B240          cmp.w   d0,d1            →            B280          cmp.l   d0,d1
   731:       //  0000B8E8  6406          bcc.s   $0000B8F0
   732:       //  0000B8EA  5241          addq.w  #$01,d1          →            5281          addq.l  #$01,d1
   733:       //  0000B8EC  B240          cmp.w   d0,d1            →            B280          cmp.l   d0,d1
   734:       //  0000B8EE  4E75          rts
   735:       //
   736:       //サブのメモリ空間を削除するときサブの管理下で常駐したブロックをメインのメモリ空間からサブのメモリ空間に入る方向に繋いでいない(human215,human301,human302)
   737:       //
   738:       //スレッドを切り替えるためのTimer-D割り込みルーチンがMC68030のコプロセッサ命令途中割り込みに対応していない(human215,human301,human302)
   739:       //
   740:       //IOCTRL(19,1)でBPBテーブルをコピーする長さとPDAとイジェクトフラグを書き込む位置が間違っている(human215,human301,human302)
   741:       //
   742:       //  00010B38  700B          moveq.l #$0B,d0          →  00010B38  700F          moveq.l #$0F,d0
   743:       //  00010B3A  10DE          move.b  (a6)+,(a0)+
   744:       //  00010B3C  51C8FFFC      dbra.w  d0,$00010B3A
   745:       if (MC68060.mmuPeekWordZeroData (0x00010b38, 1) == 0x700b) {
   746:         MC68060.mmuPokeByteData (0x00010b38 + 1, 0x0f, 1);
   747:         patched++;
   748:       } else {
   749:         failed++;
   750:       }
   751:       //
   752:       break;
   753:     }
   754:     //
   755:     //  Humanのline 1111 emulator/privilege violation例外処理ルーチンの手前にFLOATn.Xのマジック'FEfn'を押し込む
   756:     //    手前にある_EXITVC/_CTRLVC/_ERRJVCのコードを詰めて隙間を作る
   757:     //  Human自身がFLOATn.Xのマジックを持つことでFLOATn.Xを組み込めなくする
   758:     //    シェルが正常終了した
   759:     //      00008518  6140          bsr.s   $0000855A       1行改行
   760:     //      0000851A  4879000111AE  pea.l   $000111AE.l     '終了しました。',$00
   761:     //      00008520  FF09          DOS     _PRINT
   762:     //      00008522  588F          addq.l  #$04,sp
   763:     //      00008524  4879000111BD  pea.l   $000111BD.l     'コマンドを、入力してください',$0D,$0A,'#',$00
   764:     //      0000852A  6006          bra.s   $00008532
   765:     //    コマンド入力ループ
   766:     //      0000852C  4879000111DB  pea.l   $000111DB.l     '#',$00
   767:     //      00008532  FF09          DOS     _PRINT
   768:     //          :
   769:     //    _EXITVC/_CTRLVC/_ERRJVC
   770:     //      00008566  FF81          DOS     _GETPDB         human203まではX68030に対応していないため_GETPDBは$FF51
   771:     //      00008568  B0BC00008382  cmp.l   #$00008382,d0   Humanのプロセス管理テーブル
   772:     //      0000856E  6626          bne.s   $00008596       →  0000856E  6622          bne.s   $00008592
   773:     //    シェルが停止した
   774:     //      00008570  4FF900008372  lea.l   $00008372.l,sp  スタック復元
   775:     //      00008576  42A7          clr.l   -(sp)
   776:     //      00008578  FF20          DOS     _SUPER
   777:     //      0000857A  588F          addq.l  #$04,sp
   778:     //      0000857C  207900011090  movea.l $00011090.l,a0  ユーザスタックエリアのアドレス
   779:     //      00008582  41E800F0      lea.l   $00F0(a0),a0
   780:     //      00008586  4E60          move.l  a0,usp
   781:     //      00008588  61D0          bsr.s   $0000855A       1行改行
   782:     //      0000858A  4879000111DD  pea.l   $000111DD.l     '停止しました。',$00
   783:     //      00008590  FF09          DOS     _PRINT          →  00008590  608E          bra.s   $00008520
   784:     //      00008592  588F          addq.l  #$04,sp         →  00008592  FF00          DOS     _EXIT
   785:     //      00008594  608E          bra.s   $00008524       →  00008594  4645          .dc.w   'FE'
   786:     //    シェル以外のプロセスが停止した
   787:     //      00008596  FF00          DOS     _EXIT           →  00008596  666E          .dc.w   'fn'
   788:     //    line 1111 emulator/privilege violation
   789:     //      00008598  48E78006      movem.l d0/a5-a6,-(sp)  human203まではX68030に対応していないためline 1111 emulatorのコードが異なる
   790:     if (FEFunction.fpkRejectFloatOn) {
   791:       int fline = (mmrHumanVersion == 0x0302 ? 0x00008598 :
   792:                    mmrHumanVersion == 0x0301 ? 0x000084f6 :
   793:                    mmrHumanVersion == 0x020f ? 0x00008642 :
   794:                    mmrHumanVersion == 0x0203 ? 0x00007f58 :
   795:                    mmrHumanVersion == 0x0202 ? 0x00007fd6 :
   796:                    mmrHumanVersion == 0x0201 ? 0x00007fb6 :
   797:                    mmrHumanVersion == 0x0200 ? 0x00007fb6 :  //human200はhuman201と同じ
   798:                    //human101とhuman100はコードが異なるのでここでは非対応とする
   799:                    -1);
   800:       if (fline > 0) {
   801:         if (MC68060.mmuPeekWordZeroData (0x0000856e - 0x00008598 + fline, 1) == 0x6626 &&
   802:             MC68060.mmuPeekLongData (0x00008590 - 0x00008598 + fline, 1) == 0xff09588f &&
   803:             MC68060.mmuPeekLongData (0x00008594 - 0x00008598 + fline, 1) == 0x608eff00) {
   804:           MC68060.mmuPokeWordData (0x0000856e - 0x00008598 + fline, 0x6622, 1);
   805:           MC68060.mmuPokeLongData (0x00008590 - 0x00008598 + fline, 0x608eff00, 1);
   806:           MC68060.mmuPokeLongData (0x00008594 - 0x00008598 + fline, 0x4645666e, 1);
   807:           patched++;
   808:         } else {
   809:           failed++;
   810:         }
   811:       }
   812:     }
   813:     XEiJ.prgMessage (new StringBuilder ().
   814:                      append ("Human68k version ").
   815:                      append ((char) ('0' + (mmrHumanVersion >> 8 & 15))).
   816:                      append ('.').
   817:                      append ((char) ('0' + (mmrHumanVersion >> 4 & 15))).
   818:                      append ((char) ('0' + (mmrHumanVersion & 15))).
   819:                      append (Multilingual.mlnJapanese ? " にパッチをあてました (" : " was patched (").
   820:                      append (patched).
   821:                      append ('/').
   822:                      append (patched + failed).
   823:                      append (')').toString ());
   824:     //FEファンクション命令を有効にする
   825:     mmrFEfuncActivated = FEFunction.fpkOn;
   826:     if (mmrFEfuncActivated) {
   827:       XEiJ.prgMessage (Multilingual.mlnJapanese ? "FE ファンクション命令が有効になりました" : "FE function instruction has been activated");
   828:     }
   829:   }  //mmrCheckHuman()
   830: 
   831: }  //class MainMemory
   832: 
   833: 
   834: