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

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.1.3 ! root       60:                // バースト用の線は回路図によると配線されていないようだ。
1.1       root       61:                break;
                     62: 
                     63:         case VMType::LUNA1:
1.1.1.2   root       64:         {
1.1       root       65:                // 16MB までは、実機に合わせて 4MB 単位とする。
                     66:                // see http://wiki.netbsd.org/ports/luna68k/luna68k_info/#hardware
                     67:                //
1.1.1.2   root       68:                // 16MB を超える増設 (or 魔改造) 部分は 1MB 単位とする。
1.1       root       69:                if (ram_size_MB <= 16) {
                     70:                        if (ram_size_MB % 4 != 0) {
                     71:                                item.Err("For 16MB or less, must be specified in 4 [MB] unit");
                     72:                                return false;
                     73:                        }
1.1.1.2   root       74:                } else if (ram_size_MB > 512) {
                     75:                        item.Err("Configurable maximum RAM size is 512 [MB]");
1.1       root       76:                        return false;
                     77:                }
1.1.1.2   root       78: 
                     79:                // 実 ROM のメモリチェックは 32KB だかそのくらいずつ行われ、
                     80:                // 最後に番兵として NOP 領域 (BusError ではなく) が必要。
                     81:                // 現行の構成をあまり変えない範囲なら厳密には (256MB - 32KB) が
                     82:                // 上限だが、サイズ指定が 1MB 単位なので 255MB を上限にする。
                     83:                auto prom = dynamic_cast<PROMDevice *>(GetPROMDevice());
                     84:                if (prom) {
                     85:                        if (ram_size_MB > 255) {
                     86:                                item.Err("(Warning) Maximum RAM size with PROM is 255[MB]; "
                     87:                                        "Clip RAM size to 255[MB].");
                     88:                                ram_size_MB = 255;
                     89:                        }
                     90:                }
                     91: 
1.1.1.3 ! root       92:                // 通常サイクルは1ウェイトらしい?
        !            93:                // バーストウェイトは LUNA-88K の取説からの推論。
        !            94:                normal_wait = busdata::Wait(1 * clock_nsec);
        !            95:                burst_wait  = busdata::Wait(4 * clock_nsec);
1.1       root       96:                break;
1.1.1.2   root       97:         }
1.1       root       98: 
                     99:         case VMType::LUNA88K:
                    100:         {
                    101:                // 64MB までは、実機に合わせて 16MB 単位とする。
                    102:                //
                    103:                // 64MB を超える増設 (or 魔改造) 部分は未確認。
                    104:                if (ram_size_MB <= 64) {
                    105:                        if (ram_size_MB % 16 != 0) {
                    106:                                item.Err("For 64MB or less, must be specified in 16 [MB] unit");
                    107:                                return false;
                    108:                        }
1.1.1.2   root      109:                } else if (ram_size_MB > 512) {
                    110:                        item.Err("Configurable maximum RAM size is 512 [MB]");
1.1       root      111:                        return false;
                    112:                }
                    113: 
                    114:                // PROM 1.20 では 240MB を上限にする。
                    115:                // 0x0f00'0000 (ちょうど 240MB 目) へのアクセスでバスエラーが
                    116:                // 出ることを CMMU のアドレス変換チェックに使っているため。
                    117:                auto prom = dynamic_cast<PROMDevice *>(GetPROMDevice());
                    118:                if (prom && prom->GetROMVer() == 120) {
                    119:                        if (ram_size_MB > 240) {
1.1.1.2   root      120:                                item.Err("(warning) Maximum RAM size with PROM 1.20 is 240[MB];"
                    121:                                        " Clip RAM size to 240[MB].");
                    122:                                ram_size_MB = 240;
1.1       root      123:                        }
                    124:                }
                    125: 
1.1.1.2   root      126:                // 取扱説明書p.21 に、CMMU からのアクセスタイムが
                    127:                // リード(4byte)で 200ns、バーストリード(16byte)で 320ns
                    128:                // ライト(4byte)で 160ns、バーストライト(16byte)で 280ns とある。
                    129:                // 25MHz は 40ns/clock なのでそれぞれ、
                    130:                // リード(4byte)で 5 clock、バーストリード(16byte)で 8 clock
                    131:                // ライト(4byte)で 4 clock、バーストライト(16byte)で 7 clock となる。
                    132:                // これは CMMU 以降のアクセスタイムらしいので、
                    133:                // リード3クロック、ライト2クロック引いたものをウェイトとしてみる?
                    134:                // XXX 要確認。
1.1.1.3 ! root      135:                normal_wait = busdata::Wait(2 * clock_nsec);
        !           136:                burst_wait  = busdata::Wait(5 * clock_nsec);
1.1       root      137:                break;
                    138:         }
                    139: 
                    140:         case VMType::NEWS:
