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

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

unix.superglobalmegacorp.com

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