|
|
1.1 root 1: //
2: // nono
1.1.1.2 root 3: // Copyright (C) 2020 nono project
4: // Licensed under nono-license.txt
1.1 root 5: //
6:
1.1.1.7 root 7: // LUNA シリーズの ROM エミュレーション共通部分
1.1.1.2 root 8:
9: // IODevice
10: // |
1.1.1.7 root 11: // +----------+---------------------+
12: // v v
13: // ROMDevice LunaPROMEmuDeivce (ROM エミュレーションの共通部分)
14: // | |
15: // | +------------+----------------+
16: // v v v
17: // PROMDevice Luna1PROMEmuDevice Luna88kPROMEmuDevice
18: // (実ROM) (LUNA-I エミュレーション) (LUNA88K エミュレーション)
1.1.1.2 root 19:
20: #include "romemu_luna.h"
1.1 root 21: #include "bitmap.h"
22: #include "bt454.h"
23: #include "mainapp.h"
24: #include "mk48t02.h"
25: #include "ram.h"
26: #include "sio.h"
27: #include "spc.h"
1.1.1.7 root 28: #include "ufs.h"
1.1 root 29:
30: // コンストラクタ
31: LunaPROMEmuDevice::LunaPROMEmuDevice()
32: {
1.1.1.6 root 33: logname = "prom";
34: devname = "PROM";
1.1 root 35: }
36:
37: // デストラクタ
38: LunaPROMEmuDevice::~LunaPROMEmuDevice()
39: {
40: }
41:
42: bool
43: LunaPROMEmuDevice::Init()
44: {
45: // 都度都度 dynamic_cast は面倒なので、ここで一度代入しとく
46: nvram = dynamic_cast<MK48T02Device*>(gRTC.get());
47:
48: return true;
49: }
50:
51: void
52: LunaPROMEmuDevice::ResetHard()
53: {
1.1.1.2 root 54: is_closed = false;
1.1.1.8 ! root 55:
! 56: // ブートページを ROM に切り替える。
! 57: isrom = true;
! 58: gVM->SwitchBootPage(this, true);
1.1 root 59: }
60:
61: // アドレスデコーダ
62: inline uint64
63: LunaPROMEmuDevice::Decoder(uint32 addr) const
64: {
1.1.1.2 root 65: // 折り返しなし
1.1 root 66: return addr - baseaddr;
67: }
68:
69: uint64
1.1.1.2 root 70: LunaPROMEmuDevice::Read8(uint32 addr)
71: {
72: uint64 offset = Decoder(addr);
73:
74: // 謎の IO 空間はロングワードアクセスのみ
75: return romdata[offset & (devlen - 1)];
76: }
77:
78: uint64
79: LunaPROMEmuDevice::Read16(uint32 addr)
80: {
81: uint64 offset = Decoder(addr);
82:
83: // 謎の IO 空間はロングワードアクセスのみ
84: return be16toh(*(uint16 *)&romdata[offset & (devlen - 1)]);
85: }
86:
87: uint64
1.1 root 88: LunaPROMEmuDevice::Read32(uint32 addr)
89: {
90: uint64 offset = Decoder(addr);
91:
92: // ロングワードアクセスでだけ謎の I/O 空間が見える
1.1.1.2 root 93: if (!is_closed) {
1.1 root 94: switch (offset) {
1.1.1.2 root 95: case ROMIO_INIT - baseaddr:
96: return ROM_Init();
1.1 root 97:
1.1.1.2 root 98: case ROMIO_KEYIN - baseaddr:
1.1.1.7 root 99: ROM_Keyin();
100: return 0;
1.1 root 101:
1.1.1.2 root 102: case ROMIO_CLOSE - baseaddr:
1.1.1.7 root 103: ROM_Close();
104: return 0;
1.1 root 105:
1.1.1.6 root 106: case ROMIO_ENTRY - baseaddr:
1.1.1.7 root 107: return ROM_Entry();
1.1.1.6 root 108:
1.1 root 109: default:
110: break;
111: }
112: }
1.1.1.2 root 113: return be32toh(*(uint32 *)&romdata[offset & (devlen - 1)]);
114: }
115:
116: uint64
117: LunaPROMEmuDevice::Write8(uint32 addr, uint32 data)
118: {
119: return 0;
120: }
121:
122: uint64
123: LunaPROMEmuDevice::Write16(uint32 addr, uint32 data)
124: {
125: return 0;
126: }
127:
128: uint64
129: LunaPROMEmuDevice::Write32(uint32 addr, uint32 data)
130: {
131: return 0;
132: }
133:
134: uint64
135: LunaPROMEmuDevice::Peek8(uint32 addr)
136: {
137: uint64 offset = Decoder(addr);
138:
139: return romdata[offset & (devlen - 1)];
1.1 root 140: }
141:
1.1.1.7 root 142: // デバイスの初期化の共通部分。(継承クラスの ROM_Init() から呼ぶ)
143: void
144: LunaPROMEmuDevice::InitDevice()
1.1 root 145: {
1.1.1.8 ! root 146: // ブートページを RAM に切り替える。
! 147: if (isrom) {
! 148: isrom = false;
! 149: gVM->SwitchBootPage(this, false);
! 150: }
! 151:
1.1 root 152: // 初期パレット
1.1.1.4 root 153: // 偶数番は白(R/G/B=15/15/15)、奇数番は黒(0/0/0)。
154: uint8 val = 0xf0;
1.1.1.7 root 155: gBT454->Write(0, 0); // select palette
1.1.1.4 root 156: for (int i = 0; i < 16; i++) {
1.1.1.7 root 157: gBT454->Write(1, val); // R
158: gBT454->Write(1, val); // G
159: gBT454->Write(1, val); // B
1.1.1.4 root 160: val ^= 0xf0;
161: }
1.1 root 162:
163: // SCSI
164: // BDID の書き込みによってホストデバイスがバスにアタッチされる構造なので。
1.1.1.7 root 165: gSPC->Write(SPC::BDID, 7);
1.1 root 166:
1.1.1.7 root 167: // キーボード(chB)を初期化
168: gSIO->Write(3, 0x01); // CR1
169: gSIO->Write(3, 0x10); // RX Int(all char)
170: gSIO->Write(3, 0x03); // CR3
171: gSIO->Write(3, 0xc1); // RX Enable, 8bit
172: gSIO->Write(3, 0x04); // CR4
173: gSIO->Write(3, 0x44); // Stop 1bit
174: gSIO->Write(3, 0x05); // CR5
175: gSIO->Write(3, 0x68); // TX Enable, 8bit
176: }
1.1.1.2 root 177:
1.1.1.7 root 178: // スクリーンを初期化
179: void
180: LunaPROMEmuDevice::InitScreen(const char *machine_name)
181: {
1.1 root 182: text.Init(80, 32);
183: gBitmap->EmuConsoleOpen(&text);
1.1.1.2 root 184: inputbuf.clear();
185: inputpos = 0;
186: is_shift = false;
1.1.1.3 root 187: mousecnt = 0;
1.1 root 188:
1.1.1.7 root 189: text.Print(0, 0, "NONO %d.%d.%d Emulated ROM Monitor for %s",
190: NONO_MAJOR_VER, NONO_MINOR_VER, NONO_PATCH_VER, machine_name);
1.1 root 191: text.Locate(0, 2);
192: }
193:
1.1.1.7 root 194: // ROM 処理のクローズ
195: void
1.1.1.2 root 196: LunaPROMEmuDevice::ROM_Close()
1.1 root 197: {
198: // ここでバックドアに蓋をする
1.1.1.2 root 199: is_closed = true;
1.1 root 200:
1.1.1.7 root 201: // SIO からキーの Break 入力を取り除いておく。
202: // コマンド入力によってここへ来る時は、キーの Make で呼ばれるため
203: // Break はまだ取り出されておらず SIO のバッファに残っている。
204: // コマンド入力によらずここに来た場合でも空読みして問題ないだろう。
205: (void)gSIO->Read(2);
206:
1.1 root 207: // コンソールクローズ
208: gBitmap->EmuConsoleClose();
209: }
210:
1.1.1.2 root 211: // ROM プロンプトのキー入力。
1.1.1.7 root 212: // ゲストコードの割り込みハンドラから呼ばれて、キー入力で行を構成し、
213: // あるいは行が完成すればコマンドを実行する。
214: // 実行結果により画面を更新したりメンバ変数を更新する。
215: void
1.1.1.2 root 216: LunaPROMEmuDevice::ROM_Keyin()
1.1 root 217: {
1.1.1.7 root 218: uint32 lunakey = gSIO->Read(2);
1.1 root 219:
1.1.1.3 root 220: // マウス入力の 2, 3バイト目は無視
221: if (mousecnt > 0) {
222: mousecnt--;
1.1.1.7 root 223: return;
1.1.1.3 root 224: }
225:
1.1.1.2 root 226: // SHIFT キーだけ状態を持つので先に処理
227: if (lunakey == 0x0c || lunakey == 0x0d) { // 左右SHIFT押下
228: is_shift = true;
1.1.1.7 root 229: return;
1.1.1.2 root 230: }
231: if (lunakey == 0x8c || lunakey == 0x8d) { // 左右SHIFT開放
1.1 root 232: is_shift = false;
1.1.1.7 root 233: return;
1.1.1.2 root 234: }
1.1.1.3 root 235: // マウスデータの1バイト目なら、後続2バイトをスキップ
236: if ((lunakey & 0xf8) == 0x80) {
237: mousecnt = 2;
1.1.1.7 root 238: return;
1.1.1.3 root 239: }
240: // キー開放は無視してよい
1.1.1.2 root 241: if ((lunakey & 0x80)) {
1.1.1.7 root 242: return;
1.1.1.2 root 243: }
1.1 root 244:
1.1.1.2 root 245: switch (lunakey) {
246: case 0x11: // BS
247: if (inputpos > 0) {
248: inputbuf.erase(--inputpos);
1.1 root 249: }
1.1.1.2 root 250: break;
251: case 0x12: // Enter
252: {
253: // 現在位置のカーソルを消去
254: int curx = prompt.length() + inputpos;
1.1.1.8 ! root 255: // TA::On かそうでないかしか使っていないので
! 256: // とりあえずこうしておく
! 257: text.Locate(curx, text.GetY());
! 258: text.SetAttr(TA::Normal);
1.1.1.2 root 259: // 改行
260: text.Putc('\n');
261: // コマンド処理。
1.1.1.7 root 262: Command();
1.1.1.2 root 263: inputbuf.clear();
264: inputpos = 0;
265: break;
266: }
267: case 0x1d: // ←
268: if (inputpos > 0) {
269: inputpos--;
1.1 root 270: }
1.1.1.2 root 271: break;
272: case 0x1e: // →
273: if (inputpos < inputbuf.length()) {
1.1 root 274: inputpos++;
275: }
276: break;
1.1.1.2 root 277: default: // 通常文字
278: {
279: char asciicode;
280: if (is_shift) {
281: asciicode = lunakey2shifttable[lunakey];
282: } else {
283: asciicode = lunakey2asciitable[lunakey];
284: }
285: if (asciicode == 0) {
286: // 割り当てなし
1.1.1.7 root 287: return;
1.1.1.2 root 288: }
289: inputbuf.insert(inputbuf.begin() + inputpos, asciicode);
290: inputpos++;
291: break;
292: }
1.1 root 293: }
1.1.1.2 root 294: putmsg(2, "inputbuf=%zd|%s|", inputbuf.length(), inputbuf.c_str());
295: ConsoleUpdate();
296: }
1.1 root 297:
1.1.1.2 root 298: // 画面を更新
299: void
300: LunaPROMEmuDevice::ConsoleUpdate()
301: {
1.1 root 302: // 入力行全体を都度更新 (面倒なので行をはみ出さないようにする)
303: std::string buf = prompt + inputbuf;
304: text.Print(0, text.GetY(), "%-79s", buf.c_str());
1.1.1.8 ! root 305: // カーソルを描画
1.1 root 306: int curx = prompt.length() + inputpos;
1.1.1.8 ! root 307: // TA::On かそうでないかしか使っていないので
! 308: // とりあえずこうしておく
! 309: text.Locate(curx, text.GetY());
! 310: text.SetAttr(TA::On);
1.1 root 311: // 画面更新
312: gBitmap->EmuConsoleUpdate();
313: }
314:
315: // -A オプションで指定されたホストファイルをロードする。
316: // ロードできればエントリポイントを返す。
317: // host_file が指定されている時に呼ぶこと。
318: uint32
319: LunaPROMEmuDevice::LoadHostFile()
320: {
321: assert(gMainApp.host_file);
322:
1.1.1.7 root 323: uint32 entry = gRAM->LoadFile(gMainApp.host_file);
1.1 root 324: if (entry) {
325: text.Print("Host program loaded. Entry point = $%08x\n",
326: entry);
327: } else {
328: text.Print("** Couldn't load specified host program.\n");
329: }
330: return entry;
331: }
332:
1.1.1.7 root 333: // bootinfo に従ってゲストから起動先をロードする。
1.1 root 334: // 成功すればエントリポイントを返す。
335: // 失敗ならをエラーメッセージを errmsg にセットして 0 を返す。
336: uint32
1.1.1.7 root 337: LunaPROMEmuDevice::LoadGuestFile(const bootinfo_t& bootinfo)
1.1 root 338: {
1.1.1.7 root 339: const int& dkpart = bootinfo.dkpart;
340: const int& dkunit = bootinfo.dkunit;
341: const std::string& dkfile = bootinfo.dkfile;
1.1 root 342:
343: // ユニット (今は SCSI ID=6 決め打ち)
344: int id = 6;
345: SCSITarget *target = gSPC->GetTarget(id);
346: if (target == NULL) {
347: errmsg = "No bootable disks";
348: putmsg(0, "%s", errmsg.c_str());
349: return 0;
350: }
1.1.1.3 root 351: if (target->GetDevType() != SCSI::DevType::HD) {
1.1 root 352: errmsg = "No bootable disks";
353: putmsg(0, "%s", errmsg.c_str());
354: return 0;
355: }
356:
357: SCSIHD *hd = dynamic_cast<SCSIHD*>(target);
358: putmsg(2, "%s SCSIHD[%d] found", __func__, id);
359:
360: // +0 セクタ目(512byte)に Sun disklabel
361: scd_dk_label dk;
362: if (hd->PeekImage(&dk, 0, sizeof(dk)) == false) {
363: putmsg(0, "SCSIHD[%d] ReadSector failed", id);
364: errmsg = string_format("dk%d Read disklabel failed.", dkunit);
365: return 0;
366: }
367:
368: // +$1fc の MAGIC をチェック
369: uint32 magic = be16toh(dk.magic);
370: if (magic != scd_dk_label::DKL_MAGIC) {
371: putmsg(0, "SCSIHD[%d] Bad magic 0x%04x (!= 0x%x)",
372: id, magic, scd_dk_label::DKL_MAGIC);
373: errmsg = string_format("dk%d Bad disklabel magic.", dkunit);
374: return 0;
375: }
376:
377: // チェックサム照合は手抜きで省略
378:
379: // 指定パーティションの開始位置とサイズ
380: if (loglevel >= 2) {
381: // デバッグ用に全部表示
382: for (int i = 0; i < 8; i++) {
1.1.1.7 root 383: putmsgn("%s partition %c: { start=%8u size=%8u }", __func__,
1.1 root 384: 'a' + i,
385: be32toh(dk.map[i].blkno),
386: be32toh(dk.map[i].nblk));
387: }
388: }
389: uint32 part_start = be32toh(dk.map[dkpart].blkno);
390: uint32 part_size = be32toh(dk.map[dkpart].nblk);
391: putmsg(1, "%s partition=%c, start=%u size=%u", __func__,
392: dkpart + 'a', part_start, part_size);
393:
394: // ファイルシステムをオープン (マウントっぽいイメージ)
395: Filesys fsys(this);
1.1.1.7 root 396: if (fsys.Mount(hd, part_start, part_size) == false) {
397: errmsg = string_format("dk%d,%c Open ffs failed: %s",
398: dkunit, dkpart + 'a', fsys.errstr.c_str());
399: putmsg(0, "%s: %s", __func__, errmsg.c_str());
1.1 root 400: return 0;
401: }
402:
1.1.1.7 root 403: // ファイルを探してオープンする
404: inodefile f(this);
405: if (fsys.OpenFile(f, dkfile) == false) {
406: errmsg = string_format("dk%d,%c,%s open failed: %s",
407: dkunit, dkpart + 'a', dkfile.c_str(), fsys.errstr.c_str());
408: putmsg(0, "%s: %s", __func__, errmsg.c_str());
1.1 root 409: return 0;
410: }
1.1.1.7 root 411:
1.1 root 412: // ファイル本体を読み込み
1.1.1.7 root 413: fsys.ReadData(f);
1.1 root 414:
415: // ロード
416: uint32 entry;
417: std::string name = string_format("SCSIHD %d,%c:%s",
1.1.1.7 root 418: id, dkpart + 'a', dkfile.c_str());
419: entry = gRAM->LoadFile(name.c_str(), f.data.data(), f.data.size());
420: if (entry == 0) {
421: errmsg = string_format("dk%d,%c,%s not executable",
422: dkunit, dkpart + 'a', dkfile.c_str());
1.1 root 423: }
424:
1.1.1.7 root 425: return entry;
1.1 root 426: }
427:
1.1.1.7 root 428: // キーコードから文字への変換
429: /*static*/ const uint8
430: LunaPROMEmuDevice::lunakey2asciitable[] = {
431: 0, 0, 0, 0, 0, 0, 0, 0,
432: 0, 0, 0, 0, 0, 0, 0, 0,
433: 0, 0, 0, 0, ' ', 0, 0, 0,
434: 0, 0, 0, 0, 0, 0, 0, 0,
435: 0, 0, '1', '2', '3', '4', '5', '6',
436: '7', '8', '9', '0', '-', '^', '\\', 0,
437: 0, 0, 'q', 'w', 'e', 'r', 't', 'y',
438: 'u', 'i', 'o', 'p', '@', '[', 0, 0,
439: 0, 0, 'a', 's', 'd', 'f', 'g', 'h',
440: 'j', 'k', 'l', ';', ':', ']', 0, 0,
441: 0, 0, 'z', 'x', 'c', 'v', 'b', 'n',
442: 'm', ',', '.', '/', 0, 0, 0, 0,
443: 0, 0, 0, 0, 0, 0, 0, 0, // XXX テンキー
444: 0, 0, 0, 0, 0, 0, 0, 0,
445: 0, 0, 0, 0, 0, 0, 0, 0,
446: 0, 0, 0, 0, 0, 0, 0, 0,
447: };
448: /*static*/ const uint8
449: LunaPROMEmuDevice::lunakey2shifttable[] = {
450: 0, 0, 0, 0, 0, 0, 0, 0,
451: 0, 0, 0, 0, 0, 0, 0, 0,
452: 0, 0, 0, 0, ' ', 0, 0, 0,
453: 0, 0, 0, 0, 0, 0, 0, 0,
1.1.1.8 ! root 454: 0, 0, '!', '\"', '#', '$', '%', '&',
! 455: '\'', '(', ')', ' ', '=', '~', '|', 0, // XXX SHIFT+'0'は?
1.1.1.7 root 456: 0, 0, 'Q', 'W', 'E', 'R', 'T', 'Y',
457: 'U', 'I', 'O', 'P', '`', '{', 0, 0,
458: 0, 0, 'A', 'S', 'D', 'F', 'G', 'H',
459: 'J', 'K', 'L', '+', '*', '}', 0, 0,
460: 0, 0, 'Z', 'X', 'C', 'V', 'B', 'N',
461: 'M', '<', '>', '?', '_', 0, 0, 0,
462: 0, 0, 0, 0, 0, 0, 0, 0, // XXX テンキー
463: 0, 0, 0, 0, 0, 0, 0, 0,
464: 0, 0, 0, 0, 0, 0, 0, 0,
465: 0, 0, 0, 0, 0, 0, 0, 0,
466: };
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.