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