|
|
1.1 root 1: //
2: // nono
3: // Copyright (C) 2020 nono project
4: // Licensed under nono-license.txt
5: //
6:
7: // PROM (LUNA-I, LUNA88K 共通)
8:
9: // IODevice
10: // |
11: // +----------------------------------------+
12: // | |
13: // v v
14: // ROMDevice Luna*PROMEmuDeivce
15: // | (ROM エミュレーションはここ)
16: // +---------+---------------+
17: // v v
18: // PROMDevice CGROMDevice など
19: // (LUNA* の実ROM共通) (X68k の各種ROM)
20:
21: #include "prom.h"
22: #include "config.h"
23: #include "mainapp.h"
1.1.1.5 root 24: #include "scheduler.h"
1.1 root 25:
26: // コンストラクタ
27: PROMDevice::PROMDevice()
1.1.1.7 ! root 28: : inherited("PROM")
1.1 root 29: {
30: devaddr = 0x41000000;
31: }
32:
33: // デストラクタ
34: PROMDevice::~PROMDevice()
35: {
36: }
37:
38: bool
39: PROMDevice::Init()
40: {
41: vmtype_t vmtype = gMainApp.GetVMType();
42:
43: switch (vmtype) {
44: case VMTYPE_LUNA1:
1.1.1.6 root 45: return InitLuna1();
1.1 root 46:
47: case VMTYPE_LUNA88K:
48: return InitLuna88k();
49:
50: default:
51: PANIC("unknown vmtype %d", vmtype);
52: }
53: }
54:
55: // LUNA-I の場合
56: bool
1.1.1.6 root 57: PROMDevice::InitLuna1()
1.1 root 58: {
59: devlen = 128 * 1024;
60: mask = devlen - 1;
61:
62: // ファイル名が存在してる時しかここに来ない
63: const ConfigItem& item = gConfig->Find("prom-image");
64: if (LoadROM(item.AsString().c_str(), devlen) == false) {
65: return false;
66: }
67:
1.1.1.2 root 68: // ROM バージョンを確認。確認されてるのは
69: // V4.02 (Wed Oct 12 17:07:11 1988)
70: // V4.22 (Thu Jul 27 11:45:42 1989)
71: // V4.25
72: //
73: // とりあえず V4.22 は +$00d390 からにタイムスタンプ文字列があるので
74: // それで判別してみる。
75: //00d390 54 68 75 20 4a 75 6c 20 32 37 20 31 31 3a 34 35 |Thu Jul 27 11:45|
76: //00d3a0 3a 34 32 20 31 39 38 39 00 00 00 00 4e 56 fd f8 |:42 1989....NV..|
77:
78: if (strcmp((const char *)&mem[0xd390], "Thu Jul 27 11:45:42 1989") == 0) {
79: // V4.22
80: putlog(1, "V4.22 detected");
81:
82: // MAC アドレスは ROM に書き込まれているので、ここで上書き
83: if (strcmp((const char *)&mem[0x1ffd8], "ENADDR") != 0) {
84: warnx("ENADDR not found; unknown ROM V4.22 variants?");
85: return false;
86: }
87:
88: // MAC アドレスは12桁の16進数文字列として書き込まれている。例えば
89: // 前半の 00:00:0A 部分は 30 30 30 30 30 41 "00000A" という感じ。
90: const macaddr_t macaddr = gEthernet->GetMacAddr();
91: memcpy(&mem[0x1ffe0], macaddr.to_string().c_str(), 12);
92:
93: // SCSI デバッグビット
94: bool scsi_debug_bit = gConfig->Find(".prom-scsi-debug").AsInt();
95: mem[0x4100981d - 0x41000000] = (scsi_debug_bit) ? 0x01 : 0;
96: } else {
97: // 他の ROM は何も分からないので何もしない。
98: putlog(0, "Unknown PROM Version");
1.1 root 99: }
100:
101: return true;
102: }
103:
104: // LUNA88K の場合
105: bool
106: PROMDevice::InitLuna88k()
107: {
108: devlen = 256 * 1024;
109: mask = devlen - 1;
110:
111: // ファイル名が存在してる時しかここに来ない
112: const ConfigItem& item = gConfig->Find("prom-image");
113: if (LoadROM(item.AsString().c_str(), devlen) == false) {
114: return false;
115: }
116:
117: return true;
118: }
119:
120: bool
121: PROMDevice::PowerOn()
122: {
123: // パフォーマンス測定に電源オン時の実時刻を記憶。
124: // Write8() 参照。
1.1.1.6 root 125: sw.Start();
1.1 root 126: return true;
127: }
128:
1.1.1.6 root 129: void
130: PROMDevice::ResetHard()
131: {
132: // PROM への Write (RAM への切り替え) は何度も実行されるので、最初の
133: // 1回だけ処理するため、こちらでも状態を持つ。
134: // Scheduler も同様のステートを持っているけど、あっちはリクエストと
135: // 現状の2つがあって、リクエスト投げて状態が変わるまでに遅延があるので
136: // たぶんこっちで処理したほうがいい。
137: isrom = true;
138: gVM->SwitchBootPage(this, true);
139: }
140:
1.1 root 141: uint64
142: PROMDevice::Read8(uint32 addr)
143: {
144: // パフォーマンス測定のためのバックドア。
145: // 0x42000004 番地をバイト読み込みを行うと VM 電源オン時から現在までの
146: // 実時間をホスト (ログ) に出力する。NetBSD のマルチユーザブートが
147: // あらかた終わってログインプロンプトが出る少し前に実行される
148: // /etc/rc.local に
149: // dd if=/dev/mem skip=1107296260 bs=1 count=1
150: // と書いておくことでここまでにかかる時間を表示できる。ただしこの値は
151: // ホスト性能に依存するため、同一環境下での相対的な比較のみが可能。
152: // 実機ではこの動作では PROM のミラーが読めるだけなので副作用はないはず。
153: // PROM は仕様では 0x4100_0000 から 128KB なので、ここでは通常アクセス
154: // するはずのない 0x4200_0004 からの1バイトの読み込みをバックドアに使う。
155: // 0x4100_0000..0x41ff_ffff への書き込みは 0番地付近を ROM から RAM に
156: // 切り替えるらしいが実際に PROM がアクセスするのは 0x4100_0000.[BL]
157: // のみなので、ここではそれを避けて 0x4200_0004.B を使う。
158: // 書き込みをバックドアにしたかったが dd で書き込めなさそうだったので
159: // 読み込みを使う。ちゃんと調べてない。
1.1.1.4 root 160: if (__predict_false(addr == 0x42000004)) {
1.1.1.6 root 161: uint64 rtime;
162: uint64 vtime;
1.1 root 163:
164: // 電源オン時からここまでの時間を表示するだけでリセット等はしない。
1.1.1.6 root 165: sw.Stop();
166: rtime = sw.Elapsed();
167: vtime = gMPU->GetVirtTime();
1.1 root 168: putlog(0, "電源オンから %d.%03d 秒経過 %3.3f%%",
1.1.1.6 root 169: (int)(rtime / (1000 * 1000 * 1000)),
170: (int)((rtime / (1000 * 1000)) % 1000),
171: (double)vtime / rtime * 100);
1.1 root 172: }
173:
174: // それ以外は通常動作
175: return inherited::Read8(addr);
176: }
177:
178: uint64
179: PROMDevice::Write8(uint32 addr, uint32 data)
180: {
1.1.1.6 root 181: return Write(addr);
182: }
1.1 root 183:
1.1.1.6 root 184: uint64
185: PROMDevice::Write16(uint32 addr, uint32 data)
186: {
187: return Write(addr);
1.1 root 188: }
189:
190: uint64
191: PROMDevice::Write32(uint32 addr, uint32 data)
192: {
1.1.1.6 root 193: return Write(addr);
194: }
195:
196: // Write{8,16,32} 共通。
197: // LUNA では書き込みでバスエラーは起きない。
198: // 電源オン後最初の書き込みでブートページを RAM に切り替える。
199: uint64
200: PROMDevice::Write(uint32 addr)
201: {
202: if (__predict_false(isrom)) {
203: // LUNA では PROM への書き込みでブートページを RAM に切り替えている。
204: // - LUNA-I では最初に $41000000.B への書き込みがあるが、
205: // それ以降も $41000000.L への書き込みが(複数回)あるようだ。
206: // - LUNA88K では $4100000c.L への書き込みがある。
207: // よってアドレスを定めず PROM 全域への書き込みで最初の1回だけ発動
208: // するようにしておく。サイズも今の所ワード(16bit)アクセスは確認して
209: // ないけど統一的に対処しておく。
210:
211: // XXX PROM がブートページを担当してる期間に RAM (のはずのアドレス)
212: // への書き込みは起きるんだろうか?
213: if (addr < 0x41000000) {
214: putlogn("%s addr=$%08x", __func__, addr);
215: }
216:
217: // RAM に切り替え
218: isrom = false;
219: gVM->SwitchBootPage(this, false);
1.1 root 220: }
1.1.1.6 root 221:
222: // XXX ウェイト未調査
223: gMPU->AddCycle(wait);
224:
225: // バスエラーは起きない
226: return 0;
1.1 root 227: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.