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

1.1       root        1: //
                      2: // nono
                      3: // Copyright (C) 2020 nono project
                      4: // Licensed under nono-license.txt
                      5: //
                      6: 
                      7: //
                      8: // メインメモリ
                      9: //
                     10: 
1.1.1.5 ! root       11: // MainRAM はロングワード単位でホストバイトオーダ配置なので、
        !            12: // バイトアクセス、ワードアクセス時は HLB(), HLW() マクロを使用のこと。
        !            13: 
1.1       root       14: #include "mainram.h"
                     15: #include "config.h"
                     16: #include "mainapp.h"
                     17: #include "mpu.h"
                     18: #include "prom.h"
                     19: 
                     20: // コンストラクタ
                     21: MainRAMDevice::MainRAMDevice()
                     22:        : inherited(OBJ_MAINRAM)
                     23: {
1.1.1.5 ! root       24:        clear_on_boot = true;
1.1       root       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.5 ! root      137:                // 電源オン時に RAM に書き込んでいるため、クリアしない。
        !           138:                clear_on_boot = false;
1.1.1.3   root      139:                // 知らんけど 1クロックくらい入れておく。
                    140:                normal_wait = busdata::Wait(1 * clock_nsec);
                    141:                // NWS-1750 はバースト転送をサポートしていないようだ。
                    142:                // http://www.ceres.dti.ne.jp/tsutsui/netbsd/port-news68k.html#19991203
1.1.1.2   root      143:                break;
                    144: 
                    145:         case VMType::VIRT68K:
                    146:                // 1MB 単位で指定できる必要もないだろうから 16MB 単位に切り上げる。
                    147:                ram_size_MB = roundup(ram_size_MB, 16);
                    148: 
                    149:                // 最後の 16MB ブロックが I/O 空間なので、
                    150:                // メモリは最大で 4096 - 16 = 4080MB まで積める。
                    151:                if (ram_size_MB > 4080) {
                    152:                        item.Err("Configurable maximum RAM size is 4080 [MB]");
                    153:                        return false;
                    154:                }
                    155: 
                    156:                // ウェイト不要。
1.1.1.3   root      157:                normal_wait = busdata::Wait(0);
                    158:                burst_wait  = busdata::Wait(0);
1.1       root      159:                break;
                    160: 
                    161:         default:
1.1.1.2   root      162:                PANIC("vmtype=%s not configured", gMainApp.GetVMTypeStr().c_str());
1.1       root      163:        }
                    164: 
1.1.1.5 ! root      165:        ram_size = (size_t)ram_size_MB * 1024 * 1024;
1.1.1.2   root      166:        mainram.reset(new(std::nothrow) uint8[ram_size]);
                    167:        if ((bool)mainram == false) {
                    168:                errno = ENOMEM;
1.1.1.5 ! root      169:                warn("MainRAM(%zu bytes)", ram_size);
1.1.1.2   root      170:                return false;
                    171:        }
1.1       root      172: 
                    173:        // Human68k モードならここで一度だけメモリをゼロクリアする。
                    174:        // この時は Human68k::Init() が MainRAM にプログラムを転送するため
                    175:        // 電源オン時点で RAM を初期化してはいけない…。うーんこの…。
                    176:        // MainRAM::Init() が Human68k::Init() より先に呼ばれることは
                    177:        // VM_X68030 で指定してある。
                    178:        // 一方、通常モードなら VM リスタート(電源再投入) で前の内容を残さない
                    179:        // ために ResetHard(true) でメモリを (ゼロでなくてもいいので) クリアする
                    180:        // 必要がある。
                    181:        if (gMainApp.human_mode) {
                    182:                memset(&mainram[0], 0, ram_size);
1.1.1.5 ! root      183:                clear_on_boot = false;
1.1       root      184:        }
                    185: 
                    186:        return true;
                    187: }
                    188: 
                    189: // 電源オン/リセット
                    190: void
                    191: MainRAMDevice::ResetHard(bool poweron)
                    192: {
                    193:        if (poweron) {
1.1.1.5 ! root      194:                if (clear_on_boot) {
1.1       root      195:                        // XXX ノイズを用意するべき
                    196:                        memset(&mainram[0], 0, ram_size);
                    197:                }
                    198:        }
                    199: 
                    200:        // X68030 ではリセットで戻るはず。(LUNA は固定なので関係ない)
                    201:        if (gMainApp.IsX68030()) {
1.1.1.3   root      202:                normal_wait = busdata::Wait(0);
1.1       root      203:        }
                    204: }
                    205: 