1.1.1.3 ! root      141:                // 知らんけど 1クロックくらい入れておく。
        !           142:                normal_wait = busdata::Wait(1 * clock_nsec);
        !           143:                // NWS-1750 はバースト転送をサポートしていないようだ。
        !           144:                // http://www.ceres.dti.ne.jp/tsutsui/netbsd/port-news68k.html#19991203
1.1.1.2   root      145:                break;
                    146: 
                    147:         case VMType::VIRT68K:
                    148:                // 1MB 単位で指定できる必要もないだろうから 16MB 単位に切り上げる。
                    149:                ram_size_MB = roundup(ram_size_MB, 16);
                    150: 
                    151:                // 最後の 16MB ブロックが I/O 空間なので、
                    152:                // メモリは最大で 4096 - 16 = 4080MB まで積める。
                    153:                if (ram_size_MB > 4080) {
                    154:                        item.Err("Configurable maximum RAM size is 4080 [MB]");
                    155:                        return false;
                    156:                }
                    157: 
                    158:                // ウェイト不要。
1.1.1.3 ! root      159:                normal_wait = busdata::Wait(0);
        !           160:                burst_wait  = busdata::Wait(0);
1.1       root      161:                break;
                    162: 
                    163:         default:
1.1.1.2   root      164:                PANIC("vmtype=%s not configured", gMainApp.GetVMTypeStr().c_str());
1.1       root      165:        }
                    166: 
                    167:        ram_size = ram_size_MB * 1024 * 1024;
1.1.1.2   root      168:        mainram.reset(new(std::nothrow) uint8[ram_size]);
                    169:        if ((bool)mainram == false) {
                    170:                errno = ENOMEM;
                    171:                warn("MainRAM(%u bytes)", ram_size);
                    172:                return false;
                    173:        }
1.1       root      174: 
                    175:        // Human68k モードならここで一度だけメモリをゼロクリアする。
                    176:        // この時は Human68k::Init() が MainRAM にプログラムを転送するため
                    177:        // 電源オン時点で RAM を初期化してはいけない…。うーんこの…。
                    178:        // MainRAM::Init() が Human68k::Init() より先に呼ばれることは
                    179:        // VM_X68030 で指定してある。
                    180:        // 一方、通常モードなら VM リスタート(電源再投入) で前の内容を残さない
                    181:        // ために ResetHard(true) でメモリを (ゼロでなくてもいいので) クリアする
                    182:        // 必要がある。
                    183:        if (gMainApp.human_mode) {
                    184:                memset(&mainram[0], 0, ram_size);
                    185:        }
                    186: 
                    187:        return true;
                    188: }
                    189: 
                    190: // 電源オン/リセット
                    191: void
                    192: MainRAMDevice::ResetHard(bool poweron)
                    193: {
                    194:        if (poweron) {
                    195:                if (gMainApp.human_mode || gMainApp.IsNEWS()) {
                    196:                        // Human モードと NEWS は Init() がメモリに書き込むので
                    197:                        // ここでクリアしない。うーん。
                    198:                } else {
                    199:                        // 通常モードならメモリをクリア
                    200:                        // XXX ノイズを用意するべき
                    201:                        memset(&mainram[0], 0, ram_size);
                    202:                }
                    203:        }
                    204: 
                    205:        // X68030 ではリセットで戻るはず。(LUNA は固定なので関係ない)
                    206:        if (gMainApp.IsX68030()) {
1.1.1.3 ! root      207:                normal_wait = busdata::Wait(0);
1.1       root      208:        }
                    209: }
                    210: 
