|
|
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.1.3 ! root 60: // バースト用の線は回路図によると配線されていないようだ。
1.1 root 61: break;
62:
63: case VMType::LUNA1:
1.1.1.2 root 64: {
1.1 root 65: // 16MB までは、実機に合わせて 4MB 単位とする。
66: // see http://wiki.netbsd.org/ports/luna68k/luna68k_info/#hardware
67: //
1.1.1.2 root 68: // 16MB を超える増設 (or 魔改造) 部分は 1MB 単位とする。
1.1 root 69: if (ram_size_MB <= 16) {
70: if (ram_size_MB % 4 != 0) {
71: item.Err("For 16MB or less, must be specified in 4 [MB] unit");
72: return false;
73: }
1.1.1.2 root 74: } else if (ram_size_MB > 512) {
75: item.Err("Configurable maximum RAM size is 512 [MB]");
1.1 root 76: return false;
77: }
1.1.1.2 root 78:
79: // 実 ROM のメモリチェックは 32KB だかそのくらいずつ行われ、
80: // 最後に番兵として NOP 領域 (BusError ではなく) が必要。
81: // 現行の構成をあまり変えない範囲なら厳密には (256MB - 32KB) が
82: // 上限だが、サイズ指定が 1MB 単位なので 255MB を上限にする。
83: auto prom = dynamic_cast<PROMDevice *>(GetPROMDevice());
84: if (prom) {
85: if (ram_size_MB > 255) {
86: item.Err("(Warning) Maximum RAM size with PROM is 255[MB]; "
87: "Clip RAM size to 255[MB].");
88: ram_size_MB = 255;
89: }
90: }
91:
1.1.1.3 ! root 92: // 通常サイクルは1ウェイトらしい?
! 93: // バーストウェイトは LUNA-88K の取説からの推論。
! 94: normal_wait = busdata::Wait(1 * clock_nsec);
! 95: burst_wait = busdata::Wait(4 * clock_nsec);
1.1 root 96: break;
1.1.1.2 root 97: }
1.1 root 98:
99: case VMType::LUNA88K:
100: {
101: // 64MB までは、実機に合わせて 16MB 単位とする。
102: //
103: // 64MB を超える増設 (or 魔改造) 部分は未確認。
104: if (ram_size_MB <= 64) {
105: if (ram_size_MB % 16 != 0) {
106: item.Err("For 64MB or less, must be specified in 16 [MB] unit");
107: return false;
108: }
1.1.1.2 root 109: } else if (ram_size_MB > 512) {
110: item.Err("Configurable maximum RAM size is 512 [MB]");
1.1 root 111: return false;
112: }
113:
114: // PROM 1.20 では 240MB を上限にする。
115: // 0x0f00'0000 (ちょうど 240MB 目) へのアクセスでバスエラーが
116: // 出ることを CMMU のアドレス変換チェックに使っているため。
117: auto prom = dynamic_cast<PROMDevice *>(GetPROMDevice());
118: if (prom && prom->GetROMVer() == 120) {
119: if (ram_size_MB > 240) {
1.1.1.2 root 120: item.Err("(warning) Maximum RAM size with PROM 1.20 is 240[MB];"
121: " Clip RAM size to 240[MB].");
122: ram_size_MB = 240;
1.1 root 123: }
124: }
125:
1.1.1.2 root 126: // 取扱説明書p.21 に、CMMU からのアクセスタイムが
127: // リード(4byte)で 200ns、バーストリード(16byte)で 320ns
128: // ライト(4byte)で 160ns、バーストライト(16byte)で 280ns とある。
129: // 25MHz は 40ns/clock なのでそれぞれ、
130: // リード(4byte)で 5 clock、バーストリード(16byte)で 8 clock
131: // ライト(4byte)で 4 clock、バーストライト(16byte)で 7 clock となる。
132: // これは CMMU 以降のアクセスタイムらしいので、
133: // リード3クロック、ライト2クロック引いたものをウェイトとしてみる?
134: // XXX 要確認。
1.1.1.3 ! root 135: normal_wait = busdata::Wait(2 * clock_nsec);
! 136: burst_wait = busdata::Wait(5 * clock_nsec);
1.1 root 137: break;
138: }
139:
140: case VMType::NEWS:
1.1.1.3 ! root 141: // 知らんけど 1クロックくらい入れておく。
! 142: normal_wait = busdata::Wait(1 * clock_nsec);
! 143: // NWS-1750 はバースト転送をサポートしていないようだ。
! 144: // http://www.ceres.dti.ne.jp/tsutsui/netbsd/port-news68k.html#19991203
1.1.1.2 root 145: break;
146:
147: case VMType::VIRT68K:
148: // 1MB 単位で指定できる必要もないだろうから 16MB 単位に切り上げる。
149: ram_size_MB = roundup(ram_size_MB, 16);
150:
151: // 最後の 16MB ブロックが I/O 空間なので、
152: // メモリは最大で 4096 - 16 = 4080MB まで積める。
153: if (ram_size_MB > 4080) {
154: item.Err("Configurable maximum RAM size is 4080 [MB]");
155: return false;
156: }
157:
158: // ウェイト不要。
1.1.1.3 ! root 159: normal_wait = busdata::Wait(0);
! 160: burst_wait = busdata::Wait(0);
1.1 root 161: break;
162:
163: default:
1.1.1.2 root 164: PANIC("vmtype=%s not configured", gMainApp.GetVMTypeStr().c_str());
1.1 root 165: }
166:
167: ram_size = ram_size_MB * 1024 * 1024;
1.1.1.2 root 168: mainram.reset(new(std::nothrow) uint8[ram_size]);
169: if ((bool)mainram == false) {
170: errno = ENOMEM;
171: warn("MainRAM(%u bytes)", ram_size);
172: return false;
173: }
1.1 root 174:
175: // Human68k モードならここで一度だけメモリをゼロクリアする。
176: // この時は Human68k::Init() が MainRAM にプログラムを転送するため
177: // 電源オン時点で RAM を初期化してはいけない…。うーんこの…。
178: // MainRAM::Init() が Human68k::Init() より先に呼ばれることは
179: // VM_X68030 で指定してある。
180: // 一方、通常モードなら VM リスタート(電源再投入) で前の内容を残さない
181: // ために ResetHard(true) でメモリを (ゼロでなくてもいいので) クリアする
182: // 必要がある。
183: if (gMainApp.human_mode) {
184: memset(&mainram[0], 0, ram_size);
185: }
186:
187: return true;
188: }
189:
190: // 電源オン/リセット
191: void
192: MainRAMDevice::ResetHard(bool poweron)
193: {
194: if (poweron) {
195: if (gMainApp.human_mode || gMainApp.IsNEWS()) {
196: // Human モードと NEWS は Init() がメモリに書き込むので
197: // ここでクリアしない。うーん。
198: } else {
199: // 通常モードならメモリをクリア
200: // XXX ノイズを用意するべき
201: memset(&mainram[0], 0, ram_size);
202: }
203: }
204:
205: // X68030 ではリセットで戻るはず。(LUNA は固定なので関係ない)
206: if (gMainApp.IsX68030()) {
1.1.1.3 ! root 207: normal_wait = busdata::Wait(0);
1.1 root 208: }
209: }
210:
1.1.1.2 root 211: busdata
1.1.1.3 ! root 212: MainRAMDevice::Read(busaddr addr)
1.1 root 213: {
1.1.1.3 ! root 214: uint32 paddr = addr.Addr();
1.1.1.2 root 215: busdata data;
1.1.1.3 ! root 216:
! 217: data = *(uint32 *)&mainram[paddr & ~3];
! 218: data |= normal_wait;
! 219: data |= BusData::Size4;
1.1 root 220: return data;
221: }
222:
1.1.1.2 root 223: busdata
1.1.1.3 ! root 224: MainRAMDevice::Write(busaddr addr, uint32 data)
1.1 root 225: {
1.1.1.3 ! root 226: uint32 paddr = addr.Addr();
! 227: uint32 reqsize = addr.GetSize();
! 228: uint32 datasize = std::min(4 - (paddr & 3U), reqsize);
! 229:
! 230: if (datasize == 4) {
! 231: *(uint32 *)&mainram[paddr] = data;
! 232: } else if (datasize == 1) {
! 233: data >>= (reqsize - datasize) * 8;
! 234: mainram[HLB(paddr)] = data;
! 235: } else {
! 236: data >>= (reqsize - datasize) * 8;
! 237: for (int i = datasize - 1; i >= 0; i--) {
! 238: mainram[HLB(paddr + i)] = data;
! 239: data >>= 8;
! 240: }
! 241: }
! 242:
! 243: busdata r = normal_wait;
! 244: r |= BusData::Size4;
! 245: return r;
1.1 root 246: }
247:
1.1.1.2 root 248: busdata
1.1.1.3 ! root 249: MainRAMDevice::ReadBurst16(busaddr addr, uint32 *dst)
1.1 root 250: {
1.1.1.3 ! root 251: uint32 paddr = addr.Addr();
! 252: putlog(4, "$%08x BurstRead", paddr);
! 253: memcpy(dst, &mainram[paddr], 16);
! 254: return burst_wait;
1.1 root 255: }
256:
1.1.1.2 root 257: busdata
1.1.1.3 ! root 258: MainRAMDevice::WriteBurst16(busaddr addr, const uint32 *src)
1.1 root 259: {
1.1.1.3 ! root 260: uint32 paddr = addr.Addr();
! 261: putlog(4, "$%08x BurstWrite", paddr);
! 262: memcpy(&mainram[paddr], src, 16);
! 263: return burst_wait;
1.1 root 264: }
265:
1.1.1.2 root 266: busdata
1.1.1.3 ! root 267: MainRAMDevice::Peek1(uint32 addr)
1.1 root 268: {
1.1.1.3 ! root 269: return mainram[HLB(addr)];
1.1 root 270: }
271:
1.1.1.3 ! root 272: bool
! 273: MainRAMDevice::Poke1(uint32 addr, uint32 data)
1.1 root 274: {
1.1.1.3 ! root 275: if ((int32)data >= 0) {
! 276: mainram[HLB(addr)] = data;
! 277: }
! 278: return true;
1.1 root 279: }
280:
1.1.1.3 ! root 281: // 領域読み出し。
! 282: // addr から totallen までが領域内なら転送して true を返す。
! 283: // 領域外を指すなら何もせず false を返す。
! 284: bool
! 285: MainRAMDevice::ReadMem(uint32 addr, void *dst_, uint32 totallen)
1.1 root 286: {
1.1.1.3 ! root 287: uint8 *dst = (uint8 *)dst_;
! 288: uintptr_t u = (uintptr_t)addr;
! 289: uint32 len;
! 290:
! 291: if (__predict_false(addr + totallen > GetSize())) {
! 292: return false;
! 293: }
! 294:
! 295: if (__predict_false(((u | (uintptr_t)dst) & 3) != 0)) {
! 296: if (((u ^ (uintptr_t)dst) & 3) || totallen < 4) {
! 297: len = totallen;
! 298: } else {
! 299: len = 4 - (uint32)(u & 3);
! 300: }
! 301: totallen -= len;
! 302: for (; len > 0; len--) {
! 303: *dst++ = mainram[HLB(addr)];
! 304: addr++;
! 305: }
! 306: }
! 307:
! 308: len = totallen / 4;
! 309: for (; len > 0; len--) {
! 310: *(uint32 *)dst = be32toh(*(uint32 *)&mainram[addr]);
! 311: dst += 4;
! 312: addr += 4;
! 313: }
! 314:
! 315: len = totallen & 3;
! 316: for (; len > 0; len--) {
! 317: *dst++ = mainram[HLB(addr)];
! 318: addr++;
! 319: }
! 320:
! 321: return true;
1.1 root 322: }
323:
1.1.1.3 ! root 324: // 領域書き込み。
! 325: // addr から totallen までが領域内なら転送して true を返す。
! 326: // 領域外を指すなら何もせず false を返す。
1.1.1.2 root 327: bool
1.1.1.3 ! root 328: MainRAMDevice::WriteMem(uint32 addr, const void *src_, uint32 totallen)
1.1 root 329: {
1.1.1.3 ! root 330: const uint8 *src = (const uint8 *)src_;
! 331: uintptr_t u = (uintptr_t)addr;
! 332: uint32 len;
! 333:
! 334: if (__predict_false(addr + totallen > GetSize())) {
! 335: return false;
! 336: }
! 337:
! 338: if (__predict_false(((u | (uintptr_t)src) & 3) != 0)) {
! 339: if (((u ^ (uintptr_t)src) & 3) || totallen < 4) {
! 340: len = totallen;
! 341: } else {
! 342: len = 4 - (uint32)(u & 3);
! 343: }
! 344: totallen -= len;
! 345: for (; len > 0; len--) {
! 346: mainram[HLB(addr)] = *src++;
! 347: addr++;
! 348: }
1.1 root 349: }
1.1.1.3 ! root 350:
! 351: len = totallen / 4;
! 352: for (; len > 0; len--) {
! 353: *(uint32 *)&mainram[addr] = be32toh(*(const uint32 *)src);
! 354: addr += 4;
! 355: src += 4;
! 356: }
! 357:
! 358: len = totallen & 3;
! 359: for (; len > 0; len--) {
! 360: mainram[HLB(addr)] = *src++;
! 361: addr++;
! 362: }
! 363:
1.1.1.2 root 364: return true;
1.1 root 365: }
366:
1.1.1.3 ! root 367: // アクセスウェイト [clock] を設定。
! 368: // X68030 でシステムポートから呼ばれるため normal_wait のみ設定する。
1.1 root 369: void
1.1.1.3 ! root 370: MainRAMDevice::SetWait(uint32 wait_clock)
1.1 root 371: {
1.1.1.2 root 372: uint32 clock_nsec = mpu->GetClock_nsec();
373:
1.1.1.3 ! root 374: normal_wait = busdata::Wait(wait_clock * clock_nsec);
1.1 root 375: }
376:
1.1.1.2 root 377: // info で指定された実行ファイルをゲストにロードする。
1.1 root 378: bool
1.1.1.2 root 379: MainRAMDevice::LoadExec(LoadInfo *info)
1.1 root 380: {
381: BootLoader loader(this);
382:
1.1.1.2 root 383: return loader.LoadExec(info);
1.1 root 384: }
385:
1.1.1.2 root 386: // info で指定されたデータファイルをゲストにロードする。
1.1 root 387: bool
1.1.1.2 root 388: MainRAMDevice::LoadData(LoadInfo *info)
1.1 root 389: {
390: BootLoader loader(this);
391:
1.1.1.2 root 392: return loader.LoadData(info);
1.1 root 393: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.