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