Annotation of nono/m680x0/m68030bus.cpp, revision 1.1.1.7

1.1       root        1: //
                      2: // nono
1.1.1.3   root        3: // Copyright (C) 2020 nono project
                      4: // Licensed under nono-license.txt
1.1       root        5: //
1.1.1.3   root        6: 
1.1.1.4   root        7: #include "mpu680x0.h"
1.1.1.6   root        8: #include "mainbus.h"
                      9: #include "m68030cache.h"
1.1       root       10: 
1.1.1.5   root       11: // 現在の FC での通常アクセス (MPU 内部から使用する)
                     12: // ミスアライン可。
                     13: // バスエラーが起きると例外 M68K::EXCEP_BUSERR をスローする。
1.1.1.6   root       14: //     uint32 fetch_{2,4}()
                     15: //     uint32 read_{1,2,4}(laddr)        .. vm/mpu680x0.h にある
                     16: //     void   write_{1,2,4}(laddr, data) .. vm/mpu680x0.h にある
1.1       root       17: 
1.1.1.5   root       18: // reg.pc からワードをフェッチし reg.pc を進める。
                     19: uint32
1.1.1.7 ! root       20: MPU68030Device::fetch_2()
1.1       root       21: {
1.1.1.6   root       22:        busaddr addr = busaddr(reg.pc) | fc_inst | BusAddr::Size2;
1.1.1.5   root       23: 
1.1.1.6   root       24:        // まず可能ならキャッシュから探す。
                     25:        m68030Cache *cache = icache.get();
                     26:        if (__predict_true(cache->enable)) {
                     27:                uint32 tag = (addr.Get() >> 4) & 0xfffffff0;
                     28:                uint32 idx = (reg.pc & 0x000000f0) >> 4;
                     29:                uint32 sel = (reg.pc & 0x0000000c) >> 2;
                     30:                m68030CacheLine *l = &cache->line[idx];
                     31: 
                     32:                if (__predict_true(l->tag == tag && l->valid[sel])) {
                     33:                        cache->stat_fasthit++;
                     34:                        uint32 data = l->data[sel];
                     35:                        if ((reg.pc & 2) == 0) {
                     36:                                data >>= 16;
                     37:                        } else {
                     38:                                data &= 0xffff;
                     39:                        }
                     40:                        reg.pc += 2;
                     41:                        return data;
                     42:                }
                     43:        }
                     44: 
                     45:        busdata bd;
                     46:        if (__predict_true(cache->enable)) {
                     47:                bd = read_cache(cache, addr);
1.1       root       48:        } else {
1.1.1.6   root       49:                bd = read_nocache(addr);
                     50:        }
                     51:        if (__predict_false(bd.IsBusErr())) {
1.1.1.7 ! root       52:                bus.size = addr.GetSize();
1.1.1.6   root       53:                throw M68K::EXCEP_BUSERR;
1.1       root       54:        }
1.1.1.5   root       55:        reg.pc += 2;
1.1.1.6   root       56:        return bd.Data();
1.1       root       57: }
                     58: 
1.1.1.5   root       59: // reg.pc からロングワード(ミスアライン可)をフェッチし reg.pc を進める。
                     60: uint32
1.1.1.7 ! root       61: MPU68030Device::fetch_4()
1.1       root       62: {
1.1.1.6   root       63:        busaddr addr = busaddr(reg.pc) | fc_inst | BusAddr::Size4;
1.1.1.5   root       64: 
1.1.1.6   root       65:        // まず可能ならキャッシュから探す。
                     66:        m68030Cache *cache = icache.get();
                     67:        if (__predict_true(cache->enable)) {
                     68:                uint32 tag = (addr.Get() >> 4) & 0xfffffff0;
                     69:                uint32 idx = (reg.pc & 0x000000f0) >> 4;
                     70:                uint32 sel = (reg.pc & 0x0000000c) >> 2;
                     71:                m68030CacheLine *l = &cache->line[idx];
                     72: 
                     73:                if (__predict_true(l->tag == tag && l->valid[sel])) {
                     74:                        uint32 data;
                     75:                        if ((reg.pc & 2) == 0) {
                     76:                                cache->stat_fasthit++;
                     77:                                data = l->data[sel];
                     78:                        } else {
                     79:                                // 次のエントリにまたがる場合。
                     80:                                if (sel < 3 && l->valid[sel + 1]) {
                     81:                                        cache->stat_fasthit += 2;
                     82:                                        data  = l->data[sel] << 16;
                     83:                                        data |= l->data[sel + 1] >> 16;
                     84:                                } else {
                     85:                                        // 片方でキャッシュミスした。
                     86:                                        // この場合は fast* はカウントしない。
                     87:                                        goto fetch;
                     88:                                }
                     89:                        }
                     90:                        reg.pc += 4;
                     91:                        return data;
1.1.1.5   root       92:                }
1.1       root       93:        }
                     94: 
1.1.1.6   root       95:  fetch:
                     96:        busdata bd;
                     97:        if (__predict_true(cache->enable)) {
                     98:                bd = read_cache(cache, addr);
                     99:        } else {
                    100:                bd = read_nocache(addr);
                    101:        }
                    102:        if (__predict_false(bd.IsBusErr())) {
1.1.1.7 ! root      103:                bus.size = addr.GetSize();
1.1.1.6   root      104:                throw M68K::EXCEP_BUSERR;
                    105:        }
                    106:        reg.pc += 4;
                    107:        return bd.Data();
1.1       root      108: }
                    109: 
