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