|
|
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:
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.5 ! root 137: // 電源オン時に RAM に書き込んでいるため、クリアしない。
! 138: clear_on_boot = false;
1.1.1.3 root 139: // 知らんけど 1クロックくらい入れておく。
140: normal_wait = busdata::Wait(1 * clock_nsec);
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) {
168: errno = ENOMEM;
1.1.1.5 ! root 169: warn("MainRAM(%zu bytes)", ram_size);
1.1.1.2 root 170: return false;
171: }
1.1 root 172:
173: // Human68k モードならここで一度だけメモリをゼロクリアする。
174: // この時は Human68k::Init() が MainRAM にプログラムを転送するため
175: // 電源オン時点で RAM を初期化してはいけない…。うーんこの…。
176: // MainRAM::Init() が Human68k::Init() より先に呼ばれることは
177: // VM_X68030 で指定してある。
178: // 一方、通常モードなら VM リスタート(電源再投入) で前の内容を残さない
179: // ために ResetHard(true) でメモリを (ゼロでなくてもいいので) クリアする
180: // 必要がある。
181: if (gMainApp.human_mode) {
182: memset(&mainram[0], 0, ram_size);
1.1.1.5 ! root 183: clear_on_boot = false;
1.1 root 184: }
185:
186: return true;
187: }
188:
189: // 電源オン/リセット
190: void
191: MainRAMDevice::ResetHard(bool poweron)
192: {
193: if (poweron) {
1.1.1.5 ! root 194: if (clear_on_boot) {
1.1 root 195: // XXX ノイズを用意するべき
196: memset(&mainram[0], 0, ram_size);
197: }
198: }
199:
200: // X68030 ではリセットで戻るはず。(LUNA は固定なので関係ない)
201: if (gMainApp.IsX68030()) {
1.1.1.3 root 202: normal_wait = busdata::Wait(0);
1.1 root 203: }
204: }
205:
1.1.1.2 root 206: busdata
1.1.1.3 root 207: MainRAMDevice::Read(busaddr addr)
1.1 root 208: {
1.1.1.3 root 209: uint32 paddr = addr.Addr();
1.1.1.2 root 210: busdata data;
1.1.1.3 root 211:
212: data = *(uint32 *)&mainram[paddr & ~3];
213: data |= normal_wait;
214: data |= BusData::Size4;
1.1 root 215: return data;
216: }
217:
1.1.1.2 root 218: busdata
1.1.1.3 root 219: MainRAMDevice::Write(busaddr addr, uint32 data)
1.1 root 220: {
1.1.1.3 root 221: uint32 paddr = addr.Addr();
222: uint32 reqsize = addr.GetSize();
223: uint32 datasize = std::min(4 - (paddr & 3U), reqsize);
224:
225: if (datasize == 4) {
226: *(uint32 *)&mainram[paddr] = data;
227: } else if (datasize == 1) {
228: data >>= (reqsize - datasize) * 8;
229: mainram[HLB(paddr)] = data;
230: } else {
231: data >>= (reqsize - datasize) * 8;
232: for (int i = datasize - 1; i >= 0; i--) {
233: mainram[HLB(paddr + i)] = data;
234: data >>= 8;
235: }
236: }
237:
238: busdata r = normal_wait;
239: r |= BusData::Size4;
240: return r;
1.1 root 241: }
242:
1.1.1.2 root 243: busdata
1.1.1.3 root 244: MainRAMDevice::ReadBurst16(busaddr addr, uint32 *dst)
1.1 root 245: {
1.1.1.3 root 246: uint32 paddr = addr.Addr();
247: putlog(4, "$%08x BurstRead", paddr);
248: memcpy(dst, &mainram[paddr], 16);
249: return burst_wait;
1.1 root 250: }
251:
1.1.1.2 root 252: busdata
1.1.1.3 root 253: MainRAMDevice::WriteBurst16(busaddr addr, const uint32 *src)
1.1 root 254: {
1.1.1.3 root 255: uint32 paddr = addr.Addr();
256: putlog(4, "$%08x BurstWrite", paddr);
257: memcpy(&mainram[paddr], src, 16);
258: return burst_wait;
1.1 root 259: }
260:
1.1.1.2 root 261: busdata
1.1.1.3 root 262: MainRAMDevice::Peek1(uint32 addr)
1.1 root 263: {
1.1.1.3 root 264: return mainram[HLB(addr)];
1.1 root 265: }
266:
1.1.1.3 root 267: bool
268: MainRAMDevice::Poke1(uint32 addr, uint32 data)
1.1 root 269: {
1.1.1.3 root 270: if ((int32)data >= 0) {
271: mainram[HLB(addr)] = data;
272: }
273: return true;
1.1 root 274: }
275:
1.1.1.3 root 276: // 領域読み出し。
277: // addr から totallen までが領域内なら転送して true を返す。
278: // 領域外を指すなら何もせず false を返す。
279: bool
280: MainRAMDevice::ReadMem(uint32 addr, void *dst_, uint32 totallen)
1.1 root 281: {
1.1.1.3 root 282: uint8 *dst = (uint8 *)dst_;
283: uintptr_t u = (uintptr_t)addr;
284: uint32 len;
285:
286: if (__predict_false(addr + totallen > GetSize())) {
287: return false;
288: }
289:
290: if (__predict_false(((u | (uintptr_t)dst) & 3) != 0)) {
291: if (((u ^ (uintptr_t)dst) & 3) || totallen < 4) {
292: len = totallen;
293: } else {
294: len = 4 - (uint32)(u & 3);
295: }
296: totallen -= len;
297: for (; len > 0; len--) {
298: *dst++ = mainram[HLB(addr)];
299: addr++;
300: }
301: }
302:
303: len = totallen / 4;
304: for (; len > 0; len--) {
305: *(uint32 *)dst = be32toh(*(uint32 *)&mainram[addr]);
306: dst += 4;
307: addr += 4;
308: }
309:
310: len = totallen & 3;
311: for (; len > 0; len--) {
312: *dst++ = mainram[HLB(addr)];
313: addr++;
314: }
315:
316: return true;
1.1 root 317: }
318:
1.1.1.3 root 319: // 領域書き込み。
320: // addr から totallen までが領域内なら転送して true を返す。
321: // 領域外を指すなら何もせず false を返す。
1.1.1.2 root 322: bool
1.1.1.3 root 323: MainRAMDevice::WriteMem(uint32 addr, const void *src_, uint32 totallen)
1.1 root 324: {
1.1.1.3 root 325: const uint8 *src = (const uint8 *)src_;
326: uintptr_t u = (uintptr_t)addr;
327: uint32 len;
328:
329: if (__predict_false(addr + totallen > GetSize())) {
330: return false;
331: }
332:
333: if (__predict_false(((u | (uintptr_t)src) & 3) != 0)) {
334: if (((u ^ (uintptr_t)src) & 3) || totallen < 4) {
335: len = totallen;
336: } else {
337: len = 4 - (uint32)(u & 3);
338: }
339: totallen -= len;
340: for (; len > 0; len--) {
341: mainram[HLB(addr)] = *src++;
342: addr++;
343: }
1.1 root 344: }
1.1.1.3 root 345:
346: len = totallen / 4;
347: for (; len > 0; len--) {
348: *(uint32 *)&mainram[addr] = be32toh(*(const uint32 *)src);
349: addr += 4;
350: src += 4;
351: }
352:
353: len = totallen & 3;
354: for (; len > 0; len--) {
355: mainram[HLB(addr)] = *src++;
356: addr++;
357: }
358:
1.1.1.2 root 359: return true;
1.1 root 360: }
361:
1.1.1.3 root 362: // アクセスウェイト [clock] を設定。
363: // X68030 でシステムポートから呼ばれるため normal_wait のみ設定する。
1.1 root 364: void
1.1.1.3 root 365: MainRAMDevice::SetWait(uint32 wait_clock)
1.1 root 366: {
1.1.1.2 root 367: uint32 clock_nsec = mpu->GetClock_nsec();
368:
1.1.1.3 root 369: normal_wait = busdata::Wait(wait_clock * clock_nsec);
1.1 root 370: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.