1: //======================================================================================== 2: // HDMedia.java 3: // en:SASI hard disk media 4: // ja:SASIハードディスクメディア 5: // Copyright (C) 2003-2019 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: //SASIハードディスクのメディアの種類 15: // 16: // アドレス 17: // 00000000 SASIディスクIPL 18: // IPLROMが$2000.wに読み込んで実行する 19: // 起動パーティションを自動または手動で選択し、選択されたパーティションのSASIパーティションIPLを$2400.wに読み込んで実行する 20: // 21: // 00000400 パーティションテーブル 22: // 10MB 20MB 40MB 23: // 00000400 0x5836384b 0x5836384b 0x5836384b X68Kマジック 24: // 00000404 0x00009f54 0x00013c98 0x00027930 レコード数(ディスクイメージではこのサイズで保存する) 25: // 00000408 0x00009f54 0x00013c98 0x00027930 代替レコード 26: // 0000040c 0x0000af50 0x00015660 0x0002acc0 ランプレコード 27: // 00000410 第1パーティションの情報 28: // 10MB 20MB 40MB 29: // 00000410 0x48756d61 0x48756d61 0x48756d61 Humaマジック 30: // 00000414 0x6e36386b 0x6e36386b 0x6e36386b n68kマジック 31: // 00000418 0x00000021 0x00000021 0x00000021 開始レコード 32: // 0000041c 0x00009f2e 0x00013c68 0x000278f8 レコード数 33: // 00000420 第2パーティションの情報 34: // : 35: // 000004f0 第15パーティションの情報 36: // 00000500 空き 37: // : 38: // 39: // 第1パーティション(10MBの装置に最大サイズのパーティションを確保した場合) 40: // アドレス セクタ 41: // 00002100 00000000 SASIパーティションIPL 42: // SASIディスクIPLが$2400.wに読み込んで実行する 43: // ルートディレクトリにあるHUMAN.SYSを$6800.wに読み込んで実行する 44: // 00002500 00000001 第1FAT 45: // 00007500 00000015 第2FAT 46: // 0000c500 00000029 ルートディレクトリ 47: // 00010500 00000039 データ領域 48: // 49: // ドライブ情報(最大サイズのパーティションを確保した場合) 50: // 10MB 20MB 40MB 51: // 1024 1024 1024 バイト/セクタ 52: // 1 1 1 セクタ/クラスタ 53: // 10132 20155 40335 データ領域のクラスタ数+2 54: // 1 1 1 予約領域のセクタ数 55: // 20 40 80 1個のFAT領域に使用するセクタ数 56: // 41 81 161 ルートディレクトリの先頭セクタ番号 57: // 512 512 512 ルートディレクトリに入るエントリ数 58: // 57 97 177 データ領域の先頭セクタ番号 59: // 60: // X68000のSASIハードディスクの物理的な構成に関する考察 61: // FORMAT.XのSASIハードディスクの装置初期化で送られてくるFormatBlockコマンドのレコード番号は33ずつ増えている 62: // フロッピーディスクと同様にトラック単位で初期化していると考えられる 63: // 00ff9858 hdcDoCommand() [0x06,0x00,0x00,0x00,0x01,0x00] 64: // 00ff9858 hdcDoCommand() [0x06,0x00,0x00,0x21,0x01,0x00] 65: // 00ff9858 hdcDoCommand() [0x06,0x00,0x00,0x42,0x01,0x00] 66: // : 67: // 00ff9858 hdcDoCommand() [0x06,0x02,0x78,0xcd,0x01,0x00] 68: // 00ff9858 hdcDoCommand() [0x06,0x02,0x78,0xee,0x01,0x00] 69: // 00ff9858 hdcDoCommand() [0x06,0x02,0x79,0x0f,0x01,0x00] 70: // 実際、X68000で利用できるSASIハードディスクのレコード数はすべて33で割り切れる 71: // IBM PC/AT(1984年)の20MBのハードディスクは512バイト/レコード*17レコード/トラック*4トラック/シリンダ*614シリンダという情報を参考にすると、 72: // X68000 ACE-HD(1988年)の20MBのハードディスクは256バイト/レコード*33レコード/トラック*4トラック/シリンダ*614シリンダと考えると調度よい 73: // https://en.wikipedia.org/wiki/Timeline_of_DOS_operating_systems 74: // ドライブパラメータの詳細は不明だが4~5バイト目が10MB=[$03,$01],20MB=[$03,$02],40MB=[$07,$02]となっており、 75: // 10MB→20MBと20MB→40MBでは2倍になった項目が異なる可能性がある 76: //---------------------------------------------------------------------------------------- 77: 78: package xeij; 79: 80: import java.lang.*; //Boolean,Character,Class,Comparable,Double,Exception,Float,IllegalArgumentException,Integer,Long,Math,Number,Object,Runnable,SecurityException,String,StringBuilder,System 81: import java.util.*; //ArrayList,Arrays,Calendar,GregorianCalendar,HashMap,Map,Map.Entry,Timer,TimerTask,TreeMap 82: 83: public class HDMedia extends HumanMedia { 84: 85: public static final HDMedia[] HDM_ARRAY = { 86: // 開始 終了 全体 ランプ 87: new HDMedia (0, "SASI HDD (10MB)", 256, 0x00000021, 0x00009f4f, 0x00009f54, 0x0000af50), //10441728=256*33*4*309 88: new HDMedia (1, "SASI HDD (20MB)", 256, 0x00000021, 0x00013c89, 0x00013c98, 0x00015660), //20748288=256*33*4*614 89: new HDMedia (2, "SASI HDD (40MB)", 256, 0x00000021, 0x00027919, 0x00027930, 0x0002acc0), //41496576=256*33*8*614 90: }; 91: public static final HDMedia HDM_10MB = HDM_ARRAY[0]; 92: public static final HDMedia HDM_20MB = HDM_ARRAY[1]; 93: public static final HDMedia HDM_40MB = HDM_ARRAY[2]; 94: public static final int HDM_MAX_BYTES_PER_DISK = (int) HDM_40MB.humDiskEndByte; //HDM_ARRAYにあるhumDiskEndByteの最大値 95: 96: //media = hdmLengthToMedia (longLength) 97: // ディスクイメージファイルのサイズに合うメディアを返す 98: // 同じサイズでフォーマットの異なるメディアが複数あるときは最初に見つかったものを返す 99: public static HDMedia hdmLengthToMedia (long longLength) { 100: for (HDMedia media : HDM_ARRAY) { 101: if (media.humDiskEndByte == longLength) { 102: return media; 103: } 104: } 105: return null; 106: } //hdmLengthToMedia(long) 107: 108: //media = hdmPathToMedia (length, bb) 109: // パスに合うメディアを返す。null=見つからない 110: // バッファを指定したときはそこにコピーする 111: public static HDMedia hdmPathToMedia (String path, byte[] bb) { 112: byte[] array = XEiJ.rscGetFile (path); 113: if (array == null) { //読み込めない 114: return null; 115: } 116: HDMedia media = hdmLengthToMedia ((long) array.length); //メディアの種類 117: if (media == null) { //不明 118: System.out.println (Multilingual.mlnJapanese ? 119: path + " は SASI ハードディスクのイメージファイルではありません" : 120: path + " is not a SASI hard disk image file"); 121: return null; 122: } 123: System.out.println (Multilingual.mlnJapanese ? 124: path + " は " + media.hdmName + " です" : 125: path + " is " + media.hdmName); 126: /* 127: if (ByteArray.byaRls (hduImage, 0x00000400) != 0x5836384b) { //X68K 128: //装置初期化されていない 129: return true; 130: } 131: if (!(ByteArray.byaRls (hduImage, 0x00000410) == 0x48756d61 && 132: ByteArray.byaRls (hduImage, 0x00000414) == 0x6e36386b && 133: ByteArray.byaRls (hduImage, 0x00000418) == 0x00000021 && 134: ByteArray.byaRls (hduImage, 0x0000041c) == 0x000278f8)) { 135: //先頭のパーティションがHuman68kの40MBパーティションでない 136: return true; 137: } 138: if (false) { 139: //パーティションテーブル 140: ByteArray.byaWl (hduImage, 0x00000404, 0x00013c98); //最大セクタ 141: ByteArray.byaWl (hduImage, 0x00000408, 0x00013c98); //代替セクタ 142: ByteArray.byaWl (hduImage, 0x0000040c, 0x00015660); //シッピングゾーン 143: ByteArray.byaWl (hduImage, 0x0000041c, 0x00013c68); //先頭のパーティションのブロック数 144: //IPL内のBPBテーブル 145: ByteArray.byaWl (hduImage, 0x00002112, 0x0400_01_02); //バイト/セクタ,セクタ/クラスタ,FAT領域の個数 146: ByteArray.byaWl (hduImage, 0x00002116, 0x0001_0200); //予約領域のセクタ数,ルートディレクトリのエントリ数 147: ByteArray.byaWl (hduImage, 0x0000211a, 0x4f1a_f8_28); //総クラスタ数+2,FATID,1個のFAT領域のセクタ数 148: //FATの20MBを超える部分に使用中の領域がないか確認してからルートディレクトリ以降を1024*80バイト手前にずらす 149: // 後で読み込み方法を変更して使用中の領域が20MB以下であれば読み込めるようにしたい 150: boolean error = false; 151: for (int i = 256 * (33 + 4 * 1) + 4; i < 256 * (33 + 4 * 1) + 4 + 2 * (20155 - 2); i += 2) { 152: int fat = (char) (hduImage[i] << 8 | hduImage[i + 1] & 255); 153: error |= fat >= 20155 && fat < 40335; 154: } 155: for (int i = 256 * (33 + 4 * 1) + 4 + 2 * (20155 - 2); i < 256 * (33 + 4 * 1) + 4 + 2 * (40335 - 2); i += 2) { 156: int fat = (char) (hduImage[i] << 8 | hduImage[i + 1] & 255); 157: error |= fat != 0; 158: hduImage[i] = 0; 159: hduImage[i + 1] = 0; 160: } 161: for (int i = 256 * (33 + 4 * 161); i < 256 * (33 + 4 * (97 + 20155 - 2)); i++) { 162: hduImage[i - 1024 * 80] = hduImage[i]; 163: } 164: if (error) { 165: System.out.println (Multilingual.mlnJapanese ? 166: "40MB から 20MB へ変換できませんでした" : 167: "Failed to convert from 40MB to 20MB"); 168: } 169: } 170: */ 171: if (bb != null) { 172: System.arraycopy (array, 0, bb, 0, array.length); 173: } 174: return media; 175: } //hdmPathToMedia(String,byte[]) 176: 177: 178: public int hdmNumber; //番号 179: public String hdmName; //名前 180: public int hdmBytesShiftRecord; //1レコードあたりのバイト数のシフトカウント 181: public int hdmBytesPerRecord; //1レコードあたりのバイト数(2の累乗) 182: public int hdmPartitionStartRecord; //ディスクの先頭からパーティションの先頭までのレコード数 183: public int hdmPartitionEndRecord; //ディスクの先頭からパーティションの末尾までのレコード数 184: public int hdmDiskEndRecord; //ディスクのレコード数 185: public int hdmRampRecord; //ディスクの先頭からランプレコードまでのレコード数 186: 187: public HDMedia (int number, String name, 188: int bytesPerRecord, int partitionStartRecord, int partitionEndRecord, int diskEndRecord, int rampRecord) { 189: super (1024, //bytesPerSector 190: -1, //sectorsPerCluster 191: 2, //fatCount 192: 1, //reservedSectors 193: 512, //rootEntries 194: 0xf8, //mediaByte 195: 0xf8, //fatID 196: -1, //fatSectors 197: (long) bytesPerRecord * diskEndRecord, //diskEndByte 198: (long) bytesPerRecord * partitionStartRecord, //partitionStartByte 199: (long) bytesPerRecord * partitionEndRecord); //partitionEndByte 200: //定数で与えるもの 201: hdmNumber = number; //番号 202: hdmName = name; //名前 203: hdmBytesPerRecord = bytesPerRecord; //1レコードあたりのバイト数(2の累乗) 204: hdmPartitionStartRecord = partitionStartRecord; //ディスクの先頭からパーティションの先頭までのレコード数 205: hdmPartitionEndRecord = partitionEndRecord; //ディスクの先頭からパーティションの先頭までのレコード数 206: hdmDiskEndRecord = diskEndRecord; //ディスクのレコード数 207: hdmRampRecord = rampRecord; //ディスクの先頭からランプレコードまでのレコード数 208: //定数から求まるもの 209: hdmBytesShiftRecord = Integer.numberOfTrailingZeros (hdmBytesPerRecord); //1レコードあたりのバイト数のシフトカウント 210: } //HDMedia 211: 212: //success = media.hdmMakeFormatData (bb, copySystemFiles) 213: // SASIディスクのフォーマットデータを作る 214: public boolean hdmMakeFormatData (byte[] bb, boolean copySystemFiles) { 215: Arrays.fill (bb, (byte) 0); 216: //SASIディスクIPLを書き込む 217: System.arraycopy (HDC.HDC_DISK_IPL, 0, bb, 0x00000000, HDC.HDC_DISK_IPL.length); 218: //パーティションテーブルを作る 219: ByteArray.byaWl (bb, 0x00000400, 'X' << 24 | '6' << 16 | '8' << 8 | 'K'); //X68Kマジック 220: ByteArray.byaWl (bb, 0x00000404, hdmDiskEndRecord); //ディスクのレコード数。ディスクの先頭から確保されている領域の末尾までのレコード数ではない 221: ByteArray.byaWl (bb, 0x00000408, hdmDiskEndRecord); //ディスクのレコード数 222: ByteArray.byaWl (bb, 0x0000040c, hdmRampRecord); //ランプレコード 223: ByteArray.byaWl (bb, 0x00000410, 'H' << 24 | 'u' << 16 | 'm' << 8 | 'a'); //Humaマジック 224: ByteArray.byaWl (bb, 0x00000414, 'n' << 24 | '6' << 16 | '8' << 8 | 'k'); //n68kマジック。n68kの代わりにn/16などと書くと1クラスタが16セクタになったりする 225: ByteArray.byaWl (bb, 0x00000418, hdmPartitionStartRecord); //(0=自動起動,1=使用不可,2=使用可能)<<24|ディスクの先頭からパーティションの先頭までのレコード数 226: ByteArray.byaWl (bb, 0x0000041c, hdmPartitionEndRecord - hdmPartitionStartRecord); //パーティションのレコード数 227: //SASIパーティションIPLを書き込む 228: System.arraycopy (HDC.HDC_PARTITION_IPL, 0, bb, 0x00002100, HDC.HDC_PARTITION_IPL.length); 229: //SASIパーティションIPLにBPBを埋め込む 230: ByteArray.byaWw (bb, (int) humPartitionStartByte + 0x12, humBytesPerSector); //1138 0000.w 1セクタあたりのバイト数(2の累乗) 231: ByteArray.byaWb (bb, (int) humPartitionStartByte + 0x14, humSectorsPerCluster); //113a 0002.b 1クラスタあたりのセクタ数(2の累乗) 232: ByteArray.byaWb (bb, (int) humPartitionStartByte + 0x15, humFatCount); //113b 0003.b FAT領域の個数 233: ByteArray.byaWw (bb, (int) humPartitionStartByte + 0x16, humReservedSectors); //113c 0004.w 予約領域のセクタ数(FAT領域の先頭セクタ番号) 234: ByteArray.byaWw (bb, (int) humPartitionStartByte + 0x18, humRootEntries); //113e 0006.w ルートディレクトリに入るエントリ数 235: ByteArray.byaWw (bb, (int) humPartitionStartByte + 0x1a, humPartitionSectors); //1140 0008.w パーティションのセクタ数 236: ByteArray.byaWb (bb, (int) humPartitionStartByte + 0x1c, humFatID); //1142 000a.b FATID 237: ByteArray.byaWb (bb, (int) humPartitionStartByte + 0x1d, humFatSectors); //1143 000b.b 1個のFAT領域に使用するセクタ数 238: ByteArray.byaWl (bb, (int) humPartitionStartByte + 0x1e, hdmPartitionStartRecord); //1144 000c.l ディスクの先頭からパーティションの先頭までのレコード数 239: //FAT領域の先頭にFATマーカーを書き込む 240: humWriteFatMarker (bb); 241: //システムファイルを転送する 242: if (copySystemFiles) { 243: if (!humCopyHumanSys (bb) || 244: !humCopyCommandX (bb)) { 245: return false; 246: } 247: } 248: if (false) { 249: humDumpFat (bb); 250: } 251: return true; 252: } //media.hdmMakeFormatData(byte[],boolean) 253: 254: } //class HDMedia 255: 256: 257: