Annotation of nono/vm/mainram.cpp, revision 1.1

1.1     ! root        1: //
        !             2: // nono
        !             3: // Copyright (C) 2020 nono project
        !             4: // Licensed under nono-license.txt
        !             5: //
        !             6: 
        !             7: //
        !             8: // メインメモリ
        !             9: //
        !            10: 
        !            11: #include "mainram.h"
        !            12: #include "config.h"
        !            13: #include "mainapp.h"
        !            14: #include "mpu.h"
        !            15: #include "prom.h"
        !            16: 
        !            17: // MainRAM はロングワード単位でホストバイトオーダ配置なので、
        !            18: // バイトアクセス、ワードアクセス時は HLB(), HLW() マクロを使用のこと。
        !            19: /*static*/ std::unique_ptr<uint8[]> MainRAMDevice::mainram;
        !            20: 
        !            21: // コンストラクタ
        !            22: MainRAMDevice::MainRAMDevice()
        !            23:        : inherited(OBJ_MAINRAM)
        !            24: {
        !            25:        // アクセスウェイト
        !            26:        switch (gMainApp.GetVMType()) {
        !            27:         case VMType::LUNA1:
        !            28:                // LUNA-I は1ウェイト。
        !            29:                read_wait  = 1;
        !            30:                write_wait = 1;
        !            31:                break;
        !            32: 
        !            33:         case VMType::LUNA88K:
        !            34:                // 取扱説明書p.21 に、CMMU からのアクセスタイムが
        !            35:                // リード(4byte)で 200ns、バーストリード(16byte)で 320ns
        !            36:                // ライト(4byte)で 160ns、バーストライト(16byte)で 280ns とある。
        !            37:                // 25MHz は 40ns/clockで、この数値は CMMU からのアクセス全体の時間
        !            38:                // らしいので、ここで加算するウェイトはそれから 2クロック引いたもの。
        !            39:                read_wait  = 3;
        !            40:                write_wait = 2;
        !            41:                break;
        !            42: 
        !            43:         case VMType::X68030:
        !            44:         default:
        !            45:                // X68030 ではシステムポートが設定するのでここでは不要。
        !            46:                break;
        !            47:        }
        !            48: }
        !            49: 
        !            50: // デストラクタ
        !            51: MainRAMDevice::~MainRAMDevice()
        !            52: {
        !            53: }
        !            54: 
        !            55: // 初期化
        !            56: bool
        !            57: MainRAMDevice::Init()
        !            58: {
        !            59:        if (inherited::Init() == false) {
        !            60:                return false;
        !            61:        }
        !            62: 
        !            63:        const ConfigItem& item = gConfig->Find("ram-size");
        !            64:        int ram_size_MB = item.AsInt();
        !            65:        if (ram_size_MB < 1) {
        !            66:                item.Err();
        !            67:                return false;
        !            68:        }
        !            69:        // 下限以外の制約は機種による
        !            70:        switch (gMainApp.GetVMType()) {
        !            71:         case VMType::X68030:
        !            72:                // メインメモリは 12MB まで。
        !            73:                // 内部は 8KB 単位で処理できるが設定が 1MB 単位。
        !            74:                if (ram_size_MB > 12) {
        !            75:                        item.Err("Configurable maximum main memory size is 12 [MB]");
        !            76:                        return false;
        !            77:                }
        !            78:                break;
        !            79: 
        !            80:         case VMType::LUNA1:
        !            81:                // 16MB までは、実機に合わせて 4MB 単位とする。
        !            82:                // see http://wiki.netbsd.org/ports/luna68k/luna68k_info/#hardware
        !            83:                //
        !            84:                // 16MB を超える増設 (or 魔改造) 部分は 1MB 単位で 255MB までとする。
        !            85:                // 実 ROM のメモリチェックは 32KB だかそのくらいずつ行われ、
        !            86:                // 最後に番兵として Null 領域 (BusError ではなく) が必要。
        !            87:                // 現行の構成をあまり変えない範囲なら厳密には (256MB - 32KB) が
        !            88:                // 上限だが、設定ファイルからの指定が 1MB 単位なので 255MB。
        !            89:                if (ram_size_MB <= 16) {
        !            90:                        if (ram_size_MB % 4 != 0) {
        !            91:                                item.Err("For 16MB or less, must be specified in 4 [MB] unit");
        !            92:                                return false;
        !            93:                        }
        !            94:                } else if (ram_size_MB > 255) {
        !            95:                        item.Err("Configurable maximum RAM size is 255 [MB]");
        !            96:                        return false;
        !            97:                }
        !            98:                break;
        !            99: 
        !           100:         case VMType::LUNA88K:
        !           101:         {
        !           102:                // 64MB までは、実機に合わせて 16MB 単位とする。
        !           103:                //
        !           104:                // 64MB を超える増設 (or 魔改造) 部分は未確認。
        !           105:                if (ram_size_MB <= 64) {
        !           106:                        if (ram_size_MB % 16 != 0) {
        !           107:                                item.Err("For 64MB or less, must be specified in 16 [MB] unit");
        !           108:                                return false;
        !           109:                        }
        !           110:                } else if (ram_size_MB > 255) {
        !           111:                        item.Err("Configurable maximum RAM size is 255 [MB]");
        !           112:                        return false;
        !           113:                }
        !           114: 
        !           115:                // PROM 1.20 では 240MB を上限にする。
        !           116:                // 0x0f00'0000 (ちょうど 240MB 目) へのアクセスでバスエラーが
        !           117:                // 出ることを CMMU のアドレス変換チェックに使っているため。
        !           118:                auto prom = dynamic_cast<PROMDevice *>(GetPROMDevice());
        !           119:                if (prom && prom->GetROMVer() == 120) {
        !           120:                        if (ram_size_MB > 240) {
        !           121:                                item.Err("Maximum RAM size with PROM 1.20 is 240 [MB]");
        !           122:                                return false;
        !           123:                        }
        !           124:                }
        !           125: 
        !           126:                break;
        !           127:         }
        !           128: 
        !           129:         case VMType::NEWS:
        !           130:                // XXX とりあえず
        !           131:                memset(&mainram[0], 0, ram_size);
        !           132:                break;
        !           133: 
        !           134:         default:
        !           135:                PANIC("corrupted vmtype=%s", gMainApp.GetVMName().c_str());
        !           136:        }
        !           137: 
        !           138:        ram_size = ram_size_MB * 1024 * 1024;
        !           139:        mainram.reset(new uint8[ram_size]);
        !           140: 
        !           141:        // Human68k モードならここで一度だけメモリをゼロクリアする。
        !           142:        // この時は Human68k::Init() が MainRAM にプログラムを転送するため
        !           143:        // 電源オン時点で RAM を初期化してはいけない…。うーんこの…。
        !           144:        // MainRAM::Init() が Human68k::Init() より先に呼ばれることは
        !           145:        // VM_X68030 で指定してある。
        !           146:        // 一方、通常モードなら VM リスタート(電源再投入) で前の内容を残さない
        !           147:        // ために ResetHard(true) でメモリを (ゼロでなくてもいいので) クリアする
        !           148:        // 必要がある。
        !           149:        if (gMainApp.human_mode) {
        !           150:                memset(&mainram[0], 0, ram_size);
        !           151:        }
        !           152: 
        !           153:        // devtable[] への RAM デバイスの配置はこの後 VM::Init 側で行っている
        !           154: 
        !           155:        return true;
        !           156: }
        !           157: 
        !           158: // 電源オン/リセット
        !           159: void
        !           160: MainRAMDevice::ResetHard(bool poweron)
        !           161: {
        !           162:        if (poweron) {
        !           163:                if (gMainApp.human_mode || gMainApp.IsNEWS()) {
        !           164:                        // Human モードと NEWS は Init() がメモリに書き込むので
        !           165:                        // ここでクリアしない。うーん。
        !           166:                } else {
        !           167:                        // 通常モードならメモリをクリア
        !           168:                        // XXX ノイズを用意するべき
        !           169:                        memset(&mainram[0], 0, ram_size);
        !           170:                }
        !           171:        }
        !           172: 
        !           173:        // X68030 ではリセットで戻るはず。(LUNA は固定なので関係ない)
        !           174:        if (gMainApp.IsX68030()) {
        !           175:                read_wait  = 0;
        !           176:                write_wait = 0;
        !           177:        }
        !           178: }
        !           179: 
        !           180: uint64
        !           181: MainRAMDevice::Read8(uint32 addr)
        !           182: {
        !           183:        mpu->AddCycle(read_wait);
        !           184:        uint32 data;
        !           185:        data = mainram[HLB(addr)];
        !           186:        putlog(4, "$%08x.B -> $%02x", addr, data);
        !           187:        return data;
        !           188: }
        !           189: 
        !           190: uint64
        !           191: MainRAMDevice::Read16(uint32 addr)
        !           192: {
        !           193:        mpu->AddCycle(read_wait);
        !           194:        uint32 data;
        !           195:        data = *(uint16 *)&mainram[HLW(addr)];
        !           196:        putlog(4, "$%08x.W -> $%04x", addr, data);
        !           197:        return data;
        !           198: }
        !           199: 
        !           200: uint64
        !           201: MainRAMDevice::Read32(uint32 addr)
        !           202: {
        !           203:        mpu->AddCycle(read_wait);
        !           204:        uint32 data;
        !           205:        data = *(uint32 *)&mainram[addr];
        !           206:        putlog(4, "$%08x.L -> $%08x", addr, data);
        !           207:        return data;
        !           208: }
        !           209: 
        !           210: uint64
        !           211: MainRAMDevice::Write8(uint32 addr, uint32 data)
        !           212: {
        !           213:        mpu->AddCycle(write_wait);
        !           214:        mainram[HLB(addr)] = data;
        !           215:        putlog(3, "$%08x.B <- $%02x", addr, data);
        !           216:        return 0;
        !           217: }
        !           218: 
        !           219: uint64
        !           220: MainRAMDevice::Write16(uint32 addr, uint32 data)
        !           221: {
        !           222:        mpu->AddCycle(write_wait);
        !           223:        *(uint16 *)&mainram[HLW(addr)] = data;
        !           224:        putlog(3, "$%08x.W <- $%04x", addr, data);
        !           225:        return 0;
        !           226: }
        !           227: 
        !           228: uint64
        !           229: MainRAMDevice::Write32(uint32 addr, uint32 data)
        !           230: {
        !           231:        mpu->AddCycle(write_wait);
        !           232:        *(uint32 *)&mainram[addr] = data;
        !           233:        putlog(3, "$%08x.L <- $%08x", addr, data);
        !           234:        return 0;
        !           235: }
        !           236: 
        !           237: uint64
        !           238: MainRAMDevice::Peek8(uint32 addr)
        !           239: {
        !           240:        return mainram[HLB(addr)];
        !           241: }
        !           242: 
        !           243: uint64
        !           244: MainRAMDevice::Poke8(uint32 addr, uint32 data)
        !           245: {
        !           246:        if ((int32)data >= 0) {
        !           247:                mainram[HLB(addr)] = data;
        !           248:        }
        !           249:        return 0;
        !           250: }
        !           251: 
        !           252: // アクセスウェイトを設定 (X68030 でシステムポートから呼ばれる)
        !           253: void
        !           254: MainRAMDevice::SetWait(uint32 wait)
        !           255: {
        !           256:        read_wait  = wait;
        !           257:        write_wait = wait;
        !           258: }
        !           259: 
        !           260: // info->path で指定されたホストの実行ファイルをゲストにロードする。
        !           261: bool
        !           262: MainRAMDevice::LoadFromFile(LoadInfo *info)
        !           263: {
        !           264:        BootLoader loader(this);
        !           265: 
        !           266:        return loader.LoadFromFile(info);
        !           267: }
        !           268: 
        !           269: // info->data, size で指定されたバッファを実行ファイルとみなしてゲストに
        !           270: // ロードする。
        !           271: bool
        !           272: MainRAMDevice::LoadFromData(LoadInfo *info)
        !           273: {
        !           274:        BootLoader loader(this);
        !           275: 
        !           276:        return loader.LoadFromData(info);
        !           277: }

unix.superglobalmegacorp.com

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