1.1.1.6   root      110: // read_1,2,4() の共通部分。ミスアライン可。
                    111: // バスエラーが起きると例外 M68K::EXCEP_BUSERR をスローする。
1.1.1.5   root      112: uint32
1.1.1.7 ! root      113: MPU68030Device::read_data(busaddr addr)
1.1       root      114: {
1.1.1.6   root      115:        m68030Cache *cache = dcache.get();
                    116:        busdata data;
                    117:        if (__predict_true(cache->enable)) {
                    118:                data = read_cache(cache, addr);
                    119:        } else {
                    120:                data = read_nocache(addr);
                    121:        }
                    122:        if (__predict_false(data.IsBusErr())) {
1.1.1.7 ! root      123:                bus.size = addr.GetSize();
1.1.1.6   root      124:                throw M68K::EXCEP_BUSERR;
                    125:        }
                    126:        return data.Data();
1.1       root      127: }
                    128: 
1.1.1.6   root      129: // write_1,2,4() の共通部分。ミスアライン可。
1.1.1.5   root      130: // バスエラーが起きると例外 M68K::EXCEP_BUSERR をスローする。
1.1.1.6   root      131: void
1.1.1.7 ! root      132: MPU68030Device::write_data(busaddr addr, uint32 data)
1.1       root      133: {
1.1.1.6   root      134:        busdata r = write_bus(addr, data);
                    135:        if (__predict_false(r.IsBusErr())) {
1.1.1.7 ! root      136:                bus.size = addr.GetSize();
1.1.1.6   root      137:                throw M68K::EXCEP_BUSERR;
1.1.1.5   root      138:        }
1.1       root      139: }
                    140: 
1.1.1.6   root      141: // キャッシュ無効時の読み込み。ミスアライン可。
                    142: // バスエラーも busdata を返す。
                    143: busdata
1.1.1.7 ! root      144: MPU68030Device::read_nocache(busaddr addr)
1.1.1.6   root      145: {
                    146:        // デバイスは、addr の下位ビットによらず、自身のデバイスのポートサイズ分
                    147:        // のデータと、その応答サイズ(自分のポートサイズ) を Size フィールドに
                    148:        // セットして返してくる。
                    149:        //
                    150:        // MPU(68030) は、A1-A0、残りバイト数、デバイスの応答サイズの情報から
                    151:        // 受け取ったデータバスのうち適切なところを切り出して使う。
                    152: 
                    153:        uint32 data = 0;
                    154:        for (;;) {
                    155:                bus.laddr = addr;
                    156:                bus.paddr = addr;
                    157:                if (__predict_false(TranslateRead() == false)) {
                    158:                        return BusData::BusErr;
                    159:                }
                    160:                busdata bd = read_phys();
                    161:                if (__predict_false(bd.IsBusErr())) {
                    162:                        return bd;
                    163:                }
1.1.1.5   root      164: 
1.1.1.6   root      165:                uint32 reqsize = addr.GetSize();
                    166:                // デバイスのポートサイズ(応答サイズ)
                    167:                uint32 portsize = bd.GetSize();
                    168:                // 今回のアドレスオフセット
                    169:                uint32 offset = addr.Addr() & (portsize - 1);
                    170:                uint32 datasize = portsize - offset;
                    171:                uint32 tmp = bd.Data();
                    172:                // 下詰めされたデータに対するマスク
                    173:                uint32 mask = 0xffffffffU >> ((4 - datasize) * 8);
                    174:                // 今回必要なところ
                    175:                tmp &= mask;
                    176:                if (datasize == reqsize) {
                    177:                        data |= tmp;
                    178:                        break;
                    179:                } else if (datasize > reqsize) {
                    180:                        tmp >>= (datasize - reqsize) * 8;
                    181:                        data |= tmp;
                    182:                        break;
1.1.1.5   root      183:                } else {
1.1.1.6   root      184:                        tmp <<= (reqsize - datasize) * 8;
                    185:                        data |= tmp;
1.1.1.5   root      186:                }
                    187: 
1.1.1.6   root      188:                addr += datasize;
                    189:                reqsize -= datasize;
                    190:                addr.ChangeSize(reqsize);
                    191:        }
1.1.1.5   root      192:        return data;
1.1       root      193: }
                    194: 
1.1.1.6   root      195: // offset [0, 4) から size [1, 4] バイトのマスクを作成する。
                    196: // マスクは +0, +1, +2, +3 バイト目がビット 3, 2, 1, 0 に対応している。
                    197: static inline uint32
                    198: OPERMASK(uint32 offset, uint32 size)
                    199: {
                    200:        return ((1U << size) - 1) << (4 - offset - size);
                    201: }
                    202: 
                    203: // キャッシュ有効時の読み込み。ミスアライン可。
                    204: // バスエラーも busdata を返す。
                    205: busdata