1.1.1.2   root      206: busdata
1.1.1.3   root      207: MainRAMDevice::Read(busaddr addr)
1.1       root      208: {
1.1.1.3   root      209:        uint32 paddr = addr.Addr();
1.1.1.2   root      210:        busdata data;
1.1.1.3   root      211: 
                    212:        data  = *(uint32 *)&mainram[paddr & ~3];
                    213:        data |= normal_wait;
                    214:        data |= BusData::Size4;
1.1       root      215:        return data;
                    216: }
                    217: 
1.1.1.2   root      218: busdata
1.1.1.3   root      219: MainRAMDevice::Write(busaddr addr, uint32 data)
1.1       root      220: {
1.1.1.3   root      221:        uint32 paddr = addr.Addr();
                    222:        uint32 reqsize = addr.GetSize();
                    223:        uint32 datasize = std::min(4 - (paddr & 3U), reqsize);
                    224: 
                    225:        if (datasize == 4) {
                    226:                *(uint32 *)&mainram[paddr] = data;
                    227:        } else if (datasize == 1) {
                    228:                data >>= (reqsize - datasize) * 8;
                    229:                mainram[HLB(paddr)] = data;
                    230:        } else {
                    231:                data >>= (reqsize - datasize) * 8;
                    232:                for (int i = datasize - 1; i >= 0; i--) {
                    233:                        mainram[HLB(paddr + i)] = data;
                    234:                        data >>= 8;
                    235:                }
                    236:        }
                    237: 
                    238:        busdata r = normal_wait;
                    239:        r |= BusData::Size4;
                    240:        return r;
1.1       root      241: }
                    242: 
1.1.1.2   root      243: busdata
1.1.1.3   root      244: MainRAMDevice::ReadBurst16(busaddr addr, uint32 *dst)
1.1       root      245: {
1.1.1.3   root      246:        uint32 paddr = addr.Addr();
                    247:        putlog(4, "$%08x BurstRead", paddr);
                    248:        memcpy(dst, &mainram[paddr], 16);
                    249:        return burst_wait;
1.1       root      250: }
                    251: 
1.1.1.2   root      252: busdata
1.1.1.3   root      253: MainRAMDevice::WriteBurst16(busaddr addr, const uint32 *src)
1.1       root      254: {
1.1.1.3   root      255:        uint32 paddr = addr.Addr();
                    256:        putlog(4, "$%08x BurstWrite", paddr);
                    257:        memcpy(&mainram[paddr], src, 16);
                    258:        return burst_wait;
1.1       root      259: }
                    260: 
1.1.1.2   root      261: busdata
1.1.1.3   root      262: MainRAMDevice::Peek1(uint32 addr)
1.1       root      263: {
1.1.1.3   root      264:        return mainram[HLB(addr)];
1.1       root      265: }
                    266: 
1.1.1.3   root      267: bool
                    268: MainRAMDevice::Poke1(uint32 addr, uint32 data)
1.1       root      269: {
1.1.1.3   root      270:        if ((int32)data >= 0) {
                    271:                mainram[HLB(addr)] = data;
                    272:        }
                    273:        return true;
1.1       root      274: }
                    275: 
1.1.1.3   root      276: // 領域読み出し。
                    277: // addr から totallen までが領域内なら転送して true を返す。
                    278: // 領域外を指すなら何もせず false を返す。
                    279: bool
                    280: MainRAMDevice::ReadMem(uint32 addr, void *dst_, uint32 totallen)
