|
|
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.2 root 7: // LUNA88K の ROM エミュレーション
8:
9: // IODevice
10: // |
1.1.1.5 ! 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_luna88k.h"
1.1.1.5 ! root 21: #include "bitmap.h"
! 22: #include "iodevstream.h"
1.1 root 23: #include "mainapp.h"
24: #include "memorystream.h"
1.1.1.5 ! root 25: #include "pio.h"
1.1 root 26: #include "ram.h"
1.1.1.5 ! root 27: #include "sysctlr.h"
1.1 root 28:
29: // コンストラクタ
30: Luna88kPROMEmuDevice::Luna88kPROMEmuDevice()
31: {
32: devaddr = baseaddr;
1.1.1.5 ! root 33:
! 34: // ROM の特定アドレスを読み出す人がいるかも知れないので、
! 35: // サイズは実 ROM と同じにしておく。LUNA-I からの類推。
1.1.1.2 root 36: devlen = 256 * 1024;
1.1.1.5 ! root 37: romdata.reset(new uint8 [devlen]);
1.1.1.2 root 38:
1.1.1.5 ! root 39: // プロンプトを初期化。
! 40: // 本物は "O>" というプロンプトでよく分からんけど、こっちは nono の
! 41: // 頭文字ということにしておく。
! 42: prompt = "N>";
1.1 root 43: }
44:
45: // デストラクタ
46: Luna88kPROMEmuDevice::~Luna88kPROMEmuDevice()
47: {
48: }
49:
50: bool
51: Luna88kPROMEmuDevice::Init()
52: {
1.1.1.5 ! root 53: // 親クラス
! 54: if (inherited::Init() == false) {
! 55: return false;
! 56: }
! 57:
1.1.1.2 root 58: MemoryStreamBE ms(romdata.get());
1.1 root 59:
1.1.1.5 ! root 60: // MPU を仕様通りに動作させるなら、リセット時に ROM を 0番地付近に見せて
! 61: // 実行中に RAM に切り替えるのが定番だが、nono ではそれは意図して実装して
! 62: // いない。従って xip = $41000000 から実行開始するのに対して vbr の初期値
! 63: // は 0 なので、ROM の $41000008 以降をベクタ用にリザーブする必要がない。
! 64: // よって $41000000 から直接コードを置いていく。
! 65:
! 66: // ; 元の PSR を r10 に保存しつつ
! 67: // ; 割り込み許可
! 68: ms.Write32(0x81404020); // ldcr r10, psr
! 69: ms.Write32(0xf04a8040); // clr r2, r10, 2<1> ; IND,SFRZ
! 70: ms.Write32(0x80028022); // stcr r2, psr
! 71: // ; r3 <- ROMIO_BASE
! 72: ms.Write32(0x5c600000 | // or.u r3, r0, #ROMIO_BASE.Hi
! 73: (ROMIO_BASE >> 16)); //
! 74: ms.Write32(0x58630000 | // or r3, r0, #ROMIO_BASE.Lo
! 75: (ROMIO_BASE & 0xffff)); //
! 76: // ; ROMIO_INIT を読み出す
! 77: ms.Write32(0x14430000); // ld r2, r3, #+INIT
! 78: // ; 起動先があれば GO
! 79: ms.Write32(0xe9a20005); // bcnd ne0, r2, _go
! 80: // _prompt:
! 81: // ; 疑似 STOP でキー入力を待つ
! 82: ms.Write32(0xc8000001); // bsr _stop
! 83: // ; この時点で r1 = _stop
! 84: // _stop:
! 85: ms.Write32(0xf400c001); // jmp r1
! 86: // _back:
! 87: ms.Write32(0x14430000 | // ld r2, r3, #+ENTRY
! 88: (ROMIO_ENTRY - ROMIO_BASE));//
! 89: // ; 起動先がなければループ
! 90: ms.Write32(0xe842fffd); // bcnd eq0, r2, _prompt
! 91: // ; 起動先があれば後始末して
! 92: ms.Write32(0x14030000 | // _go:
! 93: (ROMIO_CLOSE - ROMIO_BASE));// ld r0, r3, #+CLOSE
! 94: // ; 割り込み禁止に戻す
! 95: ms.Write32(0x800a802a); // stcr r10, psr
! 96: // ; ジャンプ
! 97: ms.Write32(0xf400c002); // jmp r2
! 98:
! 99: // ここから割り込みハンドラ。割り込みは SIO のみ許可にしてある。
! 100: // キーボード割り込みが上がったら KEYIN をコールして _back に戻る。
! 101: ms.SetPtr(&romdata[0x200]);
! 102: ms.Write32(0x14030000 | // ld r0, r3, #+KEYIN
! 103: (ROMIO_KEYIN - ROMIO_BASE));//
! 104: // ; 戻ったところの jmp を抜ける
! 105: ms.Write32(0x60210004); // addu r1, r1, #4
! 106: ms.Write32(0xf400fc00); // rte
1.1 root 107:
108: return true;
109: }
110:
1.1.1.5 ! root 111: // 起動時の処理を行う。
! 112: // 次段実行ファイルの読み込みに成功すればそのエントリポイントを返す。
! 113: // そうでなければ 0 を返すので、プロンプトに処理を移すこと。
! 114: uint32
! 115: Luna88kPROMEmuDevice::ROM_Init()
1.1 root 116: {
1.1.1.5 ! root 117: IODeviceStream rs(gRAM.get());
! 118: uint32 entry;
1.1 root 119:
1.1.1.5 ! root 120: // デバイスの初期化 (親クラス)
! 121: InitDevice();
! 122: // 割り込みマスクで SIO だけ許可
! 123: gInterrupt->Write32(0x65000000, 0x40000000);
1.1 root 124:
1.1.1.5 ! root 125: rs.SetAddr(0);
! 126: // ベクタテーブルを rte で埋めておく
! 127: for (int i = 0; i < 512 * 2; i++) {
! 128: rs.Write32(0xf400fc00 /* rte */);
! 129: }
! 130: // +$08: 割り込みベクタ
! 131: rs.Write32(8, 0xc00003fe); // br $00001000
! 132:
! 133: // 割り込みトランポリン (0x1000)
! 134: // ベクタテーブルは各2ワードしかないのに、0 番地付近にあるベクタテーブル
! 135: // から2ワードでは ROM まで飛べない。一体どういう設計してんだ…。
! 136: rs.SetAddr(0x1000);
! 137: rs.Write32(0x5cc04100); // or.u r6, r0, #0x4100
! 138: rs.Write32(0x58c60200); // or r6, r6, #0x0200
! 139: rs.Write32(0xf400c006); // jmp r6
1.1.1.2 root 140:
1.1.1.5 ! root 141: // ROM の機能テーブル
! 142: // 0x00001100 からあるようだ
! 143: // 0x0000110c GETC()
! 144: // 0x00001110 PUTC(c)
! 145: // 0x00001114 ビットマッププレーンの有効状態が入っている。
! 146: // bit0: plane0 有効
! 147: // bit1..7: plane1..7 有効
! 148: rs.SetAddr(0x110c);
! 149: rs.Write32(0x00001300);
! 150: rs.Write32(0x00001400);
! 151: rs.Write32(0x00000001);
! 152:
! 153: // ROM GETC エミュレータ
! 154: rs.SetAddr(0x1300);
! 155: rs.Write32(0xfc000c00); // internal inst getc
! 156: rs.Write32(0xf400c001); // jmp r1
1.1.1.2 root 157:
1.1.1.5 ! root 158: // ROM PUTC エミュレータ
! 159: rs.SetAddr(0x1400);
! 160: rs.Write32(0xfc001000); // internal inst putc
! 161: rs.Write32(0xf400c001); // jmp r1
! 162:
! 163: // スクリーンを初期化
! 164: InitScreen("LUNA88K");
! 165:
! 166: entry = 0;
! 167:
! 168: // 表示環境が整ったところで NVRAM を照合
! 169: if (VerifyNVRAM() == false) {
! 170: InitNVRAM();
! 171: text.Print("** NVRAM Initialized.\n");
! 172: text.Print("\n");
! 173: // NVRAM をクリアしたら DIPSW によらずプロンプトに降りる
! 174: goto done;
! 175: }
! 176:
! 177: // DIPSW#1-1 が UP なら自動起動、DOWN なら ROM モニタ起動なので、
! 178: // これを真似する。
! 179: if ((gPIO0->GetDIPSW1() & 1)) {
! 180: if (gMainApp.host_file) {
! 181: // ホストのファイルを読み込んでエントリポイントアドレスを
! 182: // この Read アクセスの読み出し値として返す。
! 183: // エラーがあればエラーメッセージは呼び出し先側で表示してある。
! 184: entry = LoadHostFile();
! 185: } else {
! 186: // NVRAM の設定に従ってブート先を探す。
! 187: errmsg.clear();
! 188:
! 189: bootinfo_t bootinfo;
! 190: GetNVRAM(bootinfo);
! 191: entry = LoadGuestFile(bootinfo);
! 192: if (entry == 0) {
! 193: text.Print("** %s\n", errmsg.c_str());
! 194: }
! 195: }
! 196: }
! 197:
! 198: // ここまでタイトルなどを Print してはいるが、実際の画面更新は
! 199: // ConsoleUpdate() を呼ぶまで行われないことを利用(悪用?)して、
! 200: // ここでエラーなくブートプログラムに制御を渡せる場合には何も表示せずに
! 201: // ゲストに処理を移す。意図して或いは意図せずプロンプトに降りる場合だけ
! 202: // ConsoleUpdate を呼ぶことでタイトルを含めて画面を表示する。
! 203: done:
! 204: if (entry == 0) {
! 205: ConsoleUpdate();
! 206: }
! 207:
! 208: return entry;
! 209: }
! 210:
! 211: // ROM 処理。エントリポイントを返す。
! 212: uint32
! 213: Luna88kPROMEmuDevice::ROM_Entry()
! 214: {
! 215: if (b_entrypoint != 0) {
! 216: return b_entrypoint;
1.1.1.2 root 217: } else {
1.1.1.5 ! root 218: return 0;
1.1.1.2 root 219: }
220: }
221:
1.1.1.5 ! root 222: // 入力コマンド処理 (入力行が揃ったところで呼ばれる)。
! 223: //
! 224: // b 現在のパラメータで起動
! 225: // b ... パラメータを指定して起動
! 226: // nvram 全パラメータを表示
! 227: // nvram [<name>] name のみ表示?
! 228: // nvram <name> <val> 値を設定
! 229: // nvram - <name> 削除
! 230: // nvram-- NVRAM 初期化
! 231:
! 232: void
! 233: Luna88kPROMEmuDevice::Command()
1.1.1.2 root 234: {
1.1.1.5 ! root 235: std::vector<char> buf(inputbuf.length() + 1);
! 236: std::vector<std::string> arg;
1.1.1.2 root 237:
1.1.1.5 ! root 238: // 1ワードごとに分解
! 239: strcpy(&buf[0], inputbuf.c_str());
! 240: char *p = &buf[0];
! 241: char *s = p;
! 242: while (*p != '\0') {
! 243: if (*p == ' ') {
! 244: *p++ = '\0';
! 245: arg.push_back(std::string(s));
! 246: s = p;
! 247: } else {
! 248: p++;
! 249: }
! 250: }
! 251: if (p != s) {
! 252: arg.push_back(std::string(s));
! 253: }
! 254: if (loglevel >= 1) {
! 255: for (int i = 0; i < arg.size(); i++) {
! 256: putmsgn("arg[%d]=|%s|", i, arg[i].c_str());
! 257: }
! 258: }
1.1.1.2 root 259:
1.1.1.5 ! root 260: // 空行
! 261: if (arg.size() == 0) {
! 262: return;
! 263: }
! 264:
! 265: // 1ワード目がコマンド
! 266: if (arg[0] == "h") {
! 267: // ヘルプメッセージ
! 268: text.Print(
! 269: " *** Help Message ***\n"
! 270: " b : load and execute program\n"
! 271: " h : show this message\n"
! 272: #if 0
! 273: " nvram : show/set nvram parameters\n"
! 274: #endif
! 275: );
! 276: return;
! 277: }
! 278: if (arg[0] == "b") {
! 279: CommandB(arg);
! 280: return;
! 281: }
! 282: #if 0
! 283: if (arg[0] == "nvram") {
! 284: CommandNvram(arg);
! 285: return;
1.1.1.2 root 286: }
1.1.1.5 ! root 287: #endif
! 288:
! 289: text.Print("** Unknown command: %s\n", arg[0].c_str());
1.1.1.2 root 290: }
291:
1.1.1.5 ! root 292: // "b" コマンド
! 293: // 引数なしなら NVRAM の情報に従ってプログラムをロードして実行。
! 294: // 引数ありのほうは未実装。
! 295: void
! 296: Luna88kPROMEmuDevice::CommandB(const std::vector<std::string>& arg)
1.1 root 297: {
1.1.1.5 ! root 298: errmsg.clear();
1.1 root 299:
1.1.1.5 ! root 300: // XXX とりあえず boot を起動するだけ
! 301: bootinfo_t bootinfo;
! 302: GetNVRAM(bootinfo);
! 303: b_entrypoint = LoadGuestFile(bootinfo);
! 304: if (b_entrypoint == 0) {
! 305: text.Print("** %s\n", errmsg.c_str());
1.1 root 306: }
1.1.1.5 ! root 307: }
1.1 root 308:
1.1.1.5 ! root 309: // "bh" コマンド (勝手に拡張)
! 310: // -A オプションで指定されたホストプログラムをロードして実行。
! 311: void
! 312: Luna88kPROMEmuDevice::CommandBH()
! 313: {
! 314: // 指定されてたら読み込む
! 315: if (gMainApp.host_file == NULL) {
! 316: text.Print("** Cannot loaded; host program is not specified.\n");
! 317: return;
1.1.1.2 root 318: }
1.1.1.5 ! root 319: b_entrypoint = LoadHostFile();
1.1.1.2 root 320: }
321:
1.1.1.5 ! root 322: void
! 323: Luna88kPROMEmuDevice::CommandNvram(const std::vector<std::string>& arg)
1.1.1.2 root 324: {
1.1.1.5 ! root 325: printf("%s\n", __func__);
1.1.1.2 root 326: }
327:
1.1.1.5 ! root 328: // NVRAM のチェックサムを返す
! 329: uint8
! 330: Luna88kPROMEmuDevice::CalcNVRAMCsum()
1.1.1.2 root 331: {
332: return 0;
333: }
334:
1.1.1.5 ! root 335: // NVRAM のチェックサムを計算して書き込む
! 336: void
! 337: Luna88kPROMEmuDevice::WriteNVRAMCsum()
1.1.1.2 root 338: {
339: }
340:
1.1.1.5 ! root 341: // NVRAM のマジックとチェックサムを照合する
! 342: bool
! 343: Luna88kPROMEmuDevice::VerifyNVRAM()
1.1.1.2 root 344: {
1.1.1.5 ! root 345: return true;
1.1 root 346: }
347:
1.1.1.5 ! root 348: // NVRAM を初期化する
! 349: bool
! 350: Luna88kPROMEmuDevice::InitNVRAM()
1.1 root 351: {
1.1.1.5 ! root 352: return false;
! 353: }
1.1 root 354:
1.1.1.5 ! root 355: // NVRAM のブート設定を bootinfo に取得する。
! 356: void
! 357: Luna88kPROMEmuDevice::GetNVRAM(bootinfo_t& bootinfo)
! 358: {
! 359: // XXX NVRAM 未調査につき ID=6 a: boot 固定
! 360: bootinfo.dkunit = 0;
! 361: bootinfo.dkpart = 0;
! 362: bootinfo.dkfile = "boot";
1.1 root 363: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.