1.1.1.2   root      211: busdata
1.1.1.3 ! root      212: MainRAMDevice::Read(busaddr addr)
1.1       root      213: {
1.1.1.3 ! root      214:        uint32 paddr = addr.Addr();
1.1.1.2   root      215:        busdata data;
1.1.1.3 ! root      216: 
        !           217:        data  = *(uint32 *)&mainram[paddr & ~3];
        !           218:        data |= normal_wait;
        !           219:        data |= BusData::Size4;
1.1       root      220:        return data;
                    221: }
                    222: 
1.1.1.2   root      223: busdata
1.1.1.3 ! root      224: MainRAMDevice::Write(busaddr addr, uint32 data)
1.1       root      225: {
1.1.1.3 ! root      226:        uint32 paddr = addr.Addr();
        !           227:        uint32 reqsize = addr.GetSize();
        !           228:        uint32 datasize = std::min(4 - (paddr & 3U), reqsize);
        !           229: 
        !           230:        if (datasize == 4) {
        !           231:                *(uint32 *)&mainram[paddr] = data;
        !           232:        } else if (datasize == 1) {
        !           233:                data >>= (reqsize - datasize) * 8;
        !           234:                mainram[HLB(paddr)] = data;
        !           235:        } else {
        !           236:                data >>= (reqsize - datasize) * 8;
        !           237:                for (int i = datasize - 1; i >= 0; i--) {
        !           238:                        mainram[HLB(paddr + i)] = data;
        !           239:                        data >>= 8;
        !           240:                }
        !           241:        }
        !           242: 
        !           243:        busdata r = normal_wait;
        !           244:        r |= BusData::Size4;
        !           245:        return r;
1.1       root      246: }
                    247: 
1.1.1.2   root      248: busdata
1.1.1.3 ! root      249: MainRAMDevice::ReadBurst16(busaddr addr, uint32 *dst)
1.1       root      250: {
1.1.1.3 ! root      251:        uint32 paddr = addr.Addr();
        !           252:        putlog(4, "$%08x BurstRead", paddr);
        !           253:        memcpy(dst, &mainram[paddr], 16);
        !           254:        return burst_wait;
1.1       root      255: }
                    256: 
1.1.1.2   root      257: busdata
1.1.1.3 ! root      258: MainRAMDevice::WriteBurst16(busaddr addr, const uint32 *src)
1.1       root      259: {
1.1.1.3 ! root      260:        uint32 paddr = addr.Addr();
        !           261:        putlog(4, "$%08x BurstWrite", paddr);
        !           262:        memcpy(&mainram[paddr], src, 16);
        !           263:        return burst_wait;
1.1       root      264: }
                    265: 
1.1.1.2   root      266: busdata
1.1.1.3 ! root      267: MainRAMDevice::Peek1(uint32 addr)
1.1       root      268: {
1.1.1.3 ! root      269:        return mainram[HLB(addr)];
1.1       root      270: }
                    271: 
1.1.1.3 ! root      272: bool
        !           273: MainRAMDevice::Poke1(uint32 addr, uint32 data)
1.1       root      274: {
1.1.1.3 ! root      275:        if ((int32)data >= 0) {
        !           276:                mainram[HLB(addr)] = data;
        !           277:        }
        !           278:        return true;
1.1       root      279: }
                    280: 
1.1.1.3 ! root      281: // 領域読み出し。
        !           282: // addr から totallen までが領域内なら転送して true を返す。
        !           283: // 領域外を指すなら何もせず false を返す。
        !           284: bool
        !           285: MainRAMDevice::ReadMem(uint32 addr, void *dst_, uint32 totallen)