1.1.1.7 ! root      206: MPU68030Device::read_cache(m68030Cache *cache, busaddr addr)
1.1.1.6   root      207: {
                    208:        putlog(2, "read_cache $%u.%08x.%c",
                    209:                addr.GetFC(), addr.Addr(), "0BW3L"[addr.GetSize()]);
                    210: 
                    211:        uint32 data = 0;
                    212:        bus.ci = false;
                    213:        for (;;) {
                    214:                uint32 entry_data = 0;
                    215: 
                    216:                // addr から今回対象とするロングワードエントリに対するマスクを作成。
                    217:                uint32 reqoffset = addr.Addr() & 3;
                    218:                uint32 reqsize = addr.GetSize();
                    219:                uint32 opersize = std::min(reqsize, 4 - reqoffset);
                    220: 
                    221:                // まず可能ならキャッシュから探す。
                    222:                uint32 tag = (addr.Get() >> 4) & 0xfffffff0;
                    223:                uint32 idx = (addr.Addr() & 0x000000f0) >> 4;
                    224:                uint32 sel = (addr.Addr() & 0x0000000c) >> 2;
                    225:                m68030CacheLine *l = &cache->line[idx];
                    226:                if (__predict_true(l->tag == tag && l->valid[sel])) {
                    227:                        cache->stat_hit++;
                    228:                        entry_data = l->data[sel];
                    229:                        putlog(2, " entry_data=$%08x (match)", entry_data);
                    230:                } else {
                    231:                        cache->stat_miss++;
                    232: 
                    233:                        // キャッシュになければバスアクセス。
                    234:                        bus.laddr = addr;
                    235:                        bus.paddr = addr;
                    236:                        if (__predict_false(TranslateRead() == false)) {
                    237:                                putlog(2, " TranslateRead BusErr");
                    238:                                return BusData::BusErr;
                    239:                        }
                    240:                        putlog(2, " paddr=$%08x.%c",
                    241:                                bus.paddr.Addr(), "0BW3L"[bus.paddr.GetSize()]);
                    242: 
                    243:                        busdata bd;
                    244:                        if (__predict_true(cache->freeze == false && bus.ci == false)) {
                    245:                                // キャッシュ可。
                    246:                                if (l->tag != tag) {
                    247:                                        // タグが違う場合、出来ればバーストリードを使う。
                    248:                                        // XXX: タグが同じでもエントリがすべて無効ならバーストリード
                    249:                                        //      するのだが、パフォーマンス落ちるので保留。
                    250:                                        // TODO: 要求オペランドがラインをまたぐ場合の1エントリ目は
                    251:                                        //       バースト転送しない。
                    252:                                        if (__predict_true(cache->burst_enable) &&
                    253:                                                __predict_true(read_phys_burst(&l->data[0])))
                    254:                                        {
                    255:                                                l->tag = tag;
                    256:                                                l->valid_all = -1;
                    257:                                                entry_data = l->data[sel];
                    258:                                                putlog(2, " entry_data=$%08x (burst)", entry_data);
                    259:                                        } else {
                    260:                                                // シングル充填を4回。
                    261:                                                uint32 opermask = OPERMASK(reqoffset, opersize);
                    262:                                                bd = read_line(l, tag, opermask);
                    263:                                                if (__predict_false(bd.IsBusErr())) {
                    264:                                                        return bd;
                    265:                                                }
                    266:                                                entry_data = bd.Data();
                    267:                                                putlog(2, " entry_data=$%08x (line)", entry_data);
                    268:                                        }
                    269:                                } else {
                    270:                                        // このエントリだけ充填。
                    271:                                        bd = read_phys();
                    272:                                        if (__predict_false(bd.IsBusErr())) {
                    273:                                                return bd;
                    274:                                        }
                    275:                                        if (__predict_false(bus.ci)) {
                    276:                                                goto nofill;
                    277:                                        }
                    278:                                        if (__predict_false(bd.GetSize() != 4)) {
                    279:                                                uint32 opermask = OPERMASK(reqoffset, opersize);
                    280:                                                bd = read_single(bd, 0xf, opermask);
                    281:                                                if (__predict_false(bd.IsBusErr())) {
                    282:                                                        return bd;
                    283:                                                }
                    284:                                        }
                    285:                                        l->valid[sel] = 1;
                    286:                                        l->data[sel] = bd.Data();
                    287:                                        entry_data = bd.Data();
                    288:                                }
                    289:                        } else {
                    290:                                // キャッシュに充填しないので、要求サイズだけ読み出す。
                    291:                                bd = read_phys();
                    292:                                if (__predict_false(bd.IsBusErr())) {
                    293:                                        return bd;
                    294:                                }
                    295:  nofill:
                    296:                                if (__predict_false(bd.GetSize() != 4)) {
                    297:                                        uint32 opermask = OPERMASK(reqoffset, opersize);
                    298:                                        bd = read_single(bd, opermask, opermask);
                    299:                                        if (__predict_false(bd.IsBusErr())) {
                    300:                                                return bd;
                    301:                                        }
                    302:                                }
                    303:                                entry_data = bd.Data();
                    304:                        }
                    305:                }
1.1.1.5   root      306: 
1.1.1.6   root      307:                data <<= opersize * 8;
                    308:                // このエントリから必要な部分を抜き出す。
                    309:                uint32 mask = 0xffffffffU >> ((4 - opersize) * 8);
                    310:                if (reqsize == opersize) {
                    311:                        // 要求サイズがこのエントリをはみ出していない。
                    312:                        entry_data >>= (4 - reqoffset - opersize) * 8;
                    313:                        data |= entry_data & mask;
                    314:                        putlog(2, " data=$%0*x (done)", opersize * 2, data);
                    315:                        break;
1.1.1.5   root      316:                } else {
1.1.1.6   root      317:                        data |= entry_data & mask;
                    318:                        putlog(2, " data=$%0*x", opersize * 2, data);
1.1.1.5   root      319:                }
1.1.1.6   root      320:                addr += opersize;
                    321:                addr.ChangeSize(reqsize - opersize);
1.1.1.5   root      322:        }
                    323: 
                    324:        return data;
1.1       root      325: }
                    326: 
