|
|
1.1 root 1: //
2: // nono
3: // Copyright (C) 2020 nono project
4: // Licensed under nono-license.txt
5: //
6:
7: //
8: // メインメモリ
9: //
10:
1.1.1.5 root 11: // MainRAM はロングワード単位でホストバイトオーダ配置なので、
12: // バイトアクセス、ワードアクセス時は HLB(), HLW() マクロを使用のこと。
13:
1.1 root 14: #include "mainram.h"
15: #include "config.h"
16: #include "mainapp.h"
17: #include "mpu.h"
18: #include "prom.h"
19:
20: // コンストラクタ
21: MainRAMDevice::MainRAMDevice()
22: : inherited(OBJ_MAINRAM)
23: {
1.1.1.5 root 24: clear_on_boot = true;
1.1 root 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:
1.1.1.6 ! root 43: uint64 clock_tsec = mpu->GetClock_tsec();
1.1.1.2 root 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 の取説からの推論。
1.1.1.6 ! root 90: normal_wait = busdata::Wait(1 * clock_tsec);
! 91: burst_wait = busdata::Wait(4 * clock_tsec);
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.6 ! root 131: normal_wait = busdata::Wait(2 * clock_tsec);
! 132: burst_wait = busdata::Wait(5 * clock_tsec);
1.1 root 133: break;
134: }
135:
136: case VMType::NEWS:
1.1.1.5 root 137: // 電源オン時に RAM に書き込んでいるため、クリアしない。
138: clear_on_boot = false;
1.1.1.3 root 139: // 知らんけど 1クロックくらい入れておく。
1.1.1.6 ! root 140: normal_wait = busdata::Wait(1 * clock_tsec);
1.1.1.3 root 141: // NWS-1750 はバースト転送をサポートしていないようだ。
142: // http://www.ceres.dti.ne.jp/tsutsui/netbsd/port-news68k.html#19991203
1.1.1.2 root 143: break;
144:
145: case VMType::VIRT68K:
146: // 1MB 単位で指定できる必要もないだろうから 16MB 単位に切り上げる。
147: ram_size_MB = roundup(ram_size_MB, 16);
148:
149: // 最後の 16MB ブロックが I/O 空間なので、
150: // メモリは最大で 4096 - 16 = 4080MB まで積める。
151: if (ram_size_MB > 4080) {
152: item.Err("Configurable maximum RAM size is 4080 [MB]");
153: return false;
154: }
155:
156: // ウェイト不要。
1.1.1.3 root 157: normal_wait = busdata::Wait(0);
158: burst_wait = busdata::Wait(0);
1.1 root 159: break;
160:
161: default:
1.1.1.2 root 162: PANIC("vmtype=%s not configured", gMainApp.GetVMTypeStr().c_str());
1.1 root 163: }
164:
1.1.1.5 root 165: ram_size = (size_t)ram_size_MB * 1024 * 1024;
1.1.1.2 root 166: mainram.reset(new(std::nothrow) uint8[ram_size]);
167: if ((bool)mainram == false) {
1.1.1.6 ! root 168: warnx("Could not allocate MainRAM(%zu bytes)", ram_size);
1.1.1.2 root 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);
1.1.1.5 root 182: clear_on_boot = false;
1.1 root 183: }
184:
185: return true;
186: }
187:
188: // 電源オン/リセット
189: void
190: MainRAMDevice::ResetHard(bool poweron)
191: {
192: if (poweron) {
1.1.1.5 root 193: if (clear_on_boot) {
1.1 root 194: // XXX ノイズを用意するべき
195: memset(&mainram[0], 0, ram_size);
196: }
197: }
198:
199: // X68030 ではリセットで戻るはず。(LUNA は固定なので関係ない)
200: if (gMainApp.IsX68030()) {
1.1.1.3 root 201: normal_wait = busdata::Wait(0);
1.1 root 202: }
203: }
204:
1.1.1.2 root 205: busdata
1.1.1.3 root 206: MainRAMDevice::Read(busaddr addr)
1.1 root 207: {
1.1.1.3 root 208: uint32 paddr = addr.Addr();
1.1.1.2 root 209: busdata data;
1.1.1.3 root 210:
211: data = *(uint32 *)&mainram[paddr & ~3];
212: data |= normal_wait;
213: data |= BusData::Size4;
1.1 root 214: return data;
215: }
216:
1.1.1.2 root 217: busdata
1.1.1.3 root 218: MainRAMDevice::Write(busaddr addr, uint32 data)
1.1 root 219: {
1.1.1.3 root 220: uint32 paddr = addr.Addr();
221: uint32 reqsize = addr.GetSize();
222: uint32 datasize = std::min(4 - (paddr & 3U), reqsize);
223:
224: if (datasize == 4) {
225: *(uint32 *)&mainram[paddr] = data;
226: } else if (datasize == 1) {
227: data >>= (reqsize - datasize) * 8;
228: mainram[HLB(paddr)] = data;
229: } else {
230: data >>= (reqsize - datasize) * 8;
231: for (int i = datasize - 1; i >= 0; i--) {
232: mainram[HLB(paddr + i)] = data;
233: data >>= 8;
234: }
235: }
236:
237: busdata r = normal_wait;
238: r |= BusData::Size4;
239: return r;
1.1 root 240: }
241:
1.1.1.2 root 242: busdata
1.1.1.3 root 243: MainRAMDevice::ReadBurst16(busaddr addr, uint32 *dst)
1.1 root 244: {
1.1.1.3 root 245: uint32 paddr = addr.Addr();
246: putlog(4, "$%08x BurstRead", paddr);
247: memcpy(dst, &mainram[paddr], 16);
248: return burst_wait;
1.1 root 249: }
250:
1.1.1.2 root 251: busdata
1.1.1.3 root 252: MainRAMDevice::WriteBurst16(busaddr addr, const uint32 *src)
1.1 root 253: {
1.1.1.3 root 254: uint32 paddr = addr.Addr();
255: putlog(4, "$%08x BurstWrite", paddr);
256: memcpy(&mainram[paddr], src, 16);
257: return burst_wait;
1.1 root 258: }
259:
1.1.1.2 root 260: busdata
1.1.1.3 root 261: MainRAMDevice::Peek1(uint32 addr)
1.1 root 262: {
1.1.1.3 root 263: return mainram[HLB(addr)];
1.1 root 264: }
265:
1.1.1.3 root 266: bool
267: MainRAMDevice::Poke1(uint32 addr, uint32 data)
1.1 root 268: {
1.1.1.3 root 269: if ((int32)data >= 0) {
270: mainram[HLB(addr)] = data;
271: }
272: return true;
1.1 root 273: }
274:
1.1.1.3 root 275: // 領域読み出し。
276: // addr から totallen までが領域内なら転送して true を返す。
277: // 領域外を指すなら何もせず false を返す。
278: bool
279: MainRAMDevice::ReadMem(uint32 addr, void *dst_, uint32 totallen)
1.1 root 280: {
1.1.1.3 root 281: uint8 *dst = (uint8 *)dst_;
282: uintptr_t u = (uintptr_t)addr;
283: uint32 len;
284:
285: if (__predict_false(addr + totallen > GetSize())) {
286: return false;
287: }
288:
289: if (__predict_false(((u | (uintptr_t)dst) & 3) != 0)) {
290: if (((u ^ (uintptr_t)dst) & 3) || totallen < 4) {
291: len = totallen;
292: } else {
293: len = 4 - (uint32)(u & 3);
294: }
295: totallen -= len;
296: for (; len > 0; len--) {
297: *dst++ = mainram[HLB(addr)];
298: addr++;
299: }
300: }
301:
302: len = totallen / 4;
303: for (; len > 0; len--) {
304: *(uint32 *)dst = be32toh(*(uint32 *)&mainram[addr]);
305: dst += 4;
306: addr += 4;
307: }
308:
309: len = totallen & 3;
310: for (; len > 0; len--) {
311: *dst++ = mainram[HLB(addr)];
312: addr++;
313: }
314:
315: return true;
1.1 root 316: }
317:
1.1.1.3 root 318: // 領域書き込み。
319: // addr から totallen までが領域内なら転送して true を返す。
320: // 領域外を指すなら何もせず false を返す。
1.1.1.2 root 321: bool
1.1.1.3 root 322: MainRAMDevice::WriteMem(uint32 addr, const void *src_, uint32 totallen)
1.1 root 323: {
1.1.1.3 root 324: const uint8 *src = (const uint8 *)src_;
325: uintptr_t u = (uintptr_t)addr;
326: uint32 len;
327:
328: if (__predict_false(addr + totallen > GetSize())) {
329: return false;
330: }
331:
332: if (__predict_false(((u | (uintptr_t)src) & 3) != 0)) {
333: if (((u ^ (uintptr_t)src) & 3) || totallen < 4) {
334: len = totallen;
335: } else {
336: len = 4 - (uint32)(u & 3);
337: }
338: totallen -= len;
339: for (; len > 0; len--) {
340: mainram[HLB(addr)] = *src++;
341: addr++;
342: }
1.1 root 343: }
1.1.1.3 root 344:
345: len = totallen / 4;
346: for (; len > 0; len--) {
347: *(uint32 *)&mainram[addr] = be32toh(*(const uint32 *)src);
348: addr += 4;
349: src += 4;
350: }
351:
352: len = totallen & 3;
353: for (; len > 0; len--) {
354: mainram[HLB(addr)] = *src++;
355: addr++;
356: }
357:
1.1.1.2 root 358: return true;
1.1 root 359: }
360:
1.1.1.3 root 361: // アクセスウェイト [clock] を設定。
362: // X68030 でシステムポートから呼ばれるため normal_wait のみ設定する。
1.1 root 363: void
1.1.1.3 root 364: MainRAMDevice::SetWait(uint32 wait_clock)
1.1 root 365: {
1.1.1.6 ! root 366: normal_wait = busdata::Wait(wait_clock * mpu->GetClock_tsec());
1.1 root 367: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.