1.1       root      286: {
1.1.1.3 ! root      287:        uint8 *dst = (uint8 *)dst_;
        !           288:        uintptr_t u = (uintptr_t)addr;
        !           289:        uint32 len;
        !           290: 
        !           291:        if (__predict_false(addr + totallen > GetSize())) {
        !           292:                return false;
        !           293:        }
        !           294: 
        !           295:        if (__predict_false(((u | (uintptr_t)dst) & 3) != 0)) {
        !           296:                if (((u ^ (uintptr_t)dst) & 3) || totallen < 4) {
        !           297:                        len = totallen;
        !           298:                } else {
        !           299:                        len = 4 - (uint32)(u & 3);
        !           300:                }
        !           301:                totallen -= len;
        !           302:                for (; len > 0; len--) {
        !           303:                        *dst++ = mainram[HLB(addr)];
        !           304:                        addr++;
        !           305:                }
        !           306:        }
        !           307: 
        !           308:        len = totallen / 4;
        !           309:        for (; len > 0; len--) {
        !           310:                *(uint32 *)dst = be32toh(*(uint32 *)&mainram[addr]);
        !           311:                dst += 4;
        !           312:                addr += 4;
        !           313:        }
        !           314: 
        !           315:        len = totallen & 3;
        !           316:        for (; len > 0; len--) {
        !           317:                *dst++ = mainram[HLB(addr)];
        !           318:                addr++;
        !           319:        }
        !           320: 
        !           321:        return true;
1.1       root      322: }
                    323: 
1.1.1.3 ! root      324: // 領域書き込み。
        !           325: // addr から totallen までが領域内なら転送して true を返す。
        !           326: // 領域外を指すなら何もせず false を返す。
1.1.1.2   root      327: bool
1.1.1.3 ! root      328: MainRAMDevice::WriteMem(uint32 addr, const void *src_, uint32 totallen)
1.1       root      329: {
1.1.1.3 ! root      330:        const uint8 *src = (const uint8 *)src_;
        !           331:        uintptr_t u = (uintptr_t)addr;
        !           332:        uint32 len;
        !           333: 
        !           334:        if (__predict_false(addr + totallen > GetSize())) {
        !           335:                return false;
        !           336:        }
        !           337: 
        !           338:        if (__predict_false(((u | (uintptr_t)src) & 3) != 0)) {
        !           339:                if (((u ^ (uintptr_t)src) & 3) || totallen < 4) {
        !           340:                        len = totallen;
        !           341:                } else {
        !           342:                        len = 4 - (uint32)(u & 3);
        !           343:                }
        !           344:                totallen -= len;
        !           345:                for (; len > 0; len--) {
        !           346:                        mainram[HLB(addr)] = *src++;
        !           347:                        addr++;
        !           348:                }
1.1       root      349:        }
1.1.1.3 ! root      350: 
        !           351:        len = totallen / 4;
        !           352:        for (; len > 0; len--) {
        !           353:                *(uint32 *)&mainram[addr] = be32toh(*(const uint32 *)src);
        !           354:                addr += 4;
        !           355:                src += 4;
        !           356:        }
        !           357: 
        !           358:        len = totallen & 3;
        !           359:        for (; len > 0; len--) {
        !           360:                mainram[HLB(addr)] = *src++;
        !           361:                addr++;
        !           362:        }
        !           363: 
1.1.1.2   root      364:        return true;
1.1       root      365: }
                    366: 
1.1.1.3 ! root      367: // アクセスウェイト [clock] を設定。
        !           368: // X68030 でシステムポートから呼ばれるため normal_wait のみ設定する。
1.1       root      369: void
1.1.1.3 ! root      370: MainRAMDevice::SetWait(uint32 wait_clock)
1.1       root      371: {
1.1.1.2   root      372:        uint32 clock_nsec = mpu->GetClock_nsec();
                    373: 
1.1.1.3 ! root      374:        normal_wait = busdata::Wait(wait_clock * clock_nsec);
1.1       root      375: }
                    376: 
1.1.1.2   root      377: // info で指定された実行ファイルをゲストにロードする。
1.1       root      378: bool
1.1.1.2   root      379: MainRAMDevice::LoadExec(LoadInfo *info)
1.1       root      380: {
                    381:        BootLoader loader(this);
                    382: 
1.1.1.2   root      383:        return loader.LoadExec(info);
1.1       root      384: }
                    385: 
1.1.1.2   root      386: // info で指定されたデータファイルをゲストにロードする。
1.1       root      387: bool
1.1.1.2   root      388: MainRAMDevice::LoadData(LoadInfo *info)
1.1       root      389: {
                    390:        BootLoader loader(this);
                    391: 
1.1.1.2   root      392:        return loader.LoadData(info);
1.1       root      393: }

unix.superglobalmegacorp.com

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