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