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

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

unix.superglobalmegacorp.com

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