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