1.1.1.6   root      327: // シングル充填によるライン充填。
                    328: // 要求オペランドが2エントリ目にかかっていても、バスエラーを起こさないようだ。
                    329: busdata
1.1.1.7 ! root      330: MPU68030Device::read_line(m68030CacheLine *l, uint32 tag, uint32 opermask)
1.1.1.6   root      331: {
                    332:        uint32 sel = (bus.paddr.Addr() & 0x0c) >> 2;
                    333: 
                    334:        // 1エントリ目。
                    335:        busdata bd = read_phys();
                    336:        if (__predict_false(bd.IsBusErr())) {
                    337:                // 初手は必ず要求オペランドなのでバスエラーは発報。
                    338:                return bd;
1.1.1.5   root      339:        }
1.1.1.6   root      340:        if (__predict_false(bd.GetSize() != 4)) {
                    341:                // このエントリの残りを埋める。
                    342:                bd = read_single(bd, 0xf, opermask);
                    343:                if (__predict_false(bd.IsBusErr())) {
                    344:                        return bd;
1.1.1.5   root      345:                }
                    346:        }
1.1.1.6   root      347:        if (__predict_false(bus.ci)) {
                    348:                // CI ならキャッシュを更新せず、現状のデータを返す。
                    349:                // 要求オペランド外でのバスエラーもここに来る。
                    350:                return bd.Data();
                    351:        }
                    352:        // そうでなければ、ここでタグとエントリを更新。
                    353:        l->tag = tag;
                    354:        l->valid_all = 0;
                    355:        l->valid[sel] = 1;
                    356:        l->data[sel] = bd.Data();
                    357: 
                    358:        // 2エントリ目以降は充填してもしなくても1エントリ目のこれが戻り値。
                    359:        uint32 data = bd.Data();
                    360: 
                    361:        // 2エントリ目以降。
                    362:        // 要求オペランドが2エントリ目にまたがっていても、
                    363:        // 2エントリ目以降はバスエラーを起こさないらしい。
                    364:        for (int i = 1; i < 4; i++) {
                    365:                // アドレスを更新。
                    366:                if (++sel >= 4) {
                    367:                        sel = 0;
                    368:                }
                    369:                bus.paddr.ChangeAddr((bus.paddr.Addr() & ~0xf) | (sel << 2));
                    370:                bus.paddr.ChangeSize(4);
1.1       root      371: 
1.1.1.6   root      372:                bd = read_phys();
                    373:                if (__predict_false(bd.IsBusErr())) {
                    374:                        break;
                    375:                }
                    376:                if (__predict_false(bd.GetSize() != 4)) {
                    377:                        // このエントリの残りを埋める。
                    378:                        bd = read_single(bd, 0xf, 0);
                    379:                        if (__predict_false(bd.IsBusErr())) {
                    380:                                // バスエラーならエントリを無効にして充填をアボート。
                    381:                                // エントリはまだ有効にしていないので何もしなくていい。
                    382:                                break;
                    383:                        }
                    384:                }
                    385:                if (__predict_false(bus.ci)) {
                    386:                        // CI は1ライン中で変化しないと思うが、
                    387:                        // 要求オペランド外でのバスエラーもここに来る。
                    388:                        break;
1.1.1.5   root      389:                }
1.1.1.6   root      390: 
                    391:                l->valid[sel] = 1;
                    392:                l->data[sel] = bd.Data();
1.1.1.5   root      393:        }
1.1.1.6   root      394: 
                    395:        return data;
1.1       root      396: }
                    397: 
1.1.1.6   root      398: // シングル充填の残りの読み出し。
                    399: // まず bus.paddr を1回読んでみて、ロングワードポートならそのまま使える
                    400: // (し、大抵はこのケースなので早期に抜けたい) のでここには来ない。
                    401: // ロングワードでない時だけここへ来て残りを埋める、という分担になっている。
                    402: //
                    403: // readmask は読み込みを行うバイト (キャッシュ充填なら %1111)。
                    404: // opermask はバスエラーを起こすバイト。
                    405: // readmask、opermask はともに下位の 4 ビットで、
                    406: // ビット 3, 2, 1, 0 がそれぞれ +0, +1, +2, +3 バイト目を示す。
                    407: //
                    408: // bd = read_phys();
                    409: // if (BusErr) ...;
                    410: // if (bd.GetSize() != 4) {
                    411: //   bd = read_single(bd, readmask, opermask);
                    412: //   :
                    413: // }
                    414: // if (bus.ci) ...;
                    415: // のように呼ぶ。
                    416: //
                    417: // 応答は、
                    418: // a) 成功すれば、readmask で示した読み出しバイトをロングワードで返す。
                    419: //    下詰めではなくロングワード境界からの所定のバイト位置。
                    420: // b) opermask で示したバイトでバスエラーが起きれば、その場で処理を中断して
                    421: //    BusErr を返す (上位に発報するため)。
                    422: // c) opermask で示したバイト以外でバスエラーが起きれば、その場で処理を中断
                    423: //    し bus.ci を立てて、現状のデータを返す (エントリを更新しないため)。
                    424: // d) バスアクセスで CI が立てば、読み込んだデータは使うがエントリは更新しない
                    425: //    ので、これは c) と同じ。
                    426: busdata
