|
|
1.1 ! root 1: // ! 2: // nono ! 3: // Copyright (C) 2020 nono project ! 4: // Licensed under nono-license.txt ! 5: // ! 6: ! 7: // ! 8: // メインメモリ ! 9: // ! 10: ! 11: #include "mainram.h" ! 12: #include "config.h" ! 13: #include "mainapp.h" ! 14: #include "mpu.h" ! 15: #include "prom.h" ! 16: ! 17: // MainRAM はロングワード単位でホストバイトオーダ配置なので、 ! 18: // バイトアクセス、ワードアクセス時は HLB(), HLW() マクロを使用のこと。 ! 19: /*static*/ std::unique_ptr<uint8[]> MainRAMDevice::mainram; ! 20: ! 21: // コンストラクタ ! 22: MainRAMDevice::MainRAMDevice() ! 23: : inherited(OBJ_MAINRAM) ! 24: { ! 25: // アクセスウェイト ! 26: switch (gMainApp.GetVMType()) { ! 27: case VMType::LUNA1: ! 28: // LUNA-I は1ウェイト。 ! 29: read_wait = 1; ! 30: write_wait = 1; ! 31: break; ! 32: ! 33: case VMType::LUNA88K: ! 34: // 取扱説明書p.21 に、CMMU からのアクセスタイムが ! 35: // リード(4byte)で 200ns、バーストリード(16byte)で 320ns ! 36: // ライト(4byte)で 160ns、バーストライト(16byte)で 280ns とある。 ! 37: // 25MHz は 40ns/clockで、この数値は CMMU からのアクセス全体の時間 ! 38: // らしいので、ここで加算するウェイトはそれから 2クロック引いたもの。 ! 39: read_wait = 3; ! 40: write_wait = 2; ! 41: break; ! 42: ! 43: case VMType::X68030: ! 44: default: ! 45: // X68030 ではシステムポートが設定するのでここでは不要。 ! 46: break; ! 47: } ! 48: } ! 49: ! 50: // デストラクタ ! 51: MainRAMDevice::~MainRAMDevice() ! 52: { ! 53: } ! 54: ! 55: // 初期化 ! 56: bool ! 57: MainRAMDevice::Init() ! 58: { ! 59: if (inherited::Init() == false) { ! 60: return false; ! 61: } ! 62: ! 63: const ConfigItem& item = gConfig->Find("ram-size"); ! 64: int ram_size_MB = item.AsInt(); ! 65: if (ram_size_MB < 1) { ! 66: item.Err(); ! 67: return false; ! 68: } ! 69: // 下限以外の制約は機種による ! 70: switch (gMainApp.GetVMType()) { ! 71: case VMType::X68030: ! 72: // メインメモリは 12MB まで。 ! 73: // 内部は 8KB 単位で処理できるが設定が 1MB 単位。 ! 74: if (ram_size_MB > 12) { ! 75: item.Err("Configurable maximum main memory size is 12 [MB]"); ! 76: return false; ! 77: } ! 78: break; ! 79: ! 80: case VMType::LUNA1: ! 81: // 16MB までは、実機に合わせて 4MB 単位とする。 ! 82: // see http://wiki.netbsd.org/ports/luna68k/luna68k_info/#hardware ! 83: // ! 84: // 16MB を超える増設 (or 魔改造) 部分は 1MB 単位で 255MB までとする。 ! 85: // 実 ROM のメモリチェックは 32KB だかそのくらいずつ行われ、 ! 86: // 最後に番兵として Null 領域 (BusError ではなく) が必要。 ! 87: // 現行の構成をあまり変えない範囲なら厳密には (256MB - 32KB) が ! 88: // 上限だが、設定ファイルからの指定が 1MB 単位なので 255MB。 ! 89: if (ram_size_MB <= 16) { ! 90: if (ram_size_MB % 4 != 0) { ! 91: item.Err("For 16MB or less, must be specified in 4 [MB] unit"); ! 92: return false; ! 93: } ! 94: } else if (ram_size_MB > 255) { ! 95: item.Err("Configurable maximum RAM size is 255 [MB]"); ! 96: return false; ! 97: } ! 98: break; ! 99: ! 100: case VMType::LUNA88K: ! 101: { ! 102: // 64MB までは、実機に合わせて 16MB 単位とする。 ! 103: // ! 104: // 64MB を超える増設 (or 魔改造) 部分は未確認。 ! 105: if (ram_size_MB <= 64) { ! 106: if (ram_size_MB % 16 != 0) { ! 107: item.Err("For 64MB or less, must be specified in 16 [MB] unit"); ! 108: return false; ! 109: } ! 110: } else if (ram_size_MB > 255) { ! 111: item.Err("Configurable maximum RAM size is 255 [MB]"); ! 112: return false; ! 113: } ! 114: ! 115: // PROM 1.20 では 240MB を上限にする。 ! 116: // 0x0f00'0000 (ちょうど 240MB 目) へのアクセスでバスエラーが ! 117: // 出ることを CMMU のアドレス変換チェックに使っているため。 ! 118: auto prom = dynamic_cast<PROMDevice *>(GetPROMDevice()); ! 119: if (prom && prom->GetROMVer() == 120) { ! 120: if (ram_size_MB > 240) { ! 121: item.Err("Maximum RAM size with PROM 1.20 is 240 [MB]"); ! 122: return false; ! 123: } ! 124: } ! 125: ! 126: break; ! 127: } ! 128: ! 129: case VMType::NEWS: ! 130: // XXX とりあえず ! 131: memset(&mainram[0], 0, ram_size); ! 132: break; ! 133: ! 134: default: ! 135: PANIC("corrupted vmtype=%s", gMainApp.GetVMName().c_str()); ! 136: } ! 137: ! 138: ram_size = ram_size_MB * 1024 * 1024; ! 139: mainram.reset(new uint8[ram_size]); ! 140: ! 141: // Human68k モードならここで一度だけメモリをゼロクリアする。 ! 142: // この時は Human68k::Init() が MainRAM にプログラムを転送するため ! 143: // 電源オン時点で RAM を初期化してはいけない…。うーんこの…。 ! 144: // MainRAM::Init() が Human68k::Init() より先に呼ばれることは ! 145: // VM_X68030 で指定してある。 ! 146: // 一方、通常モードなら VM リスタート(電源再投入) で前の内容を残さない ! 147: // ために ResetHard(true) でメモリを (ゼロでなくてもいいので) クリアする ! 148: // 必要がある。 ! 149: if (gMainApp.human_mode) { ! 150: memset(&mainram[0], 0, ram_size); ! 151: } ! 152: ! 153: // devtable[] への RAM デバイスの配置はこの後 VM::Init 側で行っている ! 154: ! 155: return true; ! 156: } ! 157: ! 158: // 電源オン/リセット ! 159: void ! 160: MainRAMDevice::ResetHard(bool poweron) ! 161: { ! 162: if (poweron) { ! 163: if (gMainApp.human_mode || gMainApp.IsNEWS()) { ! 164: // Human モードと NEWS は Init() がメモリに書き込むので ! 165: // ここでクリアしない。うーん。 ! 166: } else { ! 167: // 通常モードならメモリをクリア ! 168: // XXX ノイズを用意するべき ! 169: memset(&mainram[0], 0, ram_size); ! 170: } ! 171: } ! 172: ! 173: // X68030 ではリセットで戻るはず。(LUNA は固定なので関係ない) ! 174: if (gMainApp.IsX68030()) { ! 175: read_wait = 0; ! 176: write_wait = 0; ! 177: } ! 178: } ! 179: ! 180: uint64 ! 181: MainRAMDevice::Read8(uint32 addr) ! 182: { ! 183: mpu->AddCycle(read_wait); ! 184: uint32 data; ! 185: data = mainram[HLB(addr)]; ! 186: putlog(4, "$%08x.B -> $%02x", addr, data); ! 187: return data; ! 188: } ! 189: ! 190: uint64 ! 191: MainRAMDevice::Read16(uint32 addr) ! 192: { ! 193: mpu->AddCycle(read_wait); ! 194: uint32 data; ! 195: data = *(uint16 *)&mainram[HLW(addr)]; ! 196: putlog(4, "$%08x.W -> $%04x", addr, data); ! 197: return data; ! 198: } ! 199: ! 200: uint64 ! 201: MainRAMDevice::Read32(uint32 addr) ! 202: { ! 203: mpu->AddCycle(read_wait); ! 204: uint32 data; ! 205: data = *(uint32 *)&mainram[addr]; ! 206: putlog(4, "$%08x.L -> $%08x", addr, data); ! 207: return data; ! 208: } ! 209: ! 210: uint64 ! 211: MainRAMDevice::Write8(uint32 addr, uint32 data) ! 212: { ! 213: mpu->AddCycle(write_wait); ! 214: mainram[HLB(addr)] = data; ! 215: putlog(3, "$%08x.B <- $%02x", addr, data); ! 216: return 0; ! 217: } ! 218: ! 219: uint64 ! 220: MainRAMDevice::Write16(uint32 addr, uint32 data) ! 221: { ! 222: mpu->AddCycle(write_wait); ! 223: *(uint16 *)&mainram[HLW(addr)] = data; ! 224: putlog(3, "$%08x.W <- $%04x", addr, data); ! 225: return 0; ! 226: } ! 227: ! 228: uint64 ! 229: MainRAMDevice::Write32(uint32 addr, uint32 data) ! 230: { ! 231: mpu->AddCycle(write_wait); ! 232: *(uint32 *)&mainram[addr] = data; ! 233: putlog(3, "$%08x.L <- $%08x", addr, data); ! 234: return 0; ! 235: } ! 236: ! 237: uint64 ! 238: MainRAMDevice::Peek8(uint32 addr) ! 239: { ! 240: return mainram[HLB(addr)]; ! 241: } ! 242: ! 243: uint64 ! 244: MainRAMDevice::Poke8(uint32 addr, uint32 data) ! 245: { ! 246: if ((int32)data >= 0) { ! 247: mainram[HLB(addr)] = data; ! 248: } ! 249: return 0; ! 250: } ! 251: ! 252: // アクセスウェイトを設定 (X68030 でシステムポートから呼ばれる) ! 253: void ! 254: MainRAMDevice::SetWait(uint32 wait) ! 255: { ! 256: read_wait = wait; ! 257: write_wait = wait; ! 258: } ! 259: ! 260: // info->path で指定されたホストの実行ファイルをゲストにロードする。 ! 261: bool ! 262: MainRAMDevice::LoadFromFile(LoadInfo *info) ! 263: { ! 264: BootLoader loader(this); ! 265: ! 266: return loader.LoadFromFile(info); ! 267: } ! 268: ! 269: // info->data, size で指定されたバッファを実行ファイルとみなしてゲストに ! 270: // ロードする。 ! 271: bool ! 272: MainRAMDevice::LoadFromData(LoadInfo *info) ! 273: { ! 274: BootLoader loader(this); ! 275: ! 276: return loader.LoadFromData(info); ! 277: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.