MainMemory.java
     1: //========================================================================================
     2: //  MainMemory.java
     3: //    en:Main memory
     4: //    ja:メインメモリ
     5: //  Copyright (C) 2003-2022 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: //データの格納単位
    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/0x025f/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 boolean mmrMemorySaveOn;  //true=メインメモリの内容を保存する
    67: 
    68:   //mmrInit ()
    69:   //  初期化
    70:   public static void mmrInit () {
    71: 
    72:     int mainMemorySizeMB = Settings.sgsGetInt ("memory");  //メインメモリのサイズ
    73:     mmrMemorySizeRequest = (mainMemorySizeMB == 1 ||
    74:                             mainMemorySizeMB == 2 ||
    75:                             mainMemorySizeMB == 4 ||
    76:                             mainMemorySizeMB == 6 ||
    77:                             mainMemorySizeMB == 8 ||
    78:                             mainMemorySizeMB == 10 ||
    79:                             mainMemorySizeMB == 12 ? mainMemorySizeMB << 20 :
    80:                             12 << 20);
    81:     mmrMemorySizeCurrent = mmrMemorySizeRequest;
    82:     System.out.printf (Multilingual.mlnJapanese ?
    83:                        "メインメモリのサイズは %dMB です\n" :
    84:                        "Main memory size is %dMB\n",
    85:                        mmrMemorySizeCurrent >>> 20);
    86: 
    87:     mmrMemorySaveOn = Settings.sgsGetOnOff ("memorysave");  //メインメモリの内容を保存するか
    88: 
    89:     byte[] mainMemoryArray = Settings.sgsGetData ("memorydata");  //メインメモリの内容(gzip+base64)
    90:     if (mainMemoryArray.length != 0) {  //復元するデータがある
    91:       System.out.println (Multilingual.mlnJapanese ?
    92:                           "メインメモリのデータを復元します" :
    93:                           "Main memory data is restored");
    94:       System.arraycopy (mainMemoryArray, 0,  //from
    95:                         mmrM8, 0,  //to
    96:                         Math.min (mainMemoryArray.length, mmrMemorySizeCurrent));
    97:       if (mainMemoryArray.length < mmrMemorySizeCurrent) {
    98:         Arrays.fill (mmrM8, mainMemoryArray.length, mmrMemorySizeCurrent, (byte) 0);
    99:       }
   100:     } else {
   101:       System.out.println (Multilingual.mlnJapanese ?
   102:                           "メインメモリをゼロクリアします" :
   103:                           "Main memory is zero-cleared");
   104:       Arrays.fill (mmrM8, 0, mmrMemorySizeCurrent, (byte) 0);
   105:     }
   106: 
   107:     //mmrM8 = new byte[XEiJ.BUS_MOTHOR_SIZE];
   108:     if (MMR_USE_BYTE_BUFFER) {
   109:       mmrBuffer = ByteBuffer.wrap (mmrM8);
   110:       mmrBuffer.order (ByteOrder.BIG_ENDIAN);
   111:     }
   112: 
   113:     mmrHumanVersion = 0;
   114:     mmrFEfuncActivated = false;
   115:     if (HFS.HFS_USE_TWENTY_ONE) {
   116:       mmrTwentyOneOptionAddress = 0;
   117:     }
   118: 
   119:   }  //mmrInit()
   120: 
   121:   public static void mmrReset () {
   122: 
   123:     mmrMemorySizeCurrent = mmrMemorySizeRequest;
   124:     mmrHumanVersion = 0;
   125:     mmrFEfuncActivated = false;
   126:     if (HFS.HFS_USE_TWENTY_ONE) {
   127:       mmrTwentyOneOptionAddress = 0;
   128:     }
   129: 
   130:     XEiJ.busSuper (MemoryMappedDevice.MMD_MMR, 0x00000000, 0x00002000);
   131:     XEiJ.busUser (MemoryMappedDevice.MMD_MMR, 0x00002000, mmrMemorySizeCurrent);
   132:     if (mmrMemorySizeCurrent < 0x00200000) {
   133:       XEiJ.busUser (MemoryMappedDevice.MMD_MM1, mmrMemorySizeCurrent, 0x00200000);
   134:       XEiJ.busSuper (MemoryMappedDevice.MMD_NUL, 0x00200000, 0x00c00000);
   135:     } else {
   136:       XEiJ.busSuper (MemoryMappedDevice.MMD_NUL, mmrMemorySizeCurrent, 0x00c00000);
   137:     }
   138: 
   139:     mmrSetSupervisorArea (0);
   140: 
   141:   }  //mmrReset()
   142: 
   143:   //mmrSetSupervisorArea (d)
   144:   //  スーパーバイザ領域設定
   145:   public static void mmrSetSupervisorArea (int d) {
   146:     int a = ((d & 0xff) + 1) << 13;
   147:     if (mmrMemorySizeCurrent < 0x00200000) {
   148:       //  1MB搭載機
   149:       //    0  a  1     2     3
   150:       //    SSSUUUuuuuuuNNNNNN
   151:       //    0     1  a  2     3
   152:       //    SSSSSSsssuuuNNNNNN
   153:       if (a < 0x00100000) {
   154:         XEiJ.busSuper (MemoryMappedDevice.MMD_MMR, 0x00000000, a);
   155:         XEiJ.busUser (MemoryMappedDevice.MMD_MMR, a, 0x00100000);
   156:         XEiJ.busUser (MemoryMappedDevice.MMD_MM1, 0x00100000, 0x00200000);
   157:       } else {
   158:         XEiJ.busSuper (MemoryMappedDevice.MMD_MMR, 0x00000000, 0x00100000);
   159:         XEiJ.busSuper (MemoryMappedDevice.MMD_MM1, 0x00100000, a);
   160:         XEiJ.busUser (MemoryMappedDevice.MMD_MM1, a, 0x00200000);
   161:       }
   162:     } else {
   163:       //  2MB搭載機
   164:       //    0  a  1     2     3
   165:       //    SSSUUUUUUUUUNNNNNN
   166:       //    0     1  a  2     3
   167:       //    SSSSSSSSSUUUNNNNNN
   168:       XEiJ.busSuper (MemoryMappedDevice.MMD_MMR, 0x00000000, a);
   169:       XEiJ.busUser (MemoryMappedDevice.MMD_MMR, a, 0x00200000);
   170:     }
   171:   }
   172: 
   173:   //d = mmrRbs (a)
   174:   //  メモリリードバイト符号拡張
   175:   public static byte mmrRbs (int a) {
   176:     //byteの配列からbyteのデータを読み出す
   177:     //       a
   178:     //    +-----+
   179:     //    |  a  |
   180:     //    +-----+
   181:     //    |  d  |
   182:     //    +-----+
   183:     return mmrM8[a & XEiJ.BUS_MOTHER_MASK];
   184:   }  //mmrRbs(int)
   185: 
   186:   //d = mmrRbz (a)
   187:   //  メモリリードバイトゼロ拡張
   188:   public static int mmrRbz (int a) {
   189:     //byteの配列からbyteのデータを読み出す
   190:     //       a
   191:     //    +-----+
   192:     //    |  a  |
   193:     //    +-----+
   194:     //    |  d  |
   195:     //    +-----+
   196:     return mmrM8[a & XEiJ.BUS_MOTHER_MASK] & 255;
   197:   }  //mmrRbz(int)
   198: 
   199:   //d = mmrRws (a)
   200:   //  メモリリードワード符号拡張
   201:   public static int mmrRws (int a) {
   202:     if (MMR_USE_BYTE_BUFFER) {
   203:       return mmrBuffer.getShort (a & XEiJ.BUS_MOTHER_MASK);
   204:     } else {
   205:       //byteの配列からshortのデータを読み出す
   206:       //       a    a+1
   207:       //    +-----+-----+
   208:       //    |  a  | a+1 |
   209:       //    +-----+-----+
   210:       //    |     d     |
   211:       //    +-----+-----+
   212:       return mmrM8[a & XEiJ.BUS_MOTHER_MASK] << 8 | mmrM8[a + 1 & XEiJ.BUS_MOTHER_MASK] & 255;
   213:     }
   214:   }  //mmrRws(int)
   215: 
   216:   //d = mmrRwz (a)
   217:   //  メモリリードワードゼロ拡張
   218:   public static int mmrRwz (int a) {
   219:     if (MMR_USE_BYTE_BUFFER) {
   220:       return mmrBuffer.getChar (a & XEiJ.BUS_MOTHER_MASK);
   221:     } else {
   222:       //byteの配列からunsigned shortのデータを読み出す
   223:       //       a    a+1
   224:       //    +-----+-----+
   225:       //    |  a  | a+1 |
   226:       //    +-----+-----+
   227:       //    |     d     |
   228:       //    +-----+-----+
   229:       return (char) (mmrM8[a & XEiJ.BUS_MOTHER_MASK] << 8 | mmrM8[a + 1 & XEiJ.BUS_MOTHER_MASK] & 255);
   230:     }
   231:   }  //mmrRwz(int)
   232: 
   233:   //d = mmrRls (a)
   234:   //  メモリリードロング符号拡張
   235:   public static int mmrRls (int a) {
   236:     if (MMR_USE_BYTE_BUFFER) {
   237:       return mmrBuffer.getInt (a & XEiJ.BUS_MOTHER_MASK);
   238:     } else {
   239:       //byteの配列からintのデータを読み出す
   240:       //       a    a+1   a+2   a+3
   241:       //    +-----+-----+-----+-----+
   242:       //    |  a  | a+1 | a+2 | a+3 |
   243:       //    +-----+-----+-----+-----+
   244:       //    |           d           |
   245:       //    +-----+-----+-----+-----+
   246:       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);
   247:     }
   248:   }  //mmrRls(int)
   249: 
   250:   //d = mmrRqs (a)
   251:   //  メモリリードクワッド符号拡張
   252:   public static long mmrRqs (int a) {
   253:     if (MMR_USE_BYTE_BUFFER) {
   254:       return mmrBuffer.getLong (a & XEiJ.BUS_MOTHER_MASK);
   255:     } else {
   256:       return ((long) (mmrM8[a     & XEiJ.BUS_MOTHER_MASK] << 24 |
   257:                       mmrM8[a + 1 & XEiJ.BUS_MOTHER_MASK] << 16 & 0x00ff0000 |
   258:                       mmrM8[a + 2 & XEiJ.BUS_MOTHER_MASK] <<  8 & 0x0000ff00 |
   259:                       mmrM8[a + 3 & XEiJ.BUS_MOTHER_MASK]       & 0x000000ff) << 32 |
   260:               (long) (mmrM8[a + 4 & XEiJ.BUS_MOTHER_MASK] << 24 |
   261:                       mmrM8[a + 5 & XEiJ.BUS_MOTHER_MASK] << 16 & 0x00ff0000 |
   262:                       mmrM8[a + 6 & XEiJ.BUS_MOTHER_MASK] <<  8 & 0x0000ff00 |
   263:                       mmrM8[a + 7 & XEiJ.BUS_MOTHER_MASK]       & 0x000000ff) & 0x00000000ffffffffL);
   264:     }
   265:   }  //mmrRqs(int)
   266: 
   267:   //mmrWb (a, d)
   268:   //  メモリライトバイト
   269:   public static void mmrWb (int a, int d) {
   270:     //byteの配列にbyteのデータを書き込む
   271:     //       a
   272:     //    +-----+
   273:     //    |  d  |
   274:     //    +-----+
   275:     //    |  a  |
   276:     //    +-----+
   277:     mmrM8[a & XEiJ.BUS_MOTHER_MASK] = (byte) d;
   278:   }  //mmrWb(int,int)
   279: 
   280:   //mmrWw (a, d)
   281:   //  メモリライトワード
   282:   public static void mmrWw (int a, int d) {
   283:     if (MMR_USE_BYTE_BUFFER) {
   284:       mmrBuffer.putShort (a & XEiJ.BUS_MOTHER_MASK, (short) d);
   285:     } else {
   286:       //byteの配列にshortのデータを書き込む
   287:       //       a    a+1
   288:       //    +-----+-----+
   289:       //    |     d     |
   290:       //    +-----+-----+
   291:       //    |  a  | a+1 |
   292:       //    +-----+-----+
   293:       mmrM8[a     & XEiJ.BUS_MOTHER_MASK] = (byte) (d >> 8);
   294:       mmrM8[a + 1 & XEiJ.BUS_MOTHER_MASK] = (byte)  d;
   295:     }
   296:   }  //mmrWw(int,int)
   297: 
   298:   //a = mmrWl (a, d)
   299:   //  メモリライトロング
   300:   public static void mmrWl (int a, int d) {
   301:     if (MMR_USE_BYTE_BUFFER) {
   302:       mmrBuffer.putInt (a & XEiJ.BUS_MOTHER_MASK, d);
   303:     } else {
   304:       //byteの配列にintのデータを書き込む
   305:       //       a    a+1   a+2   a+3
   306:       //    +-----+-----+-----+-----+
   307:       //    |           d           |
   308:       //    +-----+-----+-----+-----+
   309:       //    |  a  | a+1 | a+2 | a+3 |
   310:       //    +-----+-----+-----+-----+
   311:       mmrM8[a     & XEiJ.BUS_MOTHER_MASK] = (byte) (d >> 24);
   312:       mmrM8[a + 1 & XEiJ.BUS_MOTHER_MASK] = (byte) (d >> 16);
   313:       mmrM8[a + 2 & XEiJ.BUS_MOTHER_MASK] = (byte) (d >> 8);
   314:       mmrM8[a + 3 & XEiJ.BUS_MOTHER_MASK] = (byte)  d;
   315:     }
   316:   }  //mmrWl(int,int)
   317: 
   318:   //a = mmrWq (a, d)
   319:   //  メモリライトクワッド
   320:   public static void mmrWq (int a, long d) {
   321:     if (MMR_USE_BYTE_BUFFER) {
   322:       mmrBuffer.putLong (a & XEiJ.BUS_MOTHER_MASK, d);
   323:     } else {
   324:       mmrM8[a     & XEiJ.BUS_MOTHER_MASK] = (byte) (d >> 56);
   325:       mmrM8[a + 1 & XEiJ.BUS_MOTHER_MASK] = (byte) (d >> 48);
   326:       mmrM8[a + 2 & XEiJ.BUS_MOTHER_MASK] = (byte) (d >> 40);
   327:       mmrM8[a + 3 & XEiJ.BUS_MOTHER_MASK] = (byte) (d >> 32);
   328:       mmrM8[a + 4 & XEiJ.BUS_MOTHER_MASK] = (byte) (d >> 24);
   329:       mmrM8[a + 5 & XEiJ.BUS_MOTHER_MASK] = (byte) (d >> 16);
   330:       mmrM8[a + 6 & XEiJ.BUS_MOTHER_MASK] = (byte) (d >> 8);
   331:       mmrM8[a + 7 & XEiJ.BUS_MOTHER_MASK] = (byte)  d;
   332:     }
   333:   }  //mmrWq(int,long)
   334: 
   335:   //mmrWba (a, d, ...)
   336:   //  メモリライトバイトアレイ
   337:   public static void mmrWba (int a, int... da) {
   338:     for (int d : da) {
   339:       mmrWb (a, d);
   340:       a++;
   341:     }
   342:   }  //mmrWba(int,int...)
   343: 
   344:   //mmrWwa (a, d, ...)
   345:   //  メモリライトワードアレイ
   346:   public static void mmrWwa (int a, int... da) {
   347:     for (int d : da) {
   348:       mmrWw (a, d);
   349:       a += 2;
   350:     }
   351:   }  //mmrWwa(int,int...)
   352: 
   353:   //a = mmrWla (a, d, ...)
   354:   //  メモリライトロングアレイ
   355:   public static void mmrWla (int a, int... da) {
   356:     for (int d : da) {
   357:       mmrWl (a, d);
   358:       a += 4;
   359:     }
   360:   }  //mmrWla(int,int...)
   361: 
   362:   //len = mmrStrlen (a, l)
   363:   public static int mmrStrlen (int a, int l) {
   364:     for (int i = 0; i < l; i++) {
   365:       if (mmrM8[a + i] == 0) {
   366:         return i;
   367:       }
   368:     }
   369:     return l;
   370:   }  //mmrStrlen(int,int)
   371: 
   372:   //s = mmrRstr (a, l)
   373:   //sb = mmrRstr (sb, a, l)
   374:   //  メモリリードストリング
   375:   //  文字列を読み出す
   376:   //  対応する文字がないときは'.'または'※'になる
   377:   //  制御コードは'.'になる
   378:   public static String mmrRstr (int a, int l) {
   379:     return mmrRstr (new StringBuilder (), a, l).toString ();
   380:   }  //mmrRstr(int,int)
   381:   public static StringBuilder mmrRstr (StringBuilder sb, int a, int l) {
   382:     for (int i = 0; i < l; i++) {
   383:       int s = mmrRbz (a + i);
   384:       char c;
   385:       if (0x81 <= s && s <= 0x9f || 0xe0 <= s && s <= 0xef) {  //SJISの2バイトコードの1バイト目
   386:         int t = i + 1 < l ? mmrRbz (a + i + 1) : 0;
   387:         if (0x40 <= t && t != 0x7f && t <= 0xfc) {  //SJISの2バイトコードの2バイト目
   388:           c = CharacterCode.chrSJISToChar[s << 8 | t];  //2バイトで変換する
   389:           if (c == 0) {  //対応する文字がない
   390:             c = '※';
   391:           }
   392:           i++;
   393:         } else {  //SJISの2バイトコードの2バイト目ではない
   394:           c = '.';  //SJISの2バイトコードの1バイト目ではなかった
   395:         }
   396:       } else {  //SJISの2バイトコードの1バイト目ではない
   397:         c = CharacterCode.chrSJISToChar[s];  //1バイトで変換する
   398:         if (c < 0x20 || c == 0x7f) {  //対応する文字がないまたは制御コード
   399:           c = '.';
   400:         }
   401:       }
   402:       sb.append (c);
   403:     }
   404:     return sb;
   405:   }  //mmrRstr(StringBuilder,int,int)
   406: 
   407:   //a = mmrWstr (a, s)
   408:   //  メモリライトストリング
   409:   //  文字列をSJISに変換しながら書き込む
   410:   //  SJISに変換できない文字は'※'になる
   411:   //  文字列の直後のアドレス(マスク済み)を返す
   412:   public static void mmrWstr (int a, String s) {
   413:     int l = s.length ();
   414:     for (int i = 0; i < l; i++) {
   415:       int c = CharacterCode.chrCharToSJIS[s.charAt (i)];
   416:       if (c == 0 && s.charAt (i) != '\0') {  //SJISに変換できないとき'\0'でない文字が0になる
   417:         mmrWw (a, 0x81a6);  //※
   418:         a += 2;
   419:       } else if (c <= 0x00ff) {
   420:         mmrWb (a, c);
   421:         a++;
   422:       } else {
   423:         mmrWw (a, c);
   424:         a += 2;
   425:       }
   426:     }
   427:   }  //mmrWstr(int,String)
   428: 
   429:   //top = mmrHumanTop ()
   430:   //  Human68kのメモリ管理の先頭のアドレス(HUMAN.SYSのメモリ管理テーブルのアドレス)を返す
   431:   //  -1  Human68kが読み込まれていないか、未知のバージョン
   432:   //  Human68kのメモリ管理の先頭のアドレス。Human200以降は0x1c04に入っているものと同じ
   433:   //    human100 0x00010a10
   434:   //    human101 0x00010a1a
   435:   //    human200 0x00007dae
   436:   //    human201 0x00007dae
   437:   //    human202 0x00007dce
   438:   //    human203 0x00007d50
   439:   //    human215 0x0000841c
   440:   //    human301 0x000082d0
   441:   //    human302 0x00008372 human295
   442:   public static int mmrHumanTop () {
   443:     return (mmrHumanVersion == 0x0302 ||
   444:             mmrHumanVersion == 0x025f ? 0x00008372 :
   445:             mmrHumanVersion == 0x0301 ? 0x000082d0 :
   446:             mmrHumanVersion == 0x020f ? 0x0000841c :
   447:             mmrHumanVersion == 0x0203 ? 0x00007d50 :
   448:             mmrHumanVersion == 0x0202 ? 0x00007dce :
   449:             mmrHumanVersion == 0x0201 ? 0x00007dae :
   450:             mmrHumanVersion == 0x0200 ? 0x00007dae :
   451:             mmrHumanVersion == 0x0101 ? 0x00010a1a :
   452:             mmrHumanVersion == 0x0100 ? 0x00010a10 :
   453:             -1);
   454:   }  //mmrHumanTop()
   455: 
   456:   //btm = mmrHumanBtm ()
   457:   //  Human68kのメモリ管理の末尾のアドレスを返す
   458:   //  -1  Human68kが読み込まれていないか、未知のバージョン
   459:   public static int mmrHumanBtm () {
   460:     return mmrHumanVersion > 0 ? MC68060.mmuPeekLongData (0x00001c00, 1) : -1;
   461:   }  //mmrHumanBtm()
   462: 
   463:   //pmm = mmrHumanPmm ()
   464:   //  Human68kの実行中のプロセスのメモリ管理テーブルのアドレス(GETPDB()-16)を返す
   465:   //  -1  Human68kが読み込まれていないか、未知のバージョン
   466:   //  実行中のプロセスのメモリ管理テーブルのアドレス
   467:   //    human100 [0x00008a98]
   468:   //    human101 [0x00008a92]
   469:   //    human200 [0x00012d88]
   470:   //    human201 [0x00012d88]
   471:   //    human202 [0x00012dc8]
   472:   //    human203 [0x00012b54]
   473:   //    human215 [0x00013c9c]
   474:   //    human301 [0x00013bf4]
   475:   //    human302 [0x00013d0a] human295
   476:   public static int mmrHumanPmm () {
   477:     return (mmrHumanVersion == 0x0302 ||
   478:             mmrHumanVersion == 0x025f ? MC68060.mmuPeekLongData (0x00013d0a, 1) :
   479:             mmrHumanVersion == 0x0301 ? MC68060.mmuPeekLongData (0x00013bf4, 1) :
   480:             mmrHumanVersion == 0x020f ? MC68060.mmuPeekLongData (0x00013c9c, 1) :
   481:             mmrHumanVersion == 0x0203 ? MC68060.mmuPeekLongData (0x00012b54, 1) :
   482:             mmrHumanVersion == 0x0202 ? MC68060.mmuPeekLongData (0x00012dc8, 1) :
   483:             mmrHumanVersion == 0x0201 ? MC68060.mmuPeekLongData (0x00012d88, 1) :
   484:             mmrHumanVersion == 0x0200 ? MC68060.mmuPeekLongData (0x00012d88, 1) :
   485:             mmrHumanVersion == 0x0101 ? MC68060.mmuPeekLongData (0x00008a92, 1) :
   486:             mmrHumanVersion == 0x0100 ? MC68060.mmuPeekLongData (0x00008a98, 1) :
   487:             -1);
   488:   }  //mmrHumanPmm()
   489: 
   490:   //nul = mmrHumanNul ()
   491:   //  Human68kのNULデバイスドライバのアドレスを返す
   492:   //  -1  Human68kが読み込まれていないか、未知のバージョンか、NULデバイスドライバが見つからない
   493:   //  NULデバイスドライバのアドレス
   494:   //    human100 0x0000b83e
   495:   //    human101 0x0000b84c
   496:   //    human200 0x0000ece6
   497:   //    human201 0x0000ece6
   498:   //    human202 0x0000ed36
   499:   //    human203 0x0000eac2
   500:   //    human215 0x0000fa04
   501:   //    human301 0x0000f93a
   502:   //    human302 0x0000fa50 human295
   503:   public static int mmrHumanNul () {
   504:     int a = (mmrHumanVersion == 0x0302 ||
   505:              mmrHumanVersion == 0x025f ? 0x0000fa50 :
   506:              mmrHumanVersion == 0x0301 ? 0x0000f93a :
   507:              mmrHumanVersion == 0x020f ? 0x0000fa04 :
   508:              mmrHumanVersion == 0x0203 ? 0x0000eac2 :
   509:              mmrHumanVersion == 0x0202 ? 0x0000ed36 :
   510:              mmrHumanVersion == 0x0201 ? 0x0000ece6 :
   511:              mmrHumanVersion == 0x0200 ? 0x0000ece6 :
   512:              mmrHumanVersion == 0x0101 ? 0x0000b84c :
   513:              mmrHumanVersion == 0x0100 ? 0x0000b83e :
   514:              -1);
   515:     return (a >= 0 &&
   516:             MC68060.mmuPeekLongData (a + 14, 1) == ('N' << 24 | 'U' << 16 | 'L' << 8 | ' ') &&
   517:             MC68060.mmuPeekLongData (a + 18, 1) == (' ' << 24 | ' ' << 16 | ' ' << 8 | ' ') ? a : -1);
   518:   }  //mmrHumanNul()
   519: 
   520:   //dev = mmrHumanDev (name1, name2)
   521:   //  Human68kに組み込まれている指定された名前のデバイスドライバのアドレスを返す
   522:   //  同じ名前のデバイスドライバが複数組み込まれているときは最後に見つかったものを返す
   523:   //  最初の100個までに見つからなかったら諦める
   524:   //  -1  Human68kが読み込まれていないか、未知のバージョンか、指定された名前のデバイスドライバが見つからない
   525:   //  CONデバイスの場合
   526:   //    con = mmrHumanDev ('C' << 24 | 'O' << 16 | 'N' << 8 | ' ', ' ' << 24 | ' ' << 16 | ' ' << 8 | ' ');
   527:   public static int mmrHumanDev (int name1, int name2) {
   528:     int dev = -1;
   529:     for (int a = mmrHumanNul (), i = 0; a >= 0 && i < 100; a = MC68060.mmuPeekLongData (a, 1), i++) {
   530:       //!!! ローカルメモリまで辿れない
   531:       if (MC68060.mmuPeekLongData (a + 14, 1) == name1 && MC68060.mmuPeekLongData (a + 18, 1) == name2) {  //見つかった
   532:         dev = a;
   533:         //最後に見つかったものを返すので見つかっても続ける
   534:       }
   535:     }
   536:     return dev;  //最後に見つかったデバイスドライバ
   537:   }  //mmrHumanDev(int,int)
   538: 
   539:   //mmrCheckHuman ()
   540:   //  Human68kのバージョンを確認してパッチをあてる
   541:   //  IOCS _BOOTINFで呼び出される
   542:   public static void mmrCheckHuman () {
   543:     if (mmrHumanVersion != 0) {  //確認済み
   544:       return;
   545:     }
   546:     //Human68kが起動デバイスを確認するときに呼び出した_BOOTINFであることを確認する
   547:     if (!(MC68060.mmuPeekLongData (0x00001c00, 1) != 0 &&  //_MALLOCできるメモリ空間の末尾アドレス+1が設定されていて
   548:           MC68060.mmuPeekLongData (0x00001c1c, 1) == 0)) {  //最後のデバイスドライバがまだ設定されていない
   549:       return;
   550:     }
   551:     //Human68kのバージョンを確認する
   552:     //  タイトルメッセージの領域はスタックエリアになって$FFで充填されているのでシェル起動後は確認できない
   553:     //  _VERNUMのコードを直接読み出す
   554:     //    human100  0x00009ae4  0x0100
   555:     //    human101  0x00009aee  0x0101
   556:     //    human200  0x00009ee4  0x0200
   557:     //    human201  0x00009ee4  0x0201
   558:     //    human202  0x00009ed6  0x0202
   559:     //    human203  0x00009d7e  0x0203
   560:     //    human215  0x0000a4fa  0x020f  //0x0215ではない
   561:     //    human301  0x0000a3c6  0x0301
   562:     //    human302  0x0000a4ac  0x0302 human295
   563:     //  0000A4AC  303C3638      move.w  #$3638,d0
   564:     //  0000A4B0  4840          swap.w  d0
   565:     //  0000A4B2  303C0302      move.w  #$0302,d0
   566:     //  0000A4B6  4E75          rts
   567:     mmrHumanVersion = (MC68060.mmuPeekWordZeroData (0x0000a4ac + 8, 1) == 0x0302 ? 0x0302 :
   568:                        MC68060.mmuPeekWordZeroData (0x0000a4ac + 8, 1) == 0x025f ? 0x025f :
   569:                        MC68060.mmuPeekWordZeroData (0x0000a3c6 + 8, 1) == 0x0301 ? 0x0301 :
   570:                        MC68060.mmuPeekWordZeroData (0x0000a4fa + 8, 1) == 0x020f ? 0x020f :  //0x0215ではない
   571:                        MC68060.mmuPeekWordZeroData (0x00009d7e + 8, 1) == 0x0203 ? 0x0203 :
   572:                        MC68060.mmuPeekWordZeroData (0x00009ed6 + 8, 1) == 0x0202 ? 0x0202 :
   573:                        MC68060.mmuPeekWordZeroData (0x00009ee4 + 8, 1) == 0x0201 ? 0x0201 :
   574:                        MC68060.mmuPeekWordZeroData (0x00009ee4 + 8, 1) == 0x0200 ? 0x0200 :
   575:                        MC68060.mmuPeekWordZeroData (0x00009aee + 8, 1) == 0x0101 ? 0x0101 :
   576:                        MC68060.mmuPeekWordZeroData (0x00009ae4 + 8, 1) == 0x0100 ? 0x0100 :
   577:                        -1);  //Human68kが読み込まれていないか、未知のバージョン
   578:     if (mmrHumanVersion < 0) {  //Human68kが読み込まれていないか、未知のバージョン
   579:       return;
   580:     }
   581:     //Human68kにパッチをあてる
   582:     int patched = 0;
   583:     int failed = 0;
   584:     switch (mmrHumanVersion) {
   585: 
   586:     case 0x0215:
   587: 
   588:       //RAMまたはROMから起動してDISK2HDを初期化するときリクエストヘッダの初期化コマンドを設定していない(human215,human301,human302)
   589:       //                                                   →                          sf.b    ($0002,a5)
   590:       //  0000802E  61005F74      bsr.w   ~00DEFA
   591:       //  00008032  082900070004  btst.b  #$07,($0004,a1)  →                          tst.b   ($0004,a1)
   592:       //  00008038  6618          bne.s   $00008052        →                          bmi.s   $00008052
   593: 
   594:       //MOVE from SRをMOVE from CCRに変更した後のキャッシュフラッシュを68010~68060に対応させる
   595:       //  000086EC  4E7A0002      movec.l cacr,d0          →  2F01          move.l  d1,-(sp)
   596:       //                                                       7203          moveq.l #3,d1
   597:       //  000086F0  807C0008      or.w    #$0008,d0        →  70AC4E4F      IOCS    _SYS_STAT
   598:       //  000086F4  4E7B0002      movec.l d0,cacr          →  221F          move.l  (sp)+,d1
   599:       //                                                       2048          movea.l a0,a0
   600:       if (MC68060.mmuPeekLongData (0x000086ec, 1) == 0x4e7a0002) {
   601:         MC68060.mmuPokeLongData (0x000086ec, 0x2f017203, 1);
   602:         MC68060.mmuPokeLongData (0x000086f0, 0x70ac4e4f, 1);
   603:         MC68060.mmuPokeLongData (0x000086f4, 0x221f2048, 1);
   604:         patched++;
   605:       } else {
   606:         failed++;
   607:       }
   608: 
   609:       //x形式のヘッダのメモリアロケーションモードが必要最小ブロックからかどうかをテストするbit番号が間違っている(human215,human301,human302)
   610:       //  00009A5A  08010001      btst.l  #$01,d1          →  00009A5A  08010000      btst.l  #$00,d1
   611:       if (MC68060.mmuPeekLongData (0x00009a5a, 1) == 0x08010001) {
   612:         MC68060.mmuPokeByteData (0x00009a5a + 3, 0x00, 1);
   613:         patched++;
   614:       } else {
   615:         failed++;
   616:       }
   617: 
   618:       //ディレクトリを延長するときルートディレクトリかどうかを判断するためにセクタ番号をデータ部の先頭セクタ番号と比較するとき上位ワードを無視している(human215,human301,human302)
   619:       //                                                   →            7000          moveq.l #$00,d0
   620:       //  0000B900  30280014      move.w  ($0014,a0),d0
   621:       //  0000B904  B240          cmp.w   d0,d1            →            B280          cmp.l   d0,d1
   622:       //  0000B906  6406          bcc.s   $0000B90E
   623:       //  0000B908  5241          addq.w  #$01,d1
   624:       //  0000B90A  B240          cmp.w   d0,d1
   625:       //  0000B90C  4E75          rts
   626:       //  0000B90E
   627: 
   628:       //FILESのバッファのアドレスのbit31がセットされているとき拡張部分をコピーするループのループカウンタのレジスタが間違っている(human215)
   629:       //  0000BC3E  7255          moveq.l #$55,d1
   630:       //  0000BC40  12D8          move.b  (a0)+,(a1)+
   631:       //  0000BC42  51C8FFFC      dbra.w  d0,$0000BC40     →  0000BC42  51C9FFFC      dbra.w  d1,$0000BC40
   632:       if (MC68060.mmuPeekWordZeroData (0x0000bc42, 1) == 0x51c8) {
   633:         MC68060.mmuPokeByteData (0x0000bc42 + 1, 0xc9, 1);
   634:         patched++;
   635:       } else {
   636:         failed++;
   637:       }
   638: 
   639:       //リモートデバイスに対するchmodコマンドのコマンド番号が間違っている(human215)
   640:       //  0000D848  7057          moveq.l #$57,d0          →  0000D848  7046          moveq.l #$46,d0
   641:       if (MC68060.mmuPeekWordZeroData (0x0000d848, 1) == 0x7057) {
   642:         MC68060.mmuPokeByteData (0x0000d848 + 1, 0x46, 1);
   643:         patched++;
   644:       } else {
   645:         failed++;
   646:       }
   647: 
   648:       //サブのメモリ空間を削除するときサブの管理下で常駐したブロックをメインのメモリ空間からサブのメモリ空間に入る方向に繋いでいない(human215,human301,human302)
   649: 
   650:       //スレッドを切り替えるためのTimer-D割り込みルーチンがMC68030のコプロセッサ命令途中割り込みに対応していない(human215,human301,human302)
   651: 
   652:       //IOCTRL(19,1)でBPBテーブルをコピーする長さとPDAとイジェクトフラグを書き込む位置が間違っている(human215,human301,human302)
   653:       //  00010AE8  700B          moveq.l #$0B,d0          →  00010AE8  700F          moveq.l #$0F,d0
   654:       //  00010AEA  10DE          move.b  (a6)+,(a0)+
   655:       //  00010AEC  51C8FFFC      dbra.w  d0,$00010AEA
   656:       if (MC68060.mmuPeekWordZeroData (0x00010ae8, 1) == 0x700b) {
   657:         MC68060.mmuPokeByteData (0x00010ae8 + 1, 0x0f, 1);
   658:         patched++;
   659:       } else {
   660:         failed++;
   661:       }
   662: 
   663:       //IOCTRL(19,0)でBPBテーブルのハンドルをBPBテーブルのアドレスとして参照しようとしている(human215)
   664:       //  00FCA520  61000084      bsr.w   $00FCA5A6
   665:       //  00FCA524  206D000E      movea.l $000E(a5),a0
   666:       //  ;BPBテーブルのハンドルを求めるときにd0.w=(d0.w&3)*4を計算しているのでd0.wの上位バイトは既に0になっている
   667:       //  00FCA528  4240          clr.w   d0               →  00FCA528  2C56          movea.l (a6),a6
   668:       //  00FCA52A  102E000A      move.b  $000A(a6),d0
   669:       //  00FCA52E  3080          move.w  d0,(a0)
   670: 
   671:       break;
   672: 
   673:     case 0x0301:
   674: 
   675:       //RAMまたはROMから起動してDISK2HDを初期化するときリクエストヘッダの初期化コマンドを設定していない(human215,human301,human302)
   676:       //
   677:       //                                                   →                          sf.b    ($0002,a5)
   678:       //  00007EE2  61005F74      bsr.w   ~00DEFA
   679:       //  00007EE6  082900070004  btst.b  #$07,($0004,a1)  →                          tst.b   ($0004,a1)
   680:       //  00007EEC  6618          bne.s   $00007F06        →                          bmi.s   $00007F06
   681: 
   682:       //MOVE from SRをMOVE from CCRに変更した後のキャッシュフラッシュを68010~68060に対応させる
   683:       //  000085B8  4E7A0002      movec.l cacr,d0          →  2F01          move.l  d1,-(sp)
   684:       //                                                       7203          moveq.l #3,d1
   685:       //  000085BC  807C0008      or.w    #$0008,d0        →  70AC4E4F      IOCS    _SYS_STAT
   686:       //  000085C0  4E7B0002      movec.l d0,cacr          →  221F          move.l  (sp)+,d1
   687:       //                                                       2048          movea.l a0,a0
   688:       if (MC68060.mmuPeekLongData (0x000085b8, 1) == 0x4e7a0002) {
   689:         MC68060.mmuPokeLongData (0x000085b8, 0x2f017203, 1);
   690:         MC68060.mmuPokeLongData (0x000085bc, 0x70ac4e4f, 1);
   691:         MC68060.mmuPokeLongData (0x000085c0, 0x221f2048, 1);
   692:         patched++;
   693:       } else {
   694:         failed++;
   695:       }
   696: 
   697:       //x形式のヘッダのメモリアロケーションモードが必要最小ブロックからかどうかをテストするbit番号が間違っている(human215,human301,human302)
   698:       //
   699:       //  00009926  08010001      btst.l  #$01,d1          →  00009926  08010000      btst.l  #$00,d1
   700:       if (MC68060.mmuPeekWordZeroData (0x00009926 + 2, 1) == 0x0001) {
   701:         MC68060.mmuPokeByteData (0x00009926 + 3, 0x00, 1);
   702:         patched++;
   703:       } else {
   704:         failed++;
   705:       }
   706: 
   707:       //ディレクトリを延長するときルートディレクトリかどうかを判断するためにセクタ番号をデータ部の先頭セクタ番号と比較するとき上位ワードを無視している(human215,human301,human302)
   708:       //
   709:       //サブのメモリ空間を削除するときサブの管理下で常駐したブロックをメインのメモリ空間からサブのメモリ空間に入る方向に繋いでいない(human215,human301,human302)
   710:       //
   711:       //スレッドを切り替えるためのTimer-D割り込みルーチンがMC68030のコプロセッサ命令途中割り込みに対応していない(human215,human301,human302)
   712:       //
   713:       //IOCTRL(19,1)でBPBテーブルをコピーする長さとPDAとイジェクトフラグを書き込む位置が間違っている(human215,human301,human302)
   714:       //
   715:       //  00010A22  700B          moveq.l #$0B,d0          →  00010A22  700F          moveq.l #$0F,d0
   716:       //  00010A24  10DE          move.b  (a6)+,(a0)+
   717:       //  00010A26  51C8FFFC      dbra.w  d0,$00010A24
   718:       if (MC68060.mmuPeekWordZeroData (0x00010a22, 1) == 0x700b) {
   719:         MC68060.mmuPokeByteData (0x00010a22 + 1, 0x0f, 1);
   720:         patched++;
   721:       } else {
   722:         failed++;
   723:       }
   724: 
   725:       break;
   726: 
   727:     case 0x0302:
   728:     case 0x025f:
   729: 
   730:       //デバイスドライバを初期化する直前と初期化した直後
   731:       //<a1.l:初期化されたデバイスドライバのデバイスヘッダのアドレス
   732:       //  00007140  1B7C00160000  move.b  #$16,$0000(a5)  →  00007140  4E04          emxnop
   733:       //                                                  →  00007142  2209          move.l  a1,d1
   734:       //                                                  →  00007144  1ABC0016      move.b  #$16,(a5)
   735:       //  00007146  1B7C00000002  move.b  #$00,$0002(a5)  →
   736:       //                                                  →  00007148  51ED0002      sf.b    $0002(a5)
   737:       //  0000714C  082900050004  btst.b  #$05,$0004(a1)
   738:       //  00007152  6706          beq.s   $0000715A
   739:       //  00007154  1B7C00400002  move.b  #$40,$0002(a5)
   740:       //  0000715A  2B400012      move.l  d0,$0012(a5)
   741:       //  0000715E  10381C75      move.b  $1C75.w,d0
   742:       //  00007162  5200          addq.b  #$01,d0
   743:       //  00007164  1B400016      move.b  d0,$0016(a5)
   744:       //  00007168  2209          move.l  a1,d1           →  00007168  61006D90      bsr.w   $0000DEFA
   745:       //  0000716A  2241          movea.l d1,a1           →
   746:       //  0000716C  60006D8C      bra.w   $0000DEFA       →  0000716C  4E04          emxnop
   747:       //                                                  →  0000716E  4E75          rts
   748:       if (MC68060.mmuPeekLongData (0x00007140, 1) == 0x1b7c0016) {
   749:         MC68060.mmuPokeLongData (0x00007140, XEiJ.EMX_OPCODE_EMXNOP << 16 | 0x2209, 1);
   750:         MC68060.mmuPokeLongData (0x00007144, 0x1abc0016, 1);
   751:         MC68060.mmuPokeLongData (0x00007148, 0x51ed0002, 1);
   752:         MC68060.mmuPokeLongData (0x00007168, 0x61006d90, 1);
   753:         MC68060.mmuPokeLongData (0x0000716c, XEiJ.EMX_OPCODE_EMXNOP << 16 | 0x4e75, 1);
   754:         patched++;
   755:       } else {
   756:         failed++;
   757:       }
   758: 
   759:       //ブロックデバイスのユニット数が0の場合に対応する
   760:       //  00007FA4  6B00F152      bmi.w   $000070F8           7FA4  6B00F156  bmi.w   $000070FC
   761:       //  
   762:       //  000070E2  082900070004  btst.b  #$07,$0004(a1)      70E2  4A290004  tst.b   $0004(a1)
   763:       //                                                      70E6  6B28      bmi.s   $00007110
   764:       //  000070E8  6626          bne.s   $00007110           70E8  4A2D000D  tst.b   $000D(a5)
   765:       //  000070EA  204D          movea.l a5,a0
   766:       //  000070EC  610011E2      bsr.w   $000082D0           70EC  6722      beq.s   $00007110
   767:       //                                                      70EE  204D      movea.l a5,a0
   768:       //  000070F0  6B12          bmi.s   $00007104           70F0  610011DE  bsr.w   $000082D0
   769:       //  000070F2  61001154      bsr.w   $00008248
   770:       //                                                      70F4  6B0E      bmi.s   $00007104
   771:       //  000070F6  6A1C          bpl.s   $00007114           70F6  61001150  bsr.w   $00008248
   772:       //  000070F8  41F900007DBD  lea.l   $00007DBD.l,a0
   773:       //                                                      70FA  6A18      bpl.s   $00007114
   774:       //                                                      70FC  41FA0CBF  lea.l   $00007DBD(pc),a0
   775:       //  000070FE  6134          bsr.s   $00007134
   776:       //  00007100  6000F826      bra.w   $00006928           7100  6132      bsr.s   $00007134
   777:       //                                                      7102  6008      bra.s   $0000710C
   778: /*
   779:       if (MC68060.mmuPeekLongData (0x00007fa4, 1) == 0x6b00f152) {
   780:         MC68060.mmuPokeLongData (0x00007fa4, 0x6b00f156, 1);
   781:         MC68060.mmuPokeLongData (0x000070e2, 0x4a290004, 1);
   782:         MC68060.mmuPokeLongData (0x000070e6, 0x6b284a2d, 1);
   783:         MC68060.mmuPokeLongData (0x000070ea, 0x000d6722, 1);
   784:         MC68060.mmuPokeLongData (0x000070ee, 0x204d6100, 1);
   785:         MC68060.mmuPokeLongData (0x000070f2, 0x11de6b0e, 1);
   786:         MC68060.mmuPokeLongData (0x000070f6, 0x61001150, 1);
   787:         MC68060.mmuPokeLongData (0x000070fa, 0x6a1841fa, 1);
   788:         MC68060.mmuPokeLongData (0x000070fe, 0x0cbf6132, 1);
   789:         MC68060.mmuPokeWordData (0x00007102, 0x6008, 1);
   790:         patched++;
   791:       } else {
   792:         failed++;
   793:       }
   794: */
   795: 
   796:       //RAMまたはROMから起動してDISK2HDを初期化するときリクエストヘッダの初期化コマンドを設定していない(human215,human301,human302)
   797:       //
   798:       //                                                   →                          sf.b    ($0002,a5)
   799:       //  00007F84  61005F74      bsr.w   ~00DEFA
   800:       //  00007F88  082900070004  btst.b  #$07,($0004,a1)  →                          tst.b   ($0004,a1)
   801:       //  00007F8E  6618          bne.s   $00007FA8        →                          bmi.s   $00007FA8
   802:       //
   803: 
   804:       //MOVE from SRをMOVE from CCRに変更した後のキャッシュフラッシュを68010~68060に対応させる
   805:       //  0000865A  4E7A0002      movec.l cacr,d0          →  2F01          move.l  d1,-(sp)
   806:       //                                                       7203          moveq.l #3,d1
   807:       //  0000865E  807C0008      or.w    #$0008,d0        →  70AC4E4F      IOCS    _SYS_STAT
   808:       //  00008662  4E7B0002      movec.l d0,cacr          →  221F          move.l  (sp)+,d1
   809:       //                                                       2048          movea.l a0,a0
   810:       if (MC68060.mmuPeekLongData (0x0000865a, 1) == 0x4e7a0002) {
   811:         MC68060.mmuPokeLongData (0x0000865a, 0x2f017203, 1);
   812:         MC68060.mmuPokeLongData (0x0000865e, 0x70ac4e4f, 1);
   813:         MC68060.mmuPokeLongData (0x00008662, 0x221f2048, 1);
   814:         patched++;
   815:       } else {
   816:         failed++;
   817:       }
   818: 
   819:       //プロセスを起動する直前
   820:       //  0000971E  2B48001C      move.l  a0,$001C(a5)    →  0000971E  48ED1F00001C  movem.l a0-a4,$001C(a5)
   821:       //  00009722  2B490020      move.l  a1,$0020(a5)    →
   822:       //                                                      00009724  200C          move.l  a4,d0
   823:       //  00009726  2B4A0024      move.l  a2,$0024(a5)    →  00009726  4A41          tst.w   d1
   824:       //                                                      00009728  6600FE30      bne.w   $0000955A
   825:       //  0000972A  2B4B0028      move.l  a3,$0028(a5)    →
   826:       //                                                      0000972C  4E04          emxnop
   827:       //  0000972E  2B4C002C      move.l  a4,$002C(a5)    →  0000972E  600A          bra.s   $0000973A
   828:       //  00009732  200C          move.l  a4,d0           →
   829:       //  00009734  4A41          tst.w   d1              →
   830:       //  00009736  6600FE22      bne.w   $0000955A       →
   831:       if (MC68060.mmuPeekLongData (0x0000971e, 1) == 0x2b48001c) {
   832:         MC68060.mmuPokeWordData (0x0000971e, 0x48ed, 1);
   833:         MC68060.mmuPokeLongData (0x00009720, 0x1f00001c, 1);
   834:         MC68060.mmuPokeLongData (0x00009724, 0x200c4a41, 1);
   835:         MC68060.mmuPokeLongData (0x00009728, 0x6600fe30, 1);
   836:         MC68060.mmuPokeLongData (0x0000972c, XEiJ.EMX_OPCODE_EMXNOP << 16 | 0x600a, 1);
   837:         patched++;
   838:       } else {
   839:         failed++;
   840:       }
   841: 
   842:       //x形式のヘッダのメモリアロケーションモードが必要最小ブロックからかどうかをテストするbit番号が間違っている(human215,human301,human302)
   843:       //
   844:       //  000099C4  08010001      btst.l  #$01,d1          →  000099C4  08010000      btst.l  #$00,d1
   845:       if (XEiJ.currentMPU < Model.MPU_MC68LC060) {  //060turbo.sysのパッチと衝突する
   846:         if (MC68060.mmuPeekWordZeroData (0x000099c4 + 2, 1) == 0x0001) {
   847:           MC68060.mmuPokeByteData (0x000099c4 + 3, 0x00, 1);
   848:           patched++;
   849:         } else {
   850:           failed++;
   851:         }
   852:       }
   853: 
   854:       //プロセスが常駐した直後
   855:       //<a0.l:常駐したプロセスのメモリ管理テーブルのアドレス
   856:       //  0000A088  4A380CBC      tst.b   $0CBC.w
   857:       //  0000A08C  6704          beq.s   $0000A092       →  0000A08C  6702          beq.s   $0000A090
   858:       //  0000A08E  3F3C0000      move.w  #$0000,-(sp)    →  0000A08E  4267          clr.w   -(sp)
   859:       //                                                  →  0000A090  4E04          emxnop
   860:       //  0000A092
   861:       if (MC68060.mmuPeekWordZeroData (0x0000a08c, 1) == 0x6704 &&
   862:           MC68060.mmuPeekLongData (0x0000a08e, 1) == 0x3f3c0000) {
   863:         MC68060.mmuPokeLongData (0x0000a08c, 0x67024267, 1);
   864:         MC68060.mmuPokeWordData (0x0000a090, XEiJ.EMX_OPCODE_EMXNOP, 1);
   865:         patched++;
   866:       } else {
   867:         failed++;
   868:       }
   869: 
   870:       //仮想ディレクトリを展開して実体のドライブに移るときドライブ管理テーブルのアドレスを変更する命令のオペレーションサイズが間違っている(human302)
   871:       //
   872:       //  0000B2EA  324C          movea.w a4,a1            →  0000B2EA  224C          movea.l a4,a1
   873:       if (MC68060.mmuPeekWordZeroData (0x0000b2ea, 1) == 0x324c) {
   874:         MC68060.mmuPokeByteData (0x0000b2ea + 0, 0x22, 1);
   875:         patched++;
   876:       } else {
   877:         failed++;
   878:       }
   879: 
   880:       //ディレクトリを延長するときルートディレクトリかどうかを判断するためにセクタ番号をデータ部の先頭セクタ番号と比較するとき上位ワードを無視している(human215,human301,human302)
   881:       //
   882:       //                                                   →            7000          moveq.l #$00,d0
   883:       //  0000B8E2  30280014      move.w  ($0014,a0),d0
   884:       //  0000B8E6  B240          cmp.w   d0,d1            →            B280          cmp.l   d0,d1
   885:       //  0000B8E8  6406          bcc.s   $0000B8F0
   886:       //  0000B8EA  5241          addq.w  #$01,d1          →            5281          addq.l  #$01,d1
   887:       //  0000B8EC  B240          cmp.w   d0,d1            →            B280          cmp.l   d0,d1
   888:       //  0000B8EE  4E75          rts
   889: 
   890:       //サブのメモリ空間を削除するときサブの管理下で常駐したブロックをメインのメモリ空間からサブのメモリ空間に入る方向に繋いでいない(human215,human301,human302)
   891: 
   892:       //スレッドを切り替えるためのTimer-D割り込みルーチンがMC68030のコプロセッサ命令途中割り込みに対応していない(human215,human301,human302)
   893: 
   894:       //IOCTRL(19,1)でBPBテーブルをコピーする長さとPDAとイジェクトフラグを書き込む位置が間違っている(human215,human301,human302)
   895:       //  00010B38  700B          moveq.l #$0B,d0          →  00010B38  700F          moveq.l #$0F,d0
   896:       //  00010B3A  10DE          move.b  (a6)+,(a0)+
   897:       //  00010B3C  51C8FFFC      dbra.w  d0,$00010B3A
   898:       if (MC68060.mmuPeekWordZeroData (0x00010b38, 1) == 0x700b) {
   899:         MC68060.mmuPokeByteData (0x00010b38 + 1, 0x0f, 1);
   900:         patched++;
   901:       } else {
   902:         failed++;
   903:       }
   904:       //
   905:       break;
   906:     }
   907: 
   908:     //  Humanのline 1111 emulator/privilege violation例外処理ルーチンの手前にFLOATn.Xのマジック'FEfn'を押し込む
   909:     //    手前にある_EXITVC/_CTRLVC/_ERRJVCのコードを詰めて隙間を作る
   910:     //  Human自身がFLOATn.Xのマジックを持つことでFLOATn.Xを組み込めなくする
   911:     //    シェルが正常終了した
   912:     //      00008518  6140          bsr.s   $0000855A       1行改行
   913:     //      0000851A  4879000111AE  pea.l   $000111AE.l     '終了しました。',$00
   914:     //      00008520  FF09          DOS     _PRINT
   915:     //      00008522  588F          addq.l  #$04,sp
   916:     //      00008524  4879000111BD  pea.l   $000111BD.l     'コマンドを、入力してください',$0D,$0A,'#',$00
   917:     //      0000852A  6006          bra.s   $00008532
   918:     //    コマンド入力ループ
   919:     //      0000852C  4879000111DB  pea.l   $000111DB.l     '#',$00
   920:     //      00008532  FF09          DOS     _PRINT
   921:     //          :
   922:     //    _EXITVC/_CTRLVC/_ERRJVC
   923:     //      00008566  FF81          DOS     _GETPDB         human203まではX68030に対応していないため_GETPDBは$FF51
   924:     //      00008568  B0BC00008382  cmp.l   #$00008382,d0   Humanのプロセス管理テーブル
   925:     //      0000856E  6626          bne.s   $00008596       →  0000856E  6622          bne.s   $00008592
   926:     //    シェルが停止した
   927:     //      00008570  4FF900008372  lea.l   $00008372.l,sp  スタック復元
   928:     //      00008576  42A7          clr.l   -(sp)
   929:     //      00008578  FF20          DOS     _SUPER
   930:     //      0000857A  588F          addq.l  #$04,sp
   931:     //      0000857C  207900011090  movea.l $00011090.l,a0  ユーザスタックエリアのアドレス
   932:     //      00008582  41E800F0      lea.l   $00F0(a0),a0
   933:     //      00008586  4E60          move.l  a0,usp
   934:     //      00008588  61D0          bsr.s   $0000855A       1行改行
   935:     //      0000858A  4879000111DD  pea.l   $000111DD.l     '停止しました。',$00
   936:     //      00008590  FF09          DOS     _PRINT          →  00008590  608E          bra.s   $00008520
   937:     //      00008592  588F          addq.l  #$04,sp         →  00008592  FF00          DOS     _EXIT
   938:     //      00008594  608E          bra.s   $00008524       →  00008594  4645          .dc.w   'FE'
   939:     //    シェル以外のプロセスが停止した
   940:     //      00008596  FF00          DOS     _EXIT           →  00008596  666E          .dc.w   'fn'
   941:     //    line 1111 emulator/privilege violation
   942:     //      00008598  48E78006      movem.l d0/a5-a6,-(sp)  human203まではX68030に対応していないためline 1111 emulatorのコードが異なる
   943:     if (FEFunction.fpkRejectFloatOn) {
   944:       int fline = (mmrHumanVersion == 0x0302 ||
   945:                    mmrHumanVersion == 0x025f ? 0x00008598 :
   946:                    mmrHumanVersion == 0x0301 ? 0x000084f6 :
   947:                    mmrHumanVersion == 0x020f ? 0x00008642 :
   948:                    mmrHumanVersion == 0x0203 ? 0x00007f58 :
   949:                    mmrHumanVersion == 0x0202 ? 0x00007fd6 :
   950:                    mmrHumanVersion == 0x0201 ? 0x00007fb6 :
   951:                    mmrHumanVersion == 0x0200 ? 0x00007fb6 :  //human200はhuman201と同じ
   952:                    //human101とhuman100はコードが異なるのでここでは非対応とする
   953:                    -1);
   954:       if (fline > 0) {
   955:         if (MC68060.mmuPeekWordZeroData (0x0000856e - 0x00008598 + fline, 1) == 0x6626 &&
   956:             MC68060.mmuPeekLongData (0x00008590 - 0x00008598 + fline, 1) == 0xff09588f &&
   957:             MC68060.mmuPeekLongData (0x00008594 - 0x00008598 + fline, 1) == 0x608eff00) {
   958:           MC68060.mmuPokeWordData (0x0000856e - 0x00008598 + fline, 0x6622, 1);
   959:           MC68060.mmuPokeLongData (0x00008590 - 0x00008598 + fline, 0x608eff00, 1);
   960:           MC68060.mmuPokeLongData (0x00008594 - 0x00008598 + fline, 0x4645666e, 1);
   961:           patched++;
   962:         } else {
   963:           failed++;
   964:         }
   965:       }
   966:     }
   967: 
   968:     System.out.println (new StringBuilder ().
   969:                         append ("Human68k version ").
   970:                         append ((char) ('0' + (mmrHumanVersion >> 8) % 10)).
   971:                         append ('.').
   972:                         append ((char) ('0' + (mmrHumanVersion & 255) / 10)).
   973:                         append ((char) ('0' + (mmrHumanVersion & 255) % 10)).
   974:                         append (Multilingual.mlnJapanese ? " にパッチをあてました (" : " was patched (").
   975:                         append (patched).
   976:                         append ('/').
   977:                         append (patched + failed).
   978:                         append (')').toString ());
   979:     //FEファンクション命令を有効にする
   980:     mmrFEfuncActivated = FEFunction.fpkOn;
   981:     if (mmrFEfuncActivated) {
   982:       System.out.println (Multilingual.mlnJapanese ?
   983:                           "FE ファンクション命令が有効になりました" :
   984:                           "FE function instruction has been activated");
   985:     }
   986:   }  //mmrCheckHuman()
   987: 
   988:   //pc = mmrGetLevelZeroPC ()
   989:   //  DOSコールにレベル0で入ったときのpcを返す。0=DOSコールの中でないか不明
   990:   public static int mmrGetLevelZeroPC () {
   991:     if (0x020f <= mmrHumanVersion) {  //Human 2.15以上
   992:       int level = MC68060.mmuPeekWordZeroData (0x1c08, XEiJ.regSRS);  //DOSコールのレベル
   993:       if (level != 0) {
   994:         int ssp = MC68060.mmuPeekLongData (0x1c5c, XEiJ.regSRS);  //DOSコールにレベル0で入ったときのssp
   995:         int pc = MC68060.mmuPeekLongData (ssp + 0x3a, XEiJ.regSRS);  //DOSコールにレベル0で入ったときのpc
   996:         return pc;
   997:       }
   998:     }
   999:     return 0;
  1000:   }  //mmrGetLevelZeroPC
  1001: 
  1002: }  //class MainMemory
  1003: 
  1004: 
  1005: