Annotation of nono/vm/prom.cpp, revision 1.1.1.6

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: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.