|
|
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();
1.1.1.8 ! root 715: cycle_table = cycle_table_030cc;
1.1.1.7 root 716: putlog(1, "I-Cache enabled");
717: } else {
718: // 命令キャッシュ無効
719: icache->enable = false;
1.1.1.8 ! root 720: cycle_table = cycle_table_030ncc;
1.1.1.7 root 721: putlog(1, "I-Cache disabled");
722: }
723: }
724:
725: // FI (命令キャッシュ凍結)
726: if ((chgval & M68030::CACR_FI) != 0) {
727: putlog(0, "CACR:FI Not Implemented");
728: icache->freeze = (newval & M68030::CACR_FI);
729: }
730:
731: // CEI (命令キャッシュの指定エントリをクリア)
732: if ((chgval & M68030::CACR_CEI) != 0) {
733: // CAAR の b7-2 で示されるロングワードを無効にする。
734: uint32 idx = (reg.caar & 0x000000f0) >> 4;
735: uint32 sel = (reg.caar & 0x0000000c) >> 2;
736: auto& l = icache->line[idx];
737: l.valid[sel] = 0;
738:
739: newval &= ~M68030::CACR_CEI;
740: }
741:
742: // CI (命令キャッシュクリア)
743: if ((chgval & M68030::CACR_CI) != 0) {
744: for (auto& l : icache->line) {
745: l.valid_all = 0;
746: }
747:
748: newval &= ~M68030::CACR_CI;
749: }
750:
751: // IBE (命令バースト有効)
752: if ((chgval & M68030::CACR_IBE) != 0) {
753: icache->burst_enable = (newval & M68030::CACR_IBE) && has_burst_access;
754: }
755:
756: // ED (データキャッシュ有効)
757: if ((chgval & M68030::CACR_ED) != 0) {
758: if ((newval & M68030::CACR_ED) != 0) {
759: // データキャッシュ有効。
760: dcache->enable = true;
761: dcache->hist.Clear();
762: putlog(1, "D-Cache enabled");
763: } else {
764: // データキャッシュ無効。
765: dcache->enable = false;
766: putlog(1, "D-Cache disabled");
767: }
768: }
769:
770: // FD (データキャッシュ凍結)
771: if ((chgval & M68030::CACR_FD) != 0) {
772: dcache->freeze = (newval & M68030::CACR_FD);
773: putlog(1, "CACR:FD -> %u", dcache->freeze);
774: }
775:
776: // CED (データキャッシュの指定エントリをクリア)
777: if ((chgval & M68030::CACR_CED) != 0) {
778: // CAAR の b7-2 で示されるロングワードを無効にする。
779: uint32 idx = (reg.caar & 0x000000f0) >> 4;
780: uint32 sel = (reg.caar & 0x0000000c) >> 2;
781: auto& l = dcache->line[idx];
782: l.valid[sel] = 0;
783:
784: newval &= ~M68030::CACR_CED;
785: }
786:
787: // CD (データキャッシュクリア)
788: if ((chgval & M68030::CACR_CD) != 0) {
789: for (auto& l : dcache->line) {
790: l.valid_all = 0;
791: }
792:
793: newval &= ~M68030::CACR_CD;
794: }
795:
796: // DBE (データバースト有効)
797: if ((chgval & M68030::CACR_DBE) != 0) {
798: dcache->burst_enable = (newval & M68030::CACR_DBE) && has_burst_access;
799: }
800:
801: // WA (ライトアロケート)
802: if ((chgval & M68030::CACR_WA) != 0) {
803: dcache->wa = (newval & M68030::CACR_WA);
804: }
805:
806: // とりあえずレジスタイメージも保存。
807: reg.cacr = newval;
808: }
809:
810: // リセット例外の CPU 固有部分。
811: void
812: MPU68030Device::ResetCache()
813: {
814: SetCACR(M68030::CACR_CD | M68030::CACR_CI);
815: icache->hist.Clear();
816: dcache->hist.Clear();
817: }
818:
1.1.1.6 root 819: // キャッシュの統計情報を計算。
1.1 root 820: void
1.1.1.6 root 821: m68030Cache::CalcStat()
1.1 root 822: {
1.1.1.6 root 823: m68030CacheStat s;
1.1.1.5 root 824:
1.1.1.6 root 825: memset(&s, 0, sizeof(s));
1.1 root 826:
1.1.1.6 root 827: // fasthit はファストパスでヒットした回数。
828: uint32 total_read = stat_fasthit + stat_hit + stat_miss;
829: if (__predict_true(total_read != 0)) {
830: s.hit = (float)(stat_fasthit + stat_hit) * 100 / total_read;
831: stat_fasthit = 0;
832: stat_hit = 0;
833: stat_miss = 0;
834: }
1.1.1.5 root 835:
1.1.1.6 root 836: // 前回から今回までの間に disable になったのなら有効な値がある。
837: if (__predict_true(enable || total_read != 0)) {
838: // ここはロックする。
839: std::unique_lock<std::mutex> lock(hist_mtx);
840: hist.EnqueueForce(s);
841: }
1.1 root 842: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.