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