1.1       root      281: {
1.1.1.3   root      282:        uint8 *dst = (uint8 *)dst_;
                    283:        uintptr_t u = (uintptr_t)addr;
                    284:        uint32 len;
                    285: 
                    286:        if (__predict_false(addr + totallen > GetSize())) {
                    287:                return false;
                    288:        }
                    289: 
                    290:        if (__predict_false(((u | (uintptr_t)dst) & 3) != 0)) {
                    291:                if (((u ^ (uintptr_t)dst) & 3) || totallen < 4) {
                    292:                        len = totallen;
                    293:                } else {
                    294:                        len = 4 - (uint32)(u & 3);
                    295:                }
                    296:                totallen -= len;
                    297:                for (; len > 0; len--) {
                    298:                        *dst++ = mainram[HLB(addr)];
                    299:                        addr++;
                    300:                }
                    301:        }
                    302: 
                    303:        len = totallen / 4;
                    304:        for (; len > 0; len--) {
                    305:                *(uint32 *)dst = be32toh(*(uint32 *)&mainram[addr]);
                    306:                dst += 4;
                    307:                addr += 4;
                    308:        }
                    309: 
                    310:        len = totallen & 3;
                    311:        for (; len > 0; len--) {
                    312:                *dst++ = mainram[HLB(addr)];
                    313:                addr++;
                    314:        }
                    315: 
                    316:        return true;
1.1       root      317: }
                    318: 
1.1.1.3   root      319: // 領域書き込み。
                    320: // addr から totallen までが領域内なら転送して true を返す。
                    321: // 領域外を指すなら何もせず false を返す。
1.1.1.2   root      322: bool
1.1.1.3   root      323: MainRAMDevice::WriteMem(uint32 addr, const void *src_, uint32 totallen)
1.1       root      324: {
1.1.1.3   root      325:        const uint8 *src = (const uint8 *)src_;
                    326:        uintptr_t u = (uintptr_t)addr;
                    327:        uint32 len;
                    328: 
                    329:        if (__predict_false(addr + totallen > GetSize())) {
                    330:                return false;
                    331:        }
                    332: 
                    333:        if (__predict_false(((u | (uintptr_t)src) & 3) != 0)) {
                    334:                if (((u ^ (uintptr_t)src) & 3) || totallen < 4) {
                    335:                        len = totallen;
                    336:                } else {
                    337:                        len = 4 - (uint32)(u & 3);
                    338:                }
                    339:                totallen -= len;
                    340:                for (; len > 0; len--) {
                    341:                        mainram[HLB(addr)] = *src++;
                    342:                        addr++;
                    343:                }
1.1       root      344:        }
1.1.1.3   root      345: 
                    346:        len = totallen / 4;
                    347:        for (; len > 0; len--) {
                    348:                *(uint32 *)&mainram[addr] = be32toh(*(const uint32 *)src);
                    349:                addr += 4;
                    350:                src += 4;
                    351:        }
                    352: 
                    353:        len = totallen & 3;
                    354:        for (; len > 0; len--) {
                    355:                mainram[HLB(addr)] = *src++;
                    356:                addr++;
                    357:        }
                    358: 
1.1.1.2   root      359:        return true;
1.1       root      360: }
                    361: 
1.1.1.3   root      362: // アクセスウェイト [clock] を設定。
                    363: // X68030 でシステムポートから呼ばれるため normal_wait のみ設定する。
1.1       root      364: void
1.1.1.3   root      365: MainRAMDevice::SetWait(uint32 wait_clock)
1.1       root      366: {
1.1.1.2   root      367:        uint32 clock_nsec = mpu->GetClock_nsec();
                    368: 
1.1.1.3   root      369:        normal_wait = busdata::Wait(wait_clock * clock_nsec);
1.1       root      370: }

unix.superglobalmegacorp.com

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