1.1.1.7 ! root      427: MPU68030Device::read_single(busdata bd, uint32 readmask, uint32 opermask)
1.1.1.6   root      428: {
                    429:        uint32 data = 0;
                    430:        uint32 portsize;
                    431: 
                    432:        // この時点で bd は一回目の読み込み後で、
                    433:        // バスエラーは起きておらず、ロングワードポートでなかった。
                    434:        portsize = bd.GetSize();
                    435: 
                    436:        uint32 offset = bus.paddr.Addr() & 3;
                    437:        for (;;) {
                    438:                // bd.Data をエントリの所定の位置に移動。
                    439:                // set には今回読めたところのビットを立てていく。
                    440:                uint32 set;
                    441:                if (portsize == 2) {
                    442:                        uint32 off2 = offset & 2;
                    443:                        data |= bd.Data() << ((2 - off2) * 8);
                    444:                        set = 0x3 << (2 - off2);
                    445:                        // 次の読み込みにむけて更新。
                    446:                        offset = 2 - off2;
                    447:                } else {
                    448:                        data |= bd.Data() << ((3 - offset) * 8);
                    449:                        set = 0x1 << (3 - offset);
                    450:                        // 次の読み込みにむけて更新。
                    451:                        offset = (offset + 1) & 3;
                    452:                }
1.1.1.5   root      453: 
1.1.1.6   root      454:                // readmask を全部下ろせたら終了。
                    455:                readmask &= ~set;
                    456:                if (readmask == 0) {
                    457:                        break;
                    458:                }
1.1.1.5   root      459: 
1.1.1.6   root      460:                // 次の読み込み。
                    461:                // 同一エントリ内なので paddr の更新だけでいい。
                    462:                bus.paddr.ChangeAddr((bus.paddr.Addr() & ~3U) | offset);
                    463:                bus.paddr.ChangeSize(__builtin_popcount(readmask));
                    464: 
                    465:                bd = read_phys();
                    466:                portsize = bd.GetSize();
                    467:                if (__predict_false(bd.IsBusErr())) {
                    468:                        if ((set & opermask) != 0) {
                    469:                                // ターゲットオペランドと重なっていれば即バスエラー。
                    470:                                return BusData::BusErr;
                    471:                        } else {
                    472:                                // オペランド外の充填中なら CI と同じパスになる。
                    473:                                bus.ci = true;
                    474:                                break;
                    475:                        }
                    476:                }
                    477:        }
1.1.1.5   root      478: 
1.1.1.6   root      479:        return data;
1.1       root      480: }
                    481: 
1.1.1.6   root      482: // キャッシュ/バスへの書き込み。ミスアライン可。
                    483: // バスエラーも busdata を返す。
                    484: busdata
1.1.1.7 ! root      485: MPU68030Device::write_bus(busaddr addr, uint32 data)
1.1.1.6   root      486: {
                    487:        m68030Cache *cache = dcache.get();
                    488: 
                    489:        putlog(2, "write_bus %u.%08x sz=%u data=$%0*x",
                    490:                addr.GetFC(), addr.Addr(), addr.GetSize(), addr.GetSize() * 2, data);
                    491:        for (;;) {
                    492:                uint32 nextdata;
                    493:                uint32 reqoffset = addr.Addr() & 3;
                    494:                uint32 reqsize = addr.GetSize();
                    495: 
                    496:                // ロングワード境界をはみ出す場合は持ち越し分を覚えておく。
                    497:                int nextsize = reqoffset + reqsize - 4;
                    498:                if (nextsize > 0) {
                    499:                        // 後ろにはみ出すケース。
                    500:                        nextdata = data & ((1U << (nextsize * 8)) - 1);
                    501:                        data >>= nextsize * 8;
                    502:                        reqsize -= nextsize;
                    503:                        addr.ChangeSize(reqsize);
                    504:                } else {
                    505:                        nextsize = 0;
                    506:                }
1.1.1.5   root      507: 
1.1.1.6   root      508:                // まず外部バスを駆動して CI を得る。
                    509:                // バスエラーなら記録だけしておく。キャッシュへは書き込むため。
                    510:                busdata bd = BusData::BusErr;
                    511:                bus.ci = false;
                    512:                bus.laddr = addr;
                    513:                bus.paddr = addr;
                    514:                if (__predict_true(TranslateWrite())) {
                    515:                        uint32 outdata = data;
                    516:                        for (;;) {
                    517:                                bd = write_phys(outdata);
                    518:                                if (__predict_false(bd.IsBusErr())) {
                    519:                                        putlog(2, " write_phys -> BusErr");
                    520:                                        break;
                    521:                                }
                    522:                                uint32 breqsize = bus.paddr.GetSize();
                    523:                                putlog(2, " write_phys $%08x data=$%0*x",
                    524:                                        bus.paddr.Addr(), breqsize * 2, outdata);
                    525:                                uint32 portsize = bd.GetSize();
                    526:                                uint32 offset = bus.paddr.Addr() & (portsize - 1);
                    527:                                uint32 datasize = portsize - offset;
                    528:                                if (datasize >= breqsize) {
                    529:                                        break;
                    530:                                }
                    531:                                // 同一ロングワード内なので bus.paddr の更新だけでいい。
                    532:                                bus.paddr += datasize;
                    533:                                breqsize -= datasize;
                    534:                                bus.paddr.ChangeSize(breqsize);
                    535:                                // データは下詰めで、不要な上位ビットはクリアする仕様。
                    536:                                outdata &= (1U << (breqsize * 8)) - 1;
                    537:                        }
                    538:                }
1.1.1.5   root      539: 
1.1.1.6   root      540:                bool cache_writable = (cache->enable && bus.ci == false);
                    541:                if (cache_writable) {
                    542:                        uint32 tag = (addr.Get() >> 4) & 0xfffffff0;
                    543:                        uint32 idx = (addr.Addr() & 0x000000f0) >> 4;
                    544:                        uint32 sel = (addr.Addr() & 0x0000000c) >> 2;
                    545:                        auto *l = &cache->line[idx];
                    546: 
                    547:                        // Hit Frz WA  Tag      LA
                    548:                        //      1       0       -       -       - : UpdateEntry
                    549:                        //      1       1       -       -       - : UpdateEntry (ex1, ex2のb8-b9
                    550:                        //      0       1       -       -       - : Nop
                    551:                        //      0       0       0       -       - : Nop
                    552:                        //      0       0       1       1       1 : (ex3
                    553:                        //      0       0       1       1       0 : Nop (ex2のb6-b7
                    554:                        //      0       0       1       0       1 : (ex4
                    555:                        //      0       0       1       0       0 : (ex5
                    556:                        bool tag_match = (l->tag == tag);
                    557:                        bool cache_hit = (tag_match && l->valid[sel]);
                    558:                        if (cache_hit) {
                    559:                                // エントリの更新。
                    560:                                // reqsize はロングワード境界を超えないよう調整済み。
                    561:                                // data は下詰め(上はクリア)なので、所定の位置まで左シフト。
                    562:                                // 整列ロングワードもここに来ることに注意。
                    563:                                // Fig.6-4 の ex1, ex2のb8-b9
                    564:                                int lshift = (4 - reqoffset - reqsize) * 8;
                    565:                                uint32 mask = (0xffffffffU >> ((4 - reqsize) * 8)) << lshift;
                    566:                                l->data[sel] = (data << lshift) | (l->data[sel] & ~mask);
                    567:                        } else if (cache->freeze == false && cache->wa) {
                    568:                                bool long_aligned = (reqoffset == 0 && reqsize == 4);
                    569:                                // Fig.6-4
                    570:                                if (tag_match) {
                    571:                                        if (long_aligned) {
                    572:                                                // ex3
                    573:                                                l->valid[sel] = 1;
                    574:                                                l->data[sel] = data;
                    575:                                        } else {
                    576:                                                // ex2 の b6-b7
                    577:                                                // nop
                    578:                                        }
                    579:                                } else {
                    580:                                        if (long_aligned) {
                    581:                                                // ex4
                    582:                                                l->tag = tag;
                    583:                                                l->valid_all = 0;
                    584:                                                l->valid[sel] = 1;
                    585:                                                l->data[sel] = data;
                    586:                                        } else {
                    587:                                                // ex5
                    588:                                                l->valid[sel] = 0;
                    589:                                        }
                    590:                                }
                    591:                        }
                    592:                }
1.1       root      593: 
1.1.1.6   root      594:                // バスアクセスでバスエラーが出たらキャッシュ更新後に発報。
                    595:                if (__predict_false(bd.IsBusErr())) {
                    596:                        return bd;
                    597:                }
1.1.1.5   root      598: 
1.1.1.6   root      599:                // ロングワード境界をまたいだ余りがあればもう一回。
                    600:                if (nextsize == 0) {
                    601:                        break;
                    602:                }
                    603:                putlog(2, " nextsize=%u", nextsize);
                    604:                addr += addr.GetSize();
                    605:                addr.ChangeSize(nextsize);
                    606:                data = nextdata;
                    607:        }
1.1.1.5   root      608: 
1.1.1.6   root      609:        return 0;
1.1       root      610: }
                    611: 
1.1.1.6   root      612: // mainbus の bus.paddr から指定サイズで1回読み込む。
                    613: // ウェイトはこちらで加算して、バスエラーも含めた bd を返す。
                    614: busdata
                    615: MPU680x0Device::read_phys()
1.1       root      616: {
1.1.1.6   root      617:        busaddr paddr = bus.paddr;
                    618:        busdata bd = mainbus->Read(paddr);
                    619:        buswait += bd.GetWait();
                    620:        return bd;
1.1       root      621: }
                    622: 
1.1.1.6   root      623: // mainbus の bus.paddr に指定サイズで1回書き込む。
                    624: // ウェイトはこちらで加算して、バスエラーも含めた bd を返す。
                    625: busdata
                    626: MPU680x0Device::write_phys(uint32 data)
1.1       root      627: {
1.1.1.6   root      628:        busaddr paddr = bus.paddr;
                    629:        busdata bd = mainbus->Write(paddr, data);
                    630:        buswait += bd.GetWait();
                    631:        return bd;
1.1       root      632: }
                    633: 
1.1.1.6   root      634: // バースト転送。
                    635: // bus.paddr の下位4ビットは無視する。
                    636: // addr がバースト転送可能なら dst に 16 バイト転送して true を返す。
                    637: // addr がバースト転送不可なら dst は触らず false を返す。
                    638: // VM (バス) がバースト転送対応している場合のみ呼ぶこと。
                    639: bool
                    640: MPU680x0Device::read_phys_burst(uint32 *dst)
                    641: {
                    642:        busaddr paddr = bus.paddr;
                    643:        paddr &= 0xfffffff0U;
                    644:        busdata bd = mainbus->ReadBurst16(paddr, dst);
                    645:        buswait += bd.GetWait();
1.1.1.5   root      646: 
1.1.1.6   root      647:        // BusErr ビットをバースト転送不可フラグとして使っている。
                    648:        return !bd.IsBusErr();
1.1       root      649: }
                    650: 
1.1.1.7 ! root      651: // 物理メモリからのロングワード読み込み。
        !           652: // 現在の bus に影響を与えず指定のアドレスを読み出す。MMU 専用。
        !           653: busdata
        !           654: MPU680x0Device::read_phys_4(uint32 addr)
        !           655: {
        !           656:        m68kbus backup;
        !           657:        busdata bd;
        !           658: 
        !           659:        // バス情報を一旦退避
        !           660:        backup = bus;
        !           661: 
        !           662:        // 物理バスアクセス
        !           663:        bus.laddr = busaddr(addr) | BusAddr::SRead | BusAddr::Size4;
        !           664:        bus.paddr = bus.laddr;
        !           665:        bd = read_phys();
        !           666:        if (__predict_false(bd.IsBusErr())) {
        !           667:                bus.size = 4;
        !           668:                return bd;
        !           669:        }
        !           670: 
        !           671:        // バス情報を復元
        !           672:        bus = backup;
        !           673:        return bd;
        !           674: }
        !           675: 
        !           676: // 物理メモリへのロングワード書き込み。
        !           677: // 現在の bus に影響を与えず指定のアドレスに書き出す。MMU 専用。
        !           678: busdata
        !           679: MPU680x0Device::write_phys_4(uint32 addr, uint32 data)
        !           680: {
        !           681:        m68kbus backup;
        !           682:        busdata bd;
        !           683: 
        !           684:        // バス情報を一旦退避
        !           685:        backup = bus;
        !           686: 
        !           687:        // 物理バスアクセス
        !           688:        bus.laddr = busaddr(addr) | BusAddr::SWrite | BusAddr::Size4;
        !           689:        bus.paddr = bus.laddr;
        !           690:        bd = write_phys(data);
        !           691:        if (__predict_false(bd.IsBusErr())) {
        !           692:                bus.size = 4;
        !           693:                return bd;
        !           694:        }
        !           695: 
        !           696:        // バス情報を復元
        !           697:        bus = backup;
        !           698:        return bd;
        !           699: }
        !           700: 
        !           701: // CACR レジスタ書き込み。
        !           702: void
        !           703: MPU68030Device::SetCACR(uint32 newval)
        !           704: {
        !           705:        newval &= M68030::CACR_MASK;
        !           706:        uint32 oldval = reg.cacr;
        !           707:        uint32 chgval = oldval ^ newval;
        !           708: 
        !           709:        // EI (命令キャッシュ有効)
        !           710:        if ((chgval & M68030::CACR_EI) != 0) {
        !           711:                if ((newval & M68030::CACR_EI) != 0) {
        !           712:                        // 命令キャッシュ有効
        !           713:                        icache->enable = true;
        !           714:                        icache->hist.Clear();
        !           715:                        putlog(1, "I-Cache enabled");
        !           716:                } else {
        !           717:                        // 命令キャッシュ無効
        !           718:                        icache->enable = false;
        !           719:                        putlog(1, "I-Cache disabled");
        !           720:                        // 命令キャッシュが有効だった期間 nocache は使われずに
        !           721:                        // 積算され続けているが、キャッシュ無効になるとこれを加算
        !           722:                        // しようとするのでここでリセット。
        !           723:                        cycle_nocache = 0;
        !           724:                }
        !           725: 
        !           726:                // 親クラス(自分) にもコピーを持っておく。core.cpp 参照。
        !           727:                icache_enable = icache->enable;
        !           728:        }
        !           729: 
        !           730:        // FI (命令キャッシュ凍結)
        !           731:        if ((chgval & M68030::CACR_FI) != 0) {
        !           732:                putlog(0, "CACR:FI Not Implemented");
        !           733:                icache->freeze = (newval & M68030::CACR_FI);
        !           734:        }
        !           735: 
        !           736:        // CEI (命令キャッシュの指定エントリをクリア)
        !           737:        if ((chgval & M68030::CACR_CEI) != 0) {
        !           738:                // CAAR の b7-2 で示されるロングワードを無効にする。
        !           739:                uint32 idx = (reg.caar & 0x000000f0) >> 4;
        !           740:                uint32 sel = (reg.caar & 0x0000000c) >> 2;
        !           741:                auto& l = icache->line[idx];
        !           742:                l.valid[sel] = 0;
        !           743: 
        !           744:                newval &= ~M68030::CACR_CEI;
        !           745:        }
        !           746: 
        !           747:        // CI (命令キャッシュクリア)
        !           748:        if ((chgval & M68030::CACR_CI) != 0) {
        !           749:                for (auto& l : icache->line) {
        !           750:                        l.valid_all = 0;
        !           751:                }
        !           752: 
        !           753:                newval &= ~M68030::CACR_CI;
        !           754:        }
        !           755: 
        !           756:        // IBE (命令バースト有効)
        !           757:        if ((chgval & M68030::CACR_IBE) != 0) {
        !           758:                icache->burst_enable = (newval & M68030::CACR_IBE) && has_burst_access;
        !           759:        }
        !           760: 
        !           761:        // ED (データキャッシュ有効)
        !           762:        if ((chgval & M68030::CACR_ED) != 0) {
        !           763:                if ((newval & M68030::CACR_ED) != 0) {
        !           764:                        // データキャッシュ有効。
        !           765:                        dcache->enable = true;
        !           766:                        dcache->hist.Clear();
        !           767:                        putlog(1, "D-Cache enabled");
        !           768:                } else {
        !           769:                        // データキャッシュ無効。
        !           770:                        dcache->enable = false;
        !           771:                        putlog(1, "D-Cache disabled");
        !           772:                }
        !           773:        }
        !           774: 
        !           775:        // FD (データキャッシュ凍結)
        !           776:        if ((chgval & M68030::CACR_FD) != 0) {
        !           777:                dcache->freeze = (newval & M68030::CACR_FD);
        !           778:                putlog(1, "CACR:FD -> %u", dcache->freeze);
        !           779:        }
        !           780: 
        !           781:        // CED (データキャッシュの指定エントリをクリア)
        !           782:        if ((chgval & M68030::CACR_CED) != 0) {
        !           783:                // CAAR の b7-2 で示されるロングワードを無効にする。
        !           784:                uint32 idx = (reg.caar & 0x000000f0) >> 4;
        !           785:                uint32 sel = (reg.caar & 0x0000000c) >> 2;
        !           786:                auto& l = dcache->line[idx];
        !           787:                l.valid[sel] = 0;
        !           788: 
        !           789:                newval &= ~M68030::CACR_CED;
        !           790:        }
        !           791: 
        !           792:        // CD (データキャッシュクリア)
        !           793:        if ((chgval & M68030::CACR_CD) != 0) {
        !           794:                for (auto& l : dcache->line) {
        !           795:                        l.valid_all = 0;
        !           796:                }
        !           797: 
        !           798:                newval &= ~M68030::CACR_CD;
        !           799:        }
        !           800: 
        !           801:        // DBE (データバースト有効)
        !           802:        if ((chgval & M68030::CACR_DBE) != 0) {
        !           803:                dcache->burst_enable = (newval & M68030::CACR_DBE) && has_burst_access;
        !           804:        }
        !           805: 
        !           806:        // WA (ライトアロケート)
        !           807:        if ((chgval & M68030::CACR_WA) != 0) {
        !           808:                dcache->wa = (newval & M68030::CACR_WA);
        !           809:        }
        !           810: 
        !           811:        // とりあえずレジスタイメージも保存。
        !           812:        reg.cacr = newval;
        !           813: }
        !           814: 
        !           815: // リセット例外の CPU 固有部分。
        !           816: void
        !           817: MPU68030Device::ResetCache()
        !           818: {
        !           819:        SetCACR(M68030::CACR_CD | M68030::CACR_CI);
        !           820:        icache->hist.Clear();
        !           821:        dcache->hist.Clear();
        !           822: }
        !           823: 
1.1.1.6   root      824: // キャッシュの統計情報を計算。
1.1       root      825: void
1.1.1.6   root      826: m68030Cache::CalcStat()
1.1       root      827: {
1.1.1.6   root      828:        m68030CacheStat s;
1.1.1.5   root      829: 
1.1.1.6   root      830:        memset(&s, 0, sizeof(s));
1.1       root      831: 
1.1.1.6   root      832:        // fasthit はファストパスでヒットした回数。
                    833:        uint32 total_read = stat_fasthit + stat_hit + stat_miss;
                    834:        if (__predict_true(total_read != 0)) {
                    835:                s.hit = (float)(stat_fasthit + stat_hit) * 100 / total_read;
                    836:                stat_fasthit = 0;
                    837:                stat_hit = 0;
                    838:                stat_miss = 0;
                    839:        }
1.1.1.5   root      840: 
1.1.1.6   root      841:        // 前回から今回までの間に disable になったのなら有効な値がある。
                    842:        if (__predict_true(enable || total_read != 0)) {
                    843:                // ここはロックする。
                    844:                std::unique_lock<std::mutex> lock(hist_mtx);
                    845:                hist.EnqueueForce(s);
                    846:        }
1.1       root      847: }

unix.superglobalmegacorp.com

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