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

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 共通)
1.1.1.8 ! root        8: //
        !             9: // IODevice
        !            10: //    |
        !            11: //    +-- ROMDevice (LoadROM()、ウェイト、マスク等を持つ)
        !            12: //    |     |
        !            13: //    |     |  +------------+
        !            14: //    |     +--| PROMDevice |  (LUNA* の PROM)
        !            15: //    |     |  +------------+
        !            16: //    |     |
        !            17: //    |     +-- IPLROM1Device (X680x0 の IPLROM 後半)
        !            18: //    |     +-- IPLROM2Device (X680x0 の IPLROM 前半)
        !            19: //    |     +-- CGROMDevice   (X680x0 の CGROM)
        !            20: //    |     +-- LunaPROMEmuDevice   (LUNA PROM エミュレーションの共通部分)
        !            21: //    |           |
        !            22: //    |           +-- Luna1PROMEmuDevice   (LUNA1 の PROM エミュレーション)
        !            23: //    |           +-- Luna88kPROMEmuDevice (LUNA88K の PROM エミュレーション)
        !            24: //    |
        !            25: //    |   +-------------+
        !            26: //    +-- | PROM0Device | (LUNA* のブートページ切り替え用プロキシ)
        !            27: //    |   +-------------+
        !            28: //    |
        !            29: //    +-- IPLROM0Device   (X680x0 のブートページ切り替え用プロキシ)
1.1       root       30: 
                     31: #include "prom.h"
                     32: #include "config.h"
1.1.1.8 ! root       33: #include "ethernet.h"
1.1       root       34: #include "mainapp.h"
1.1.1.5   root       35: #include "scheduler.h"
1.1       root       36: 
1.1.1.8 ! root       37: std::unique_ptr<PROM0Device> gPROM0;
        !            38: std::unique_ptr<IODevice> gPROM;
        !            39: 
        !            40: //
        !            41: // PROM0
        !            42: //
        !            43: // PROM0 は PROM のブートページ担当。
        !            44: // これ自身はメモリ領域を持たず PROM へのプロキシとして動作する。
        !            45: //
        !            46: // リセット後最初の ROM 領域への書き込みアクセスでブートページを RAM に
        !            47: // 切り替える。
        !            48: // LUNA のブートページのアドレス範囲は不明なので、とりあえず devtable の
        !            49: // 1区画である 16MB ($0000'0000..$00ff'ffff) とする。実害はない。
        !            50: 
        !            51: // コンストラクタ
        !            52: PROM0Device::PROM0Device()
        !            53:        : inherited("PROM(0)")
        !            54: {
        !            55:        ClearAlias();
        !            56:        AddAlias("PROM0");
        !            57: }
        !            58: 
        !            59: // デストラクタ
        !            60: PROM0Device::~PROM0Device()
        !            61: {
        !            62: }
        !            63: 
        !            64: bool
        !            65: PROM0Device::Init()
        !            66: {
        !            67:        prom = gPROM.get();
        !            68:        return true;
        !            69: }
        !            70: 
        !            71: void
        !            72: PROM0Device::ResetHard()
        !            73: {
        !            74:        gVM->SwitchBootPageToROM(this);
        !            75: }
        !            76: 
        !            77: // アドレスデコーダ
        !            78: /*static*/ inline uint32
        !            79: PROM0Device::Decoder(uint32 addr)
        !            80: {
        !            81:        // ここはブートページか ROM かの比較だけで十分 (それ以外はここに来ない)
        !            82:        if (addr < 0x0100'0000) {
        !            83:                addr += 0x4100'0000;
        !            84:        }
        !            85:        return addr;
        !            86: }
        !            87: 
        !            88: uint64
        !            89: PROM0Device::Read8(uint32 addr)
        !            90: {
        !            91:        addr = Decoder(addr);
        !            92:        return prom->Read8(addr);
        !            93: }
        !            94: 
        !            95: uint64
        !            96: PROM0Device::Read16(uint32 addr)
        !            97: {
        !            98:        addr = Decoder(addr);
        !            99:        return prom->Read16(addr);
        !           100: }
        !           101: 
        !           102: uint64
        !           103: PROM0Device::Read32(uint32 addr)
        !           104: {
        !           105:        addr = Decoder(addr);
        !           106:        return prom->Read32(addr);
        !           107: }
        !           108: 
        !           109: // LUNA では PROM へのライトアクセスでブートページを RAM に切り替えている。
        !           110: // - LUNA-I では最初に $41000000.B への書き込みがあるが、
        !           111: //   それ以降も $41000000.L への書き込みが(複数回)あるようだ。
        !           112: // - LUNA88K では $4100000c.L への書き込みがある。
        !           113: //
        !           114: // よってアドレスを定めず PROM 全域への書き込みで最初の1回だけ発動する
        !           115: // ようにしておく。サイズも今の所ワード(16bit)アクセスは確認してないけど
        !           116: // 統一的に対処しておく。
        !           117: uint64
        !           118: PROM0Device::Write()
        !           119: {
        !           120:        gVM->SwitchBootPageToRAM(this);
        !           121: 
        !           122:        // バスエラーは起きない
        !           123:        return 0;
        !           124: }
        !           125: 
        !           126: uint64
        !           127: PROM0Device::Write8(uint32 addr, uint32 data)
        !           128: {
        !           129:        return Write();
        !           130: }
        !           131: 
        !           132: uint64
        !           133: PROM0Device::Write16(uint32 addr, uint32 data)
        !           134: {
        !           135:        return Write();
        !           136: }
        !           137: 
        !           138: uint64
        !           139: PROM0Device::Write32(uint32 addr, uint32 data)
        !           140: {
        !           141:        return Write();
        !           142: }
        !           143: 
        !           144: uint64
        !           145: PROM0Device::Peek8(uint32 addr)
        !           146: {
        !           147:        addr = Decoder(addr);
        !           148:        return prom->Peek8(addr);
        !           149: }
        !           150: 
        !           151: 
        !           152: //
        !           153: // PROM
        !           154: //
        !           155: 
1.1       root      156: // コンストラクタ
                    157: PROMDevice::PROMDevice()
1.1.1.7   root      158:        : inherited("PROM")
1.1       root      159: {
                    160:        devaddr = 0x41000000;
1.1.1.8 ! root      161: 
        !           162:        // LUNA では ROM への書き込みは何も起きない
        !           163:        write_op = 0;
1.1       root      164: }
                    165: 
                    166: // デストラクタ
                    167: PROMDevice::~PROMDevice()
                    168: {
                    169: }
                    170: 
                    171: bool
                    172: PROMDevice::Init()
                    173: {
                    174:        vmtype_t vmtype = gMainApp.GetVMType();
                    175: 
                    176:        switch (vmtype) {
                    177:         case VMTYPE_LUNA1:
1.1.1.6   root      178:                return InitLuna1();
1.1       root      179: 
                    180:         case VMTYPE_LUNA88K:
                    181:                return InitLuna88k();
                    182: 
                    183:         default:
                    184:                PANIC("unknown vmtype %d", vmtype);
                    185:        }
                    186: }
                    187: 
                    188: // LUNA-I の場合
                    189: bool
1.1.1.6   root      190: PROMDevice::InitLuna1()
1.1       root      191: {
                    192:        devlen = 128 * 1024;
                    193:        mask = devlen - 1;
                    194: 
                    195:        // ファイル名が存在してる時しかここに来ない
                    196:        const ConfigItem& item = gConfig->Find("prom-image");
                    197:        if (LoadROM(item.AsString().c_str(), devlen) == false) {
                    198:                return false;
                    199:        }
                    200: 
1.1.1.8 ! root      201:        // XXX アクセスウェイトは未調査。とりあえず RAM と同程度にしておく
        !           202:        wait = 1;
        !           203: 
1.1.1.2   root      204:        // ROM バージョンを確認。確認されてるのは
                    205:        // V4.02 (Wed Oct 12 17:07:11 1988)
                    206:        // V4.22 (Thu Jul 27 11:45:42 1989)
                    207:        // V4.25
                    208:        //
                    209:        // とりあえず V4.22 は +$00d390 からにタイムスタンプ文字列があるので
                    210:        // それで判別してみる。
                    211:        //00d390 54 68 75 20 4a 75 6c 20 32 37 20 31 31 3a 34 35 |Thu Jul 27 11:45|
                    212:        //00d3a0 3a 34 32 20 31 39 38 39 00 00 00 00 4e 56 fd f8 |:42 1989....NV..|
                    213: 
                    214:        if (strcmp((const char *)&mem[0xd390], "Thu Jul 27 11:45:42 1989") == 0) {
                    215:                // V4.22
                    216:                putlog(1, "V4.22 detected");
                    217: 
                    218:                // MAC アドレスは ROM に書き込まれているので、ここで上書き
                    219:                if (strcmp((const char *)&mem[0x1ffd8], "ENADDR") != 0) {
                    220:                        warnx("ENADDR not found; unknown ROM V4.22 variants?");
                    221:                        return false;
                    222:                }
                    223: 
                    224:                // MAC アドレスは12桁の16進数文字列として書き込まれている。例えば
                    225:                // 前半の 00:00:0A 部分は 30 30 30 30 30 41 "00000A" という感じ。
                    226:                const macaddr_t macaddr = gEthernet->GetMacAddr();
                    227:                memcpy(&mem[0x1ffe0], macaddr.to_string().c_str(), 12);
                    228: 
                    229:                // SCSI デバッグビット
                    230:                bool scsi_debug_bit = gConfig->Find(".prom-scsi-debug").AsInt();
                    231:                mem[0x4100981d - 0x41000000] = (scsi_debug_bit) ? 0x01 : 0;
                    232:        } else {
                    233:                // 他の ROM は何も分からないので何もしない。
                    234:                putlog(0, "Unknown PROM Version");
1.1       root      235:        }
                    236: 
                    237:        return true;
                    238: }
                    239: 
                    240: // LUNA88K の場合
                    241: bool
                    242: PROMDevice::InitLuna88k()
                    243: {
                    244:        devlen = 256 * 1024;
                    245:        mask = devlen - 1;
                    246: 
                    247:        // ファイル名が存在してる時しかここに来ない
                    248:        const ConfigItem& item = gConfig->Find("prom-image");
                    249:        if (LoadROM(item.AsString().c_str(), devlen) == false) {
                    250:                return false;
                    251:        }
                    252: 
1.1.1.8 ! root      253:        // XXX アクセスウェイトは未調査。とりあえず RAM と同程度にしておく
        !           254:        wait = 3;
        !           255: 
1.1       root      256:        return true;
                    257: }
                    258: 
                    259: bool
                    260: PROMDevice::PowerOn()
                    261: {
                    262:        // パフォーマンス測定に電源オン時の実時刻を記憶。
1.1.1.8 ! root      263:        // Read8() 参照。
1.1.1.6   root      264:        sw.Start();
1.1       root      265:        return true;
                    266: }
                    267: 
                    268: uint64
                    269: PROMDevice::Read8(uint32 addr)
                    270: {
                    271:        // パフォーマンス測定のためのバックドア。
1.1.1.8 ! root      272:        // 0x42e576f7 番地をバイト読み込みを行うと VM 電源オン時から現在までの
1.1       root      273:        // 実時間をホスト (ログ) に出力する。NetBSD のマルチユーザブートが
                    274:        // あらかた終わってログインプロンプトが出る少し前に実行される
                    275:        // /etc/rc.local に
1.1.1.8 ! root      276:        // dd if=/dev/mem skip=1122334455 bs=1 count=1
1.1       root      277:        // と書いておくことでここまでにかかる時間を表示できる。ただしこの値は
                    278:        // ホスト性能に依存するため、同一環境下での相対的な比較のみが可能。
                    279:        // 実機ではこの動作では PROM のミラーが読めるだけなので副作用はないはず。
1.1.1.8 ! root      280:        // 出来れば書き込みをバックドアにしたかったが、たぶんカーネルレベルで
        !           281:        // 弾いてあるので、読み込みを使う。
        !           282:        if (__predict_false(addr == 0x42e576f7)) {
1.1.1.6   root      283:                uint64 rtime;
                    284:                uint64 vtime;
1.1       root      285: 
                    286:                // 電源オン時からここまでの時間を表示するだけでリセット等はしない。
1.1.1.6   root      287:                sw.Stop();
                    288:                rtime = sw.Elapsed();
                    289:                vtime = gMPU->GetVirtTime();
1.1       root      290:                putlog(0, "電源オンから %d.%03d 秒経過 %3.3f%%",
1.1.1.6   root      291:                        (int)(rtime / (1000 * 1000 * 1000)),
                    292:                        (int)((rtime / (1000 * 1000)) % 1000),
                    293:                        (double)vtime / rtime * 100);
1.1       root      294:        }
                    295: 
                    296:        // それ以外は通常動作
                    297:        return inherited::Read8(addr);
                    298: }

unix.superglobalmegacorp.com

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