|
|
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: //
6:
1.1.1.8 ! root 7: #include "mpu680x0.h"
1.1 root 8: #include "m68030mmu.h"
1.1.1.8 ! root 9: #include "mainbus.h"
1.1 root 10:
11: #define TIA (0)
12: #define TIB (1)
13: #define TIC (2)
14: #define TID (3)
15: #define FCL (4) // 便宜上ね
16: #define MAX_LV (5)
17:
18: // ディスクリプタタイプ
19: #define GET_DT(x) (x & 0x03)
20: #define DT_INVALID (0)
21: #define DT_PAGE (1)
22: #define DT_VALID4 (2)
23: #define DT_VALID8 (3)
24:
25: // ディスクリプタ
26: #define MMU_DESC_S (0x00000100)
27: #define MMU_DESC_CI (0x00000040)
1.1.1.4 root 28: #define MMU_DESC_M (0x00000010)
29: #define MMU_DESC_U (0x00000008)
1.1 root 30: #define MMU_DESC_WP (0x00000004)
31: #define MMU_DESC_DT (0x00000003)
32:
33: // エントリの状態
34: enum ATCtype {
35: INVALID,
36: NORMAL,
37: EARLY,
38: INDIRECT,
39: };
40:
41: //
42: // デバッグ表示
43: //
44:
45: // デバッグ表示のため値の表示に必要な桁数を返す
46: #define NIBBLE(x) ( (x) == 0 ? 1 : ((x) + 3) / 4 )
47:
1.1.1.6 root 48: // MMU デバッグモードなら ATC エントリ a を表示
1.1.1.8 ! root 49: #define FILL_PRINT(fc, a) cpu->putlogf(3, [&] { return (a)->fill_print(fc); })
1.1 root 50:
1.1.1.6 root 51: // インデント付き string_format
52: static std::string indent_format(int indent, const char *fmt, ...)
53: __printflike(2, 3);
54: static std::string
55: indent_format(int indent, const char *fmt, ...)
1.1 root 56: {
57: va_list ap;
1.1.1.6 root 58: char *buf;
1.1 root 59:
60: va_start(ap, fmt);
1.1.1.6 root 61: vasprintf(&buf, fmt, ap);
1.1 root 62: va_end(ap);
63:
1.1.1.6 root 64: std::string rv(indent, ' ');
65: rv += buf;
66: free(buf);
1.1 root 67:
1.1.1.6 root 68: return rv;
69: }
1.1 root 70:
1.1.1.6 root 71: #define MMULOG(lv, indent, arg...) \
1.1.1.8 ! root 72: gMPU->putlogf(lv, [&] { return indent_format(indent, arg); })
1.1 root 73:
74: // テーブルサーチ操作クラス
1.1.1.3 root 75: class m68030MMU final
1.1 root 76: {
77: public:
1.1.1.8 ! root 78: m68030MMU(MPU680x0Device *);
! 79: ~m68030MMU();
1.1 root 80:
81: // サーチを実行
1.1.1.8 ! root 82: void search(int level);
1.1 root 83:
84: // ATC にエントリを作成
85: void make_atc(m68030ATCLine *);
86:
87: // ATC にエントリを作成 (デバッガアクセス用)
88: uint64 make_atc_debugger();
89:
90: private:
91: // リミットチェック
92: bool limitcheck() const;
93:
94: // ディスクリプタを取得
95: bool fetch_desc(uint32, int);
96:
97: // MMU による物理メモリ読み込み
98: uint64 phys_read_32(uint32 addr);
99:
100: // MMU による物理メモリ書き込み
101: uint64 phys_write_32(uint32 addr, uint32 data);
102:
103: // ディスクリプタを表示用に (デバッグ用)
104: std::string sprintf_desc();
105:
106: // ディスクリプタタイプ文字列 (デバッグ用)
107: const char *dtname(uint32 dt);
108:
109: public:
110: ATCtype m_type; // 状態
111: int m_s; // S ビット
112: int m_wp; // WP ビット
113: int m_m; // ページディスクリプタの M が立っているか
114: int m_l; // サーチ中にリミットを越えた
115: bool m_berr; // テーブルサーチ中にバスエラー
116: bool m_ptest; // PTEST[RW] 命令中なら真
117: bool m_debugger; // デバッガからのアクセスなら true にする
118: int x; // 段数 TIA〜TID, FCL
1.1.1.8 ! root 119: uint32 m_lastaddr; // 最後にアクセスしたディスクリプタアドレス(PTEST)
! 120: private:
1.1 root 121: int m_lv[MAX_LV];
122: uint32 m_laddr;
123: int m_fc;
124: uint32 m_desc1; // ディスクリプタ
125: uint32 m_desc2; // ロングディスクリプタの後半部
126: int m_descsize; // ディスクリプタサイズ (4 or 8)
127: int m_lastsize; // 前段のディスクリプタサイズ
128:
129: // デバッグ用文字列
130: static const char * const m_lvname[MAX_LV];
131:
1.1.1.8 ! root 132: MPU680x0Device *cpu;
1.1 root 133: };
134:
135: // 現在の TC:E、TT:E の状態に応じてアドレス変換の有無を切り替える。
136: // mmu_enable ならアドレス変換ありのバスアクセスを使う。see m68030bus.cpp
137: void
1.1.1.8 ! root 138: MPU680x0Device::mmu_enable_changed()
1.1 root 139: {
140: bool enable;
141:
142: // TC、TT0、TT1 のいずれかが有効ならアドレス変換あり
143: enable = (mmu_tc.e || mmu_tt[0].e || mmu_tt[1].e);
144:
145: // 変化した時だけ
146: if (mmu_enable && !enable) {
147: // 無効にする
148: mmu_enable = false;
1.1.1.8 ! root 149: putlog(1, "MMU Translation Disabled");
1.1 root 150: } else if (!mmu_enable && enable) {
151: // 有効にする
152: mmu_enable = true;
1.1.1.8 ! root 153: putlog(1, "MMU Translation Enabled");
1.1 root 154: }
155: }
156:
157:
158: //
159: // レジスタクラス
160: //
161:
1.1.1.8 ! root 162: bool
! 163: MPU680x0Device::SetSRP(uint32 h, uint32 l)
1.1 root 164: {
1.1.1.8 ! root 165: if ((h & m68030RP::DT_MASK) == 0) {
! 166: return false;
! 167: }
1.1 root 168: reg.srp.h = h & m68030RP::H_MASK;
169: reg.srp.l = l & m68030RP::L_MASK;
1.1.1.8 ! root 170: return true;
1.1 root 171: }
172:
1.1.1.8 ! root 173: bool
! 174: MPU680x0Device::SetCRP(uint32 h, uint32 l)
1.1 root 175: {
1.1.1.8 ! root 176: if ((h & m68030RP::DT_MASK) == 0) {
! 177: return false;
! 178: }
1.1 root 179: reg.crp.h = h & m68030RP::H_MASK;
180: reg.crp.l = l & m68030RP::L_MASK;
1.1.1.8 ! root 181: return true;
1.1 root 182: }
183:
184: void
1.1.1.8 ! root 185: MPU680x0Device::SetTT(int n, uint32 data)
1.1 root 186: {
187: uint32 lbase;
188: uint32 lmask;
189: uint32 sbase;
190: uint32 smask;
191:
192: // マスクしてレジスタイメージにセット
193: reg.tt[n] = data & m68030TT::MASK;
194:
195: // data を分解してメンバにセット。
196: //
197: // 3 2 1 0
198: // 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
199: // +---------------+---------------+-+-+-+-+-+-+-+-+-+-----+-+-----+
200: // |LogicalAddrBase|LogicalAddrMask|E| |C|R|M| | FCB | | FCM |
201: // +---------------+---------------+-+-+-+-+-+-+-+-+-+-----+-+-----+
202:
203: mmu_tt[n].e = (data & m68030TT::E);
204: mmu_tt[n].ci = (data & m68030TT::CI);
205:
206: // 下位ロングワード
207: // ・lbase は比較先アドレスで、ff000000の位置。
208: // ・lmask はアドレスマスク。%1 が無視を表しているので NOT しておく。
209: //
210: // target AAAAAAAA xxxxxxxx xxxxxxxx xxxxxxxx : Aは論理アドレス
211: // ^ : xは不問
212: // lbase BBBBBBBB 00000000 00000000 00000000 : Bは論理アドレスベース
213: // &
214: // lmask MMMMMMMM 00000000 00000000 00000000 : Mは論理アドレスマスク
215: //
216: lbase = (data & m68030TT::LBASE_MASK);
217: lmask = (~data & m68030TT::LMASK_MASK) << 8;
218:
219: // 上位ロングワード
220: // ・E ビットは位置はどこでもいいので TT:E ビットの
221: // 位置をそのまま使用する。target 側のこの位置は必ずビットが落ちている
222: // ため base 側にビットを立てておくと必ず不一致になることを利用して、
223: // E ビットの評価も一度に行う。
224: // ・RW ビットは SSW の RW と比較するので、SSW_RW のビット位置を使う
1.1.1.8 ! root 225: // (0x00000040 の位置)。TT:RW も SSW_RW も Read が %1。
1.1 root 226: // ・RWM が %1 なら R/W は無視、RWM が %0 なら R/W の一致も検査するので
227: // RWM が %0 の時は RW のマスクビットを立てておく。
228: // ・FCMask は %1 が無視を表しているので NOT しておく。
229: //
230: // target 00000000 00000000 00000000 0R000FFF : R はアクセス R/~W
231: // ^ : F はアクセス FC
232: // base 00000000 00000000 E0000000 0R000FFF : R は期待する R/~W
233: // & : F は期待する FC
234: // : E は ~TT:E
235: // mask 00000000 00000000 10000000 0M000CCC : M は R/~W マスク
236: // : C は FC マスク
1.1.1.8 ! root 237: sbase = ~data & m68030TT::E;
! 238: sbase |= (data & m68030TT::RW) >> 3;
! 239: sbase |= (data & m68030TT::FCBASE_MASK) >> 4;
1.1 root 240: smask = m68030TT::E;
241: if ((data & m68030TT::RWM) == 0) {
1.1.1.8 ! root 242: smask |= M68K::SSW_RW;
1.1 root 243: }
244: smask |= ~data & m68030TT::FCMASK_MASK;
245:
246: mmu_tt[n].base = lbase | (((uint64)sbase) << 32);
247: mmu_tt[n].mask = lmask | (((uint64)smask) << 32);
248:
249: // 論理アドレスとEnableビットだけの早見表を作成。
250: // TT0 が一致するなら bit0 をセット、TT1 が一致するなら bit1 をセット
251: // しておく。
252: for (int i = 0; i < countof(mmu_tt_quick); i++) {
253: uint32 laddr = ((uint32)i) << 24;
254: if (mmu_tt[n].e && ((laddr ^ lbase) & lmask) == 0) {
255: mmu_tt_quick[i] |= (1 << n);
256: } else {
257: mmu_tt_quick[i] &= ~(1 << n);
258: }
259: }
260:
261: mmu_enable_changed();
262: }
263:
1.1.1.5 root 264: // アクセスがこの TT とマッチするか調べる。
1.1 root 265: // ssw_laddr は上位32ビットが cpu->bus.ssw、下位32ビットが論理アドレス
266: // (下24ビットは呼び出し側でマスクしなくてよい)。
1.1.1.5 root 267: // この TT が有効でアドレスがマッチすれば true を返す。
268: // (TT:E は演算に織り込んである、このすぐ上の SetTT() のコメント参照)
1.1 root 269: bool
1.1.1.8 ! root 270: m68030TT::Match(uint64 ssw_laddr) const
1.1 root 271: {
272: bool rv = (((ssw_laddr ^ base) & mask) == 0);
273: return rv;
274: }
275:
276: // 成功すれば true、MMU 構成例外が起きる場合は false を返す。
277: // 呼び出し側で例外を起こすこと。
278: bool
1.1.1.8 ! root 279: MPU680x0Device::SetTC(uint32 data)
1.1 root 280: {
281: // マスクしてレジスタイメージにセット
282: reg.tc = data & m68030TC::MASK;
283:
284: // data を分解してメンバにセット
285: mmu_tc.Set(data);
286:
287: // 有効にする場合は一貫性を確認
288: if (mmu_tc.e) {
289: if (mmu_tc.Check() == false) {
290: // エラーなら E をクリアして MMU 構成例外。
291: // (例外処理自体は呼び出し側で行う)
292: mmu_tc.e = 0;
293: mmu_enable_changed();
294: return false;
295: }
296: }
297:
298: // マスクをあらかじめ用意しておく
299: mmu_tc.MakeMask();
300:
301: // TC:E が変更されていればスイッチ更新
302: mmu_enable_changed();
303: return true;
304:
305: }
306:
307: // TC レジスタへの書き込み値を m68030TC クラスにセットする。
308: void
309: m68030TC::Set(uint32 data)
310: {
311: e = data & TC_E;
312: sre = data & TC_SRE;
313: fcl = data & TC_FCL;
314: tid = (data) & 0x0f;
315: tic = (data >>= 4) & 0x0f;
316: tib = (data >>= 4) & 0x0f;
317: tia = (data >>= 4) & 0x0f;
318: is = (data >>= 4) & 0x0f;
319: ps = (data >>= 4) & 0x0f;
320: }
321:
322: // 現在の値が MMU 構成例外になるなら false を返す。
323: bool
324: m68030TC::Check() const
325: {
326: if (ps < 8)
327: return false;
328: if (tia == 0)
329: return false;
330: if (tib == 0 && (tic > 0 || tid > 0))
331: return false;
332: if (tic == 0 && tid > 0)
333: return false;
334: if (ps + is + tia + tib + tic + tid != 32)
335: return false;
336:
337: return true;
338: }
339:
340: // 論理マスク、ページマスクを作成。(テーブルサーチで参照される)
341: void
342: m68030TC::MakeMask()
343: {
344: // lmask (論理マスク) は TIA〜TID 部分のマスク。
345: // pgmask (ページマスク) は PS 部分のマスク。
346: //
347: // 例えば IS=$8, TIA=$3, TIB=$4, TIC=$4, TID=$0, PS=$d
348: // (X68030 IPL 内の MMU 判定のケース) なら
349: //
350: // 3 2 1 0
351: // 10987654 32109876 54321098 76543210
352: // +--------+--------+--------+--------+
353: // |IIIIIIII AAABBBBC CCCPPPPP PPPPPPPP|
354: // +--------+--------+--------+--------+
355: // lmask = 00000000 11111111 11100000 00000000
356: // pgmask = 00000000 00000000 00011111 11111111
357: lmask = (1 << (tia + tib + tic + tid)) - 1;
358: lmask <<= ps;
359: pgmask = (1 << ps) - 1;
360:
361: // アドレスを (IS,) TIA 〜 TID に分解。
362: //
363: // TIA=$C, TIB=$A, (TIC = TID = 0), PS=$A の場合以下のようにする。
364: // 使ってない TIC, TID については tix[TIC] == 0 で判断する。
365: //
366: // A B PS
367: // +----------------+--------------+--------------+
368: // $00A01A00 | 0000 0000 1010 | 0000 0001 10 | xx xxxx xxxx |
369: // +----------------+--------------+--------------+
370: // shift[TIA]=20 shift[TIB]=10
371: // mask[TIA]=0xfff mask[TIB]=0x3ff
372: int sh = ps;
373: for (int i = TID; i >= TIA; i--) {
374: if (tix[i] > 0) {
375: shift[i] = sh;
376: mask[i] = (1 << tix[i]) - 1;
377: sh += tix[i];
378: }
379: }
380: }
381:
382: void
1.1.1.8 ! root 383: MPU680x0Device::SetMMUSR(uint16 data)
1.1 root 384: {
385: reg.mmusr = data & m68030MMUSR::MASK;
386: }
387:
388:
389: //
390: // ATC テーブル
391: //
392:
393: // コンストラクタ
394: m68030ATCTable::m68030ATCTable()
395: {
396: #if !defined(ATC_SINGLE)
397: for (int i = 0; i < countof(line); i++) {
398: line[i].Invalidate();
399: }
400: head = &line[0];
401: #else
402: for (int i = 0; i < countof(line); i++) {
403: line[i].Invalidate();
404: insert_tail(&line[i]);
405: }
406: #endif
407: }
408:
1.1.1.8 ! root 409: // デストラクタ
! 410: m68030ATCTable::~m68030ATCTable()
! 411: {
! 412: }
! 413:
1.1 root 414: #if !defined(ATC_SINGLE)
415: // a のエントリを先頭にする。
416: m68030ATCLine *
417: m68030ATCTable::MoveHead(m68030ATCLine *a)
418: {
419: // head を向け直す
420: head = a;
421:
422: // 更新
423: head->age = counter++;
424:
425: // そのエントリを返す
426: return head;
427: }
428: #endif
429:
430:
431: //
432: // ATC
433: //
434:
435: // コンストラクタ
1.1.1.8 ! root 436: m68030ATC::m68030ATC(MPU680x0Device *cpu_)
! 437: {
! 438: cpu = cpu_;
! 439: }
! 440:
! 441: // デストラクタ
! 442: m68030ATC::~m68030ATC()
1.1 root 443: {
444: }
445:
446: #if defined(ATC_SINGLE)
447: // item をリストの先頭に挿入。
448: void
449: m68030ATCTable::insert_head(m68030ATCLine *item)
450: {
451: item->prev = NULL;
452: item->next = head;
453: if (head) {
454: head->prev = item;
455: }
456: head = item;
457: }
458:
459: // item をリストの先頭から2番目に挿入。
460: void
461: m68030ATCTable::insert_second(m68030ATCLine *item)
462: {
463: item->prev = head;
464: if (head) {
465: item->next = head->next;
466: if (head->next) {
467: head->next->prev = item;
468: }
469: head->next = item;
470: } else {
471: item->next = NULL;
472: }
473: }
474:
475: // item をリストの末尾に追加。
476: void
477: m68030ATCTable::insert_tail(m68030ATCLine *item)
478: {
479: item->next = NULL;
480: if (head == NULL) {
481: item->prev = NULL;
482: head = item;
483: } else {
484: m68030ATCLine *a = head;
485: while (a->next)
486: a = a->next;
487: a->next = item;
488: item->prev = a;
489: }
490: }
491:
492: // item をリストから外す
493: void
494: m68030ATCTable::remove(m68030ATCLine *item)
495: {
496: if (item->prev)
497: item->prev->next = item->next;
498: if (item->next)
499: item->next->prev = item->prev;
500: if (item == head)
501: head = item->next;
502: }
503:
504: // item をリストの先頭に移す。
505: // fill_fetch() から呼ばれるもので、リストは空でなく、item は先頭から
506: // 3番目以内ではない、という前提で高速化。
507: void
508: m68030ATCTable::move_head(m68030ATCLine *item)
509: {
510: // 先頭でない前提の remove
511: item->prev->next = item->next;
512: if (item->next)
513: item->next->prev = item->prev;
514:
515: // 先頭がある前提の insert_head
516: item->prev = NULL;
517: item->next = head;
518: head->prev = item;
519: head = item;
520: }
521:
522: // item を先頭から2番目に移す。
523: // fill_{read,write} から呼ばれるもので、リストは空でなく、item は先頭から
524: // 3番目以内ではない、という前提で高速化。
525: void
526: m68030ATCTable::move_second(m68030ATCLine *item)
527: {
528: // 先頭でない前提の remove
529: item->prev->next = item->next;
530: if (item->next)
531: item->next->prev = item->prev;
532:
533: // 先頭2つがある前提の insert_second
534: item->prev = head;
535: item->next = head->next;
536: head->next->prev = item;
537: head->next = item;
538: }
539: #endif // ATC_SINGLE
540:
541: // fill_{fetch,read,write}() が各アクセス用の ATC サーチ。
542: // 論理アドレス fc:addr が ATC にあればそのエントリを返す。
543: // なければ ATC を更新してそのエントリを返す。
544: // fill_peek() はデバッグ用なので一切状態を更新せず結果だけ返す。
545:
546: const m68030ATCLine&
547: m68030ATC::fill_fetch()
548: {
549: uint32 laddr = cpu->bus.laddr & cpu->mmu_tc.lmask;
550: uint fc = cpu->bus.GetFC();
551: m68030ATCTable *table;
552: m68030ATCLine *a;
553: int i;
554:
555: #if !defined(ATC_SINGLE)
556: table = &tables[fc];
557: // キャッシュとマッチすればそれを返す
558: a = table->head;
559: if (a->GetTag() == laddr) {
560: FILL_PRINT(fc, a);
561: table->hit_head++;
562: return *a;
563: }
564: for (i = 0; i < countof(table->line); i++) {
565: a = &table->line[i];
566: if (a->GetTag() == laddr) {
567: // ヒットしたので先頭に移動。fetch は常に入れ替え
568: a = table->MoveHead(a);
569:
570: FILL_PRINT(fc, a);
571: table->hit[i]++;
572: return *a;
573: }
574: }
575:
576: // 見付からなかったので、古いエントリを1つ更新。
577: a = table->MoveHead(table->Lookup());
578: table->hit[m68030ATCTable::LINES]++;
579: // タグはこっちで初期化
580: a->tag = laddr;
581: #else
582: table = &tables[0];
583: // キャッシュとマッチすればそれを返す
584: a = table->head;
585: for (i = 0; a; a = a->next, i++) {
586: if (a->GetTag() == laddr && a->fc == fc) {
587: // ヒットしたので先頭に移動。
588: if (i > 2) {
589: table->move_head(a);
590: }
591:
592: FILL_PRINT(fc, a);
593: table->hit[i]++;
594: return *a;
595: }
596: }
597:
598: // 見付からなかったので、古いエントリを1つ更新。
599: a = table->lookup();
600: table->remove(a);
601: table->insert_head(a);
602: table->hit[m68030ATCTable::LINES]++;
603: // タグはこっちで初期化
604: a->tag = laddr;
605: a->fc = fc;
606: #endif
607:
608: // テーブルサーチして結果を ATC に入れる
609: m68030MMU mmu(cpu);
1.1.1.8 ! root 610: mmu.search(7);
1.1 root 611: mmu.make_atc(a);
612:
613: FILL_PRINT(fc, a);
614: return *a;
615: }
616:
617: const m68030ATCLine&
618: m68030ATC::fill_read()
619: {
620: uint32 laddr = cpu->bus.laddr & cpu->mmu_tc.lmask;
621: uint fc = cpu->bus.GetFC();
622: m68030ATCTable *table;
623: m68030ATCLine *a;
624: int i;
625:
626: #if !defined(ATC_SINGLE)
627: table = &tables[fc];
628: // キャッシュとマッチすればそれを返す
629: a = table->head;
630: if (a->GetTag() == laddr) {
631: FILL_PRINT(fc, a);
632: table->hit_head++;
633: return *a;
634: }
635: for (i = 0; i < countof(table->line); i++) {
636: a = &table->line[i];
637: if (a->GetTag() == laddr) {
638: // ヒットしたので先頭に移動。
639: a = table->MoveHead(a);
640:
641: FILL_PRINT(fc, a);
642: table->hit[i]++;
643: return *a;
644: }
645: }
646:
647: // 見付からなかったので、古いエントリを1つ更新
648: a = table->MoveHead(table->Lookup());
649: table->hit[m68030ATCTable::LINES]++;
650: // タグはこっちで初期化
651: a->tag = laddr;
652: #else
653: table = &tables[0];
654: // キャッシュとマッチすればそれを返す
655: a = table->head;
656: for (i = 0; a; a = a->next, i++) {
657: if ((a->GetTag() == laddr) && (a->fc == fc)) {
658: // ヒットしたので先頭から2番目に移動
659: if (i > 2) {
660: table->move_second(a);
661: }
662:
663: FILL_PRINT(fc, a);
664: table->hit[i]++;
665: return *a;
666: }
667: }
668:
669: // 見付からなかったので、古いエントリを1つ更新
670: a = table->lookup();
671: table->remove(a);
672: table->insert_head(a);
673: table->hit[m68030ATCTable::LINES]++;
674: // タグはこっちで初期化
675: a->tag = laddr;
676: a->fc = fc;
677: #endif
678:
679: // テーブルサーチして結果を ATC に入れる
680: m68030MMU mmu(cpu);
1.1.1.8 ! root 681: mmu.search(7);
1.1 root 682: mmu.make_atc(a);
683:
684: FILL_PRINT(fc, a);
685: return *a;
686: }
687:
688: const m68030ATCLine&
689: m68030ATC::fill_write()
690: {
691: uint32 laddr = cpu->bus.laddr & cpu->mmu_tc.lmask;
692: uint fc = cpu->bus.GetFC();
693: m68030ATCTable *table;
694: m68030ATCLine *a;
695: int i;
696:
697: #if !defined(ATC_SINGLE)
698: table = &tables[fc];
699: // キャッシュとマッチすればそれを返す
700: a = table->head;
701: if (a->GetTag() == laddr) {
702: // ライトアクセスなので、WP でなく Modified == 0 なら
703: // Modified を立てるため、このエントリを破棄して改めて
704: // テーブルサーチを実行する。
705: if (!a->IsWProtect() && !a->IsModified()) {
706: FILL_PRINT(fc, a);
1.1.1.6 root 707: MMULOG(3, 1, "ATC_fill: write access but M is not set, "
708: "so invalidate it");
1.1 root 709: a->Invalidate();
710: goto search;
711: }
712: FILL_PRINT(fc, a);
713: table->hit_head++;
714: return *a;
715: }
716: for (i = 0; i < countof(table->line); i++) {
717: a = &table->line[i];
718: if (a->GetTag() == laddr) {
719: // ライトアクセスなので、WP でなく Modified == 0 なら
720: // Modified を立てるため、このエントリを破棄して改めて
721: // テーブルサーチを実行する。
722: if (!a->IsWProtect() && !a->IsModified()) {
723: FILL_PRINT(fc, a);
1.1.1.6 root 724: MMULOG(3, 1, "ATC_fill: write access but M is not set, "
725: "so invalidate it");
1.1 root 726: a->Invalidate();
727: break;
728: }
729: // ヒットしたので先頭に移動。
730: a = table->MoveHead(a);
731:
732: FILL_PRINT(fc, a);
733: table->hit[i]++;
734: return *a;
735: }
736: }
737: search:;
738:
739: // 見付からなかったので、古いエントリを1つ更新
740: a = table->MoveHead(table->Lookup());
741: table->hit[m68030ATCTable::LINES]++;
742: // タグはこっちで初期化
743: a->tag = laddr;
744: #else
745: table = &tables[0];
746: // キャッシュとマッチすればそれを返す
747: a = table->head;
748: for (i = 0; a; a = a->next, i++) {
749: if ((a->GetTag() == laddr) && (a->fc == fc)) {
750: // ライトアクセスなので、WP でなく Modified == 0 なら
751: // Modified を立てるため、このエントリを破棄して改めて
752: // テーブルサーチを実行する。
753: if (!a->IsWProtect() && !a->IsModified()) {
754: FILL_PRINT(fc, a);
1.1.1.6 root 755: MMULOG(3, 1, "ATC_fill: write access but M is not set, "
756: "so invalidate it");
1.1 root 757: a->Invalidate();
758: break;
759: }
760:
761: // ヒットしたので、先頭から2番目に移動
762: if (i > 2) {
763: table->move_second(a);
764: }
765:
766: FILL_PRINT(fc, a);
767: table->hit[i]++;
768: return *a;
769: }
770: }
771:
772: // 見付からなかったので、古いエントリを1つ更新
773: a = table->lookup();
774: table->remove(a);
775: table->insert_head(a);
776: // 論理部分(タグ部分)を初期化
777: a->tag = laddr;
778: a->fc = fc;
779: table->hit[m68030ATCTable::LINES]++;
780: #endif
781:
782: // テーブルサーチして結果を ATC に入れる
783: m68030MMU mmu(cpu);
1.1.1.8 ! root 784: mmu.search(7);
1.1 root 785: mmu.make_atc(a);
786:
787: FILL_PRINT(fc, a);
788: return *a;
789: }
790:
791: // ピークアクセス用に ATC を検索する。
1.1.1.8 ! root 792: // ATC になければ NULL を返す。ここでは疑似テーブルサーチは行わない。
1.1 root 793: // laddr は論理ページアドレスにマスクしておくこと。
1.1.1.8 ! root 794: const m68030ATCLine *
1.1 root 795: m68030ATC::fill_peek(uint32 laddr, uint fc)
796: {
797: m68030ATCTable *table;
1.1.1.8 ! root 798: const m68030ATCLine *a;
1.1 root 799:
800: #if !defined(ATC_SINGLE)
801: // キャッシュとマッチすればそれを返す
802: table = &tables[fc];
803: for (int i = 0; i < countof(table->line); i++) {
804: a = &table->line[i];
805: if (a->GetTag() == laddr) {
806: // ヒットした
1.1.1.6 root 807: MMULOG(3, 1, "fill_peek: match %d:$%08x -> $%08x",
1.1.1.8 ! root 808: fc, laddr, (uint32)a->GetPAddr());
! 809: return a;
1.1 root 810: }
811: }
812: #else
813: // キャッシュとマッチすればそれを返す
814: table = &tables[0];
815: for (a = table->head; a; a = a->next) {
816: if ((a->GetTag() == laddr) && ((a->fc & 4) == fc)) {
817: // ヒットした
1.1.1.6 root 818: MMULOG(3, 1, "fill_peek: match %d:$%08x -> $%08x",
1.1.1.8 ! root 819: a->fc, laddr, (uint32)a->GetPAddr());
! 820: return a;
1.1 root 821: }
822: }
823: #endif
824:
1.1.1.8 ! root 825: return NULL;
1.1 root 826: }
827:
828: // デバッグ表示。
829: // ATC_SINGLE なら fc は ATCLine に含まれているため、引数はダミーで
830: // 変数名が衝突するため仮引数名も変えてある。なんだかなあ。
1.1.1.6 root 831: // XXX print といいつつ string を返す
1.1 root 832: #if defined(ATC_SINGLE)
1.1.1.6 root 833: std::string
1.1 root 834: m68030ATCLine::fill_print(uint dummyfc)
835: #else
1.1.1.6 root 836: std::string
1.1 root 837: m68030ATCLine::fill_print(uint fc)
838: #endif
839: {
840: uint32 laddr = GetLAddr();
841:
842: if (!IsBusError()) {
843: uint32 wp = IsWProtect();
844: uint32 mod = IsModified();
1.1.1.6 root 845: return indent_format(1,
846: "ATC_fill: match %d:$%08x -> $%08x WP=%d M=%d",
1.1 root 847: fc, laddr, GetPAddr(), wp, mod);
848: } else {
1.1.1.6 root 849: return indent_format(1,
850: "ATC_fill: match %d:$%08x -> BusErr",
1.1 root 851: fc, laddr);
852: }
853: }
854:
855: #if !defined(ATC_SINGLE)
856: // 更新用にエントリを1つ差し出す。
857: m68030ATCLine *
858: m68030ATCTable::Lookup()
859: {
860: uint32 minage;
861: int minidx;
862:
863: // 空きエントリを探しながら、最古エントリを探しておく。
864: // 最古エントリは age が最も小さいもの。
865: minage = (uint32)-1;
866: minidx = 0;
867: for (int i = 0; i < countof(line); i++) {
868: m68030ATCLine& a = line[i];
869: if (a.IsInvalid()) {
1.1.1.6 root 870: MMULOG(3, 1, "ATC_lookup got free entry [%d]", i);
1.1 root 871: return &a;
872: }
873: if (a.age < minage) {
874: minage = a.age;
875: minidx = i;
876: }
877: }
878: // 空きがなければ、最古のエントリを差し出す
1.1.1.6 root 879: MMULOG(3, 1, "ATC_lookup got oldest entry [%d]", minidx);
1.1 root 880: return &line[minidx];
881: }
882: #else
883: // 更新用にエントリを1つ差し出す。
884: m68030ATCLine *
885: m68030ATCTable::lookup()
886: {
887: m68030ATCLine *a;
888:
889: // 空きエントリを探す
890: for (int i = 0; i < LINES; i++) {
891: a = &line[i];
892: if (a->IsInvalid()) {
1.1.1.6 root 893: MMULOG(3, 1, "ATC_lookup got free entry [%d]", i);
1.1 root 894: goto found;
895: }
896: }
897:
898: // 空きがなければ、リストの末尾が最古なのでこれを差し出す
899: a = head;
900: while (a->next) {
901: a = a->next;
902: }
1.1.1.6 root 903: MMULOG(3, 1, "ATC_lookup got oldest entry");
1.1 root 904:
905: found:
906: return a;
907: }
908: #endif
909:
910: // ATC をすべてフラッシュする。命令からコールされる
911: void
912: m68030ATC::flush()
913: {
914: for (int i = 0; i < countof(tables); i++) {
915: tables[i].flush();
916: }
917: }
918:
919: // ATC の fc, mask が一致するエントリをフラッシュする。
920: // 命令からコールされる。
921: void
922: m68030ATC::flush(uint32 fc, uint32 mask)
923: {
924: #if !defined(ATC_SINGLE)
925: for (int i = 0; i < countof(tables); i++) {
926: if (((i ^ fc) & mask) == 0) {
927: // FC が一致したテーブルを全フラッシュ
928: tables[i].flush();
929: }
930: }
931: #else
932: for (int i = 0; i < 8; i++) {
933: if (((i ^ fc) & mask) == 0) {
934: // この FC をテーブルからフラッシュ
935: tables[0].flush_fc(i);
936: }
937: }
938: #endif
939: }
940:
941: // ATC の fc, mask, addr が一致するエントリをフラッシュする。
942: // 命令からコールされる。
943: void
944: m68030ATC::flush(uint32 fc, uint32 mask, uint32 addr)
945: {
946: #if !defined(ATC_SINGLE)
947: for (int i = 0; i < countof(tables); i++) {
948: if (((i ^ fc) & mask) == 0) {
949: // FC が一致したテーブルから addr が一致したエントリをフラッシュ
950: tables[i].flush(addr);
951: }
952: }
953: #else
954: for (int i = 0; i < 8; i++) {
955: if (((i ^ fc) & mask) == 0) {
956: // FC と addr が一致したエントリをフラッシュ
957: tables[0].flush(i, addr);
958: }
959: }
960: #endif
961: }
962:
963: // この ATC テーブルのエントリをすべてフラッシュする。
964: void
965: m68030ATCTable::flush()
966: {
967: for (int i = 0; i < countof(line); i++) {
968: m68030ATCLine& a = line[i];
969: a.Invalidate();
970: }
971: }
972:
973: #if !defined(ATC_SINGLE)
974: // addr が一致するエントリをすべてフラッシュ
975: void
976: m68030ATCTable::flush(uint32 addr)
977: {
978: for (int i = 0; i < countof(line); i++) {
979: m68030ATCLine& a = line[i];
980: if (a.GetLAddr() == addr) {
981: a.Invalidate();
982: }
983: }
984: }
985: #else
986: // FC が一致するエントリをすべてフラッシュする
987: void
988: m68030ATCTable::flush_fc(uint32 fc)
989: {
990: for (int i = 0; i < countof(line); i++) {
991: m68030ATCLine& a = line[i];
992: if (a.fc == fc) {
993: a.Invalidate();
994: }
995: }
996: }
997:
998: // FC と addr が一致するエントリをすべてフラッシュ
999: void
1000: m68030ATCTable::flush(uint32 fc, uint32 addr)
1001: {
1002: for (int i = 0; i < countof(line); i++) {
1003: m68030ATCLine& a = line[i];
1004: if (a.fc == fc && a.GetLAddr() == addr) {
1005: a.Invalidate();
1006: }
1007: }
1008: }
1009: #endif
1010:
1011:
1012: //
1013: // テーブルサーチ
1014: //
1015:
1016: // コンストラクタ
1.1.1.8 ! root 1017: m68030MMU::m68030MMU(MPU680x0Device *cpu_)
1.1 root 1018: {
1.1.1.8 ! root 1019: cpu = cpu_;
1.1 root 1020:
1021: m_type = INVALID;
1022: m_s = 0;
1023: m_wp = 0;
1024: m_m = 0;
1025: m_l = 0;
1026: m_berr = false;
1027: m_debugger = false;
1028: m_ptest = false;
1029:
1030: x = -1;
1031: memset(m_lv, 0, sizeof(m_lv));
1032: m_laddr = 0;
1033: m_fc = -1;
1034: m_desc1 = 0;
1035: m_desc2 = 0;
1036: m_descsize = 0;
1037: m_lastsize = 0;
1038: }
1039:
1.1.1.8 ! root 1040: // デストラクタ
! 1041: m68030MMU::~m68030MMU()
! 1042: {
! 1043: }
! 1044:
1.1 root 1045: // テーブルサーチのメイン部分。
1046: // m_type および ATC 作成に必要な情報を埋めてから帰る。
1047: // ATC は帰った先で作成する。
1048: void
1.1.1.8 ! root 1049: m68030MMU::search(int level)
1.1 root 1050: {
1051: const char *rpname;
1052: int dt;
1053: bool is_super;
1054:
1055: m_laddr = cpu->bus.laddr;
1056: m_fc = cpu->bus.GetFC();
1057:
1058: is_super = (m_fc & 0x04);
1059:
1060: // アドレスを (IS,) TIA .. TID に分解。
1061: //
1062: // TIA=$C, TIB=$A, (TIC = TID = 0), PS=$A の場合以下のようにする。
1063: // 使ってない TIC, TID については cpu->mmu_tc->{tic,tid} == 0 で判断する。
1064: //
1065: // A B PS
1066: // +----------------+--------------+--------------+
1067: // $00A01A00 | 0000 0000 1010 | 0000 0001 10 | xx xxxx xxxx |
1068: // +----------------+--------------+--------------+
1069: // shift[TIA] =20 shift[TIB] =10
1070: // lv[TIA].idx=0xA lv[TIB].idx=0x6
1071: //
1072: for (int i = TID; i >= TIA; i--) {
1073: if (cpu->mmu_tc.tix[i] > 0) {
1074: uint32 mask = cpu->mmu_tc.mask[i];
1075: m_lv[i] = (m_laddr >> cpu->mmu_tc.shift[i]) & mask;
1076: }
1077: }
1078: m_lv[FCL] = m_fc;
1079:
1.1.1.8 ! root 1080: cpu->putlogf(3, [&] {
1.1 root 1081: std::string buf;
1082:
1.1.1.6 root 1083: buf = indent_format(2, "search: laddr=$%08x ->", m_laddr);
1.1 root 1084: if (cpu->mmu_tc.is > 0)
1085: buf += string_format(" IS=%d", cpu->mmu_tc.is);
1086: if (cpu->mmu_tc.fcl)
1087: buf += string_format(" FC=%d", m_lv[FCL]);
1088: for (int i = TIA; i <= TID; i++) {
1089: if (cpu->mmu_tc.tix[i] > 0) {
1090: buf += string_format(" %s=%d($%0*x)",
1091: m_lvname[i], cpu->mmu_tc.tix[i],
1092: NIBBLE(cpu->mmu_tc.tix[i]), m_lv[i]);
1093: }
1094: }
1.1.1.6 root 1095: return buf;
1096: });
1.1 root 1097:
1098: // サーチ時の初期化処理。図9-26
1099: m_wp = 0;
1100: m_s = 0;
1101:
1102: // ここから図9-25。
1103:
1104: // 使用するルートポインタを決定
1105: if (cpu->mmu_tc.sre && is_super) {
1106: rpname = "SRP";
1107: m_desc1 = cpu->GetSRPh();
1108: m_desc2 = cpu->GetSRPl();
1109: } else {
1110: rpname = "CRP";
1111: m_desc1 = cpu->GetCRPh();
1112: m_desc2 = cpu->GetCRPl();
1113: }
1114:
1115: // ルートポインタの DT をチェック
1116: dt = GET_DT(m_desc1);
1.1.1.6 root 1117: MMULOG(3, 2, "search: %s dt=%s", rpname, dtname(dt));
1.1 root 1118: switch (dt) {
1.1.1.8 ! root 1119: case DT_INVALID:
! 1120: // 無効は設定できないはずなので、ここに来ないはず
! 1121: PANIC("%s.DT==Invalid", rpname);
! 1122: break;
! 1123:
1.1 root 1124: case DT_PAGE: // ページディスクリプタ
1125: m_type = EARLY;
1126: return;
1127:
1128: case DT_VALID4: // 有効(4バイト)
1129: case DT_VALID8: // 有効(8バイト)
1130: // descsize は DT=$2 なら 4、DT=$3 なら 8 になる
1131: m_descsize = 1 << dt;
1132: m_lastsize = 8;
1133: break;
1134: }
1135:
1136: // 必要ならファンクションコード・ルックアップ
1137: if (cpu->mmu_tc.fcl) {
1138: x = FCL;
1.1.1.8 ! root 1139: // たぶん検索レベルを1つ消費するはず。未確認。
! 1140: level--;
! 1141:
1.1.1.6 root 1142: MMULOG(3, 2, "search: %s tableaddr=$%08x idx=$%x",
1.1 root 1143: m_lvname[x], m_desc2, m_lv[x]);
1144:
1145: // ディスクリプタをフェッチ
1146: if (fetch_desc(m_desc2, m_lv[x]) == false) {
1147: return;
1148: }
1149:
1150: // ディスクリプタタイプをチェック
1151: dt = GET_DT(m_desc1);
1152: switch (dt) {
1153: case DT_INVALID: // 無効
1154: m_type = INVALID;
1155: return;
1156:
1157: case DT_PAGE: // ページディスクリプタ
1158: m_type = EARLY;
1159: return;
1160:
1161: case DT_VALID4: // 有効4バイト
1162: case DT_VALID8: // 有効8バイト
1163: m_lastsize = m_descsize;
1164: m_descsize = 1 << dt;
1165: break;
1166: }
1167: }
1168:
1169: // TIx のテーブルサーチに入る。図9-25 の下半分。
1170:
1.1.1.8 ! root 1171: for (x = TIA; x < level; x++) {
1.1 root 1172: // リミットチェック
1173: if (m_lastsize == 8 && limitcheck() == false) {
1174: m_type = INVALID;
1175: m_l = 1;
1176: return;
1177: }
1178:
1179: // テーブルアドレス
1180: uint32 tableaddr;
1181: tableaddr = (m_lastsize == 4) ? m_desc1 : m_desc2;
1182: tableaddr &= 0xfffffff0;
1.1.1.6 root 1183: MMULOG(3, 2, "search: %s tableaddr=$%08x idx=$%x",
1.1 root 1184: m_lvname[x], tableaddr, m_lv[x]);
1185:
1186: // ディスクリプタをフェッチ
1187: if (fetch_desc(tableaddr, m_lv[x]) == false) {
1188: return;
1189: }
1190:
1191: // ディスクリプタタイプをチェック
1192: dt = GET_DT(m_desc1);
1193: switch (dt) {
1194: case DT_INVALID: // 無効
1195: m_type = INVALID;
1196: return;
1197:
1198: case DT_PAGE: // ページディスクリプタ
1199: if (x == TID) {
1200: m_type = NORMAL;
1201: } else {
1202: if (cpu->mmu_tc.tix[x + 1] == 0) {
1203: m_type = NORMAL;
1204: } else {
1205: m_type = EARLY;
1206: }
1207: }
1208: return;
1209:
1210: case DT_VALID4: // 有効4バイト
1211: case DT_VALID8: // 有効8バイト
1212: m_lastsize = m_descsize;
1213: m_descsize = 1 << dt;
1214:
1215: if (x == TID || cpu->mmu_tc.tix[x + 1] == 0) {
1216: // 間接
1217: m_type = INDIRECT;
1218:
1219: // ディスクリプタをフェッチ
1220: tableaddr = (m_lastsize == 4) ? m_desc1 : m_desc2;
1221: tableaddr &= 0xfffffff0;
1222: if (fetch_desc(tableaddr, 0) == false) {
1223: return;
1224: }
1225: if (GET_DT(m_desc1) != DT_PAGE) {
1226: m_type = INVALID;
1227: }
1228: return;
1229: }
1230: // 次段のサーチを繰り返す
1.1.1.8 ! root 1231: break;
1.1 root 1232: }
1233: }
1.1.1.8 ! root 1234:
! 1235: // レベル上限にひっかかった場合、x は過ぎているので一つ戻しておく。
! 1236: x--;
1.1 root 1237: }
1238:
1239: // リミットチェックを実行。図9-28。
1240: // 無効のケースに落ちたら false を返す。
1241: bool
1242: m68030MMU::limitcheck() const
1243: {
1.1.1.8 ! root 1244: uint16 limit = (m_desc1 >> 16) & 0x7fff;
1.1 root 1245:
1.1.1.8 ! root 1246: // 最上位ビットが L/U
! 1247: if ((int32)m_desc1 < 0) {
! 1248: if (m_lv[x] < limit) {
! 1249: MMULOG(3, 2, "limitcheck: $%04x < $%04x", m_lv[x], limit);
! 1250: return false;
! 1251: }
! 1252: } else {
! 1253: if (m_lv[x] > limit) {
! 1254: MMULOG(3, 2, "limitcheck: $%04x > $%04x", m_lv[x], limit);
! 1255: return false;
! 1256: }
1.1 root 1257: }
1258: return true;
1259: }
1260:
1261: // ディスクリプタ中のフラグの更新 (を予約する)
1262: #define UPDATE_DESC(flag) do { \
1263: if ((m_desc1 & (flag)) == 0) { \
1264: m_desc1 |= (flag); \
1265: do_write = true; \
1266: } \
1267: } while (0)
1268:
1269: // ディスクリプタのフェッチと、ヒストリおよびステータスの更新。
1270: // 図9-29。
1271: // ディスクリプタを取得できれば true、
1272: // ATC エントリの作成に向かう場合は false。
1273: bool
1274: m68030MMU::fetch_desc(uint32 tableaddr, int idx)
1275: {
1276: uint32 descaddr;
1277: bool do_write;
1278: uint dt;
1279:
1280: // ディスクリプタのアドレスを計算。ここだけマニュアルの説明が雑すぎ。
1281: // インダイレクトなら idx = 0 でコールしてあるので、
1282: // tableaddr がそのまま PA になるという寸法。
1283: descaddr = tableaddr + idx * m_descsize;
1.1.1.6 root 1284: MMULOG(3, 2, "fetch_desc: descsize=%d descaddr=$%08x",
1.1 root 1285: m_descsize, descaddr);
1286:
1287: // バスエラー発生フラグをクリアしておく
1288: m_berr = false;
1289:
1290: // ディスクリプタを取得
1291: if (m_debugger) {
1292: // デバッガアクセス
1293: uint64 data;
1.1.1.8 ! root 1294: data = cpu->mainbus->Peek32(descaddr);
1.1 root 1295: if ((int64)data < 0) {
1296: goto buserr;
1297: }
1298: m_desc1 = data;
1299:
1300: if (m_descsize == 8) {
1.1.1.8 ! root 1301: data = cpu->mainbus->Peek32(descaddr + 4);
1.1 root 1302: if ((int64)data < 0) {
1303: goto buserr;
1304: }
1305: m_desc2 = data;
1306: }
1307: } else {
1308: uint64 data;
1309:
1310: data = phys_read_32(descaddr);
1311: if ((int64)data < 0) {
1312: goto buserr;
1313: }
1314: m_desc1 = data;
1315:
1316: if (m_descsize == 8) {
1317: data = phys_read_32(descaddr + 4);
1318: if ((int64)data < 0) {
1319: goto buserr;
1320: }
1321: m_desc2 = data;
1322: }
1.1.1.8 ! root 1323:
! 1324: m_lastaddr = descaddr;
1.1 root 1325: }
1326:
1327: // ディスクリプタタイプをチェック
1328: // DT は必ず最初のロングワードの下位2ビット。
1329: do_write = false;
1330: dt = GET_DT(m_desc1);
1.1.1.6 root 1331: MMULOG(3, 2, "fetch_desc: desc=%s dt=%s",
1.1 root 1332: sprintf_desc().c_str(), dtname(dt));
1333: switch (dt) {
1334: case DT_INVALID: // 無効
1335: return true;
1336:
1337: case DT_PAGE: // ページディスクリプタ
1338: // U ビットを更新
1339: UPDATE_DESC(MMU_DESC_U);
1340:
1341: // 書き込み操作なら M を更新
1342: if (cpu->bus.IsWrite() && !m_ptest) {
1343: UPDATE_DESC(MMU_DESC_M);
1344: }
1345: // 図にはないけど、ATC 更新のためと PTEST のために
1346: // ページディスクリプタの M ビットを記録。
1347: if ((m_desc1 & MMU_DESC_M))
1348: m_m = 1;
1349: break;
1350:
1351: case DT_VALID4: // 有効4バイト
1352: case DT_VALID8: // 有効8バイト
1353: // U ビットを更新
1354: UPDATE_DESC(MMU_DESC_U);
1355: break;
1356: }
1357:
1358: // デバッガ自身がアドレス変換を実施している時は書き込みは行わない
1359: if (m_debugger) {
1360: do_write = false;
1361: }
1362:
1363: // ライトライクルの実行
1364: if (do_write) {
1365: int64 berr = phys_write_32(descaddr, m_desc1);
1366: if (berr < 0) {
1367: goto buserr;
1368: }
1369: // バス動作正常終了
1.1.1.6 root 1370: MMULOG(3, 2, "fetch_desc: desc=%s updated", sprintf_desc().c_str());
1.1 root 1371: }
1372:
1373: // ステータス更新
1374: // XXX Cache Inhibit ビットは未実装なので、ページディスクリプタと
1375: // 有効4/8バイトのケースは同じでよくなる。
1376: // XXX 実際には CI はページディスクリプタにしかないけど
1377: m_wp |= (m_desc1 & MMU_DESC_WP) ? 1 : 0;
1378: if (m_descsize == 8) {
1379: m_s |= (m_desc1 & MMU_DESC_S) ? 1 : 0;
1380: }
1381:
1382: return true;
1383:
1384: // バスエラー
1385: buserr:
1386: m_type = INVALID;
1387: m_berr = true;
1388: return false;
1389: }
1390:
1391: // ATC エントリを作成。実行系用。
1392: // 図9-27 だが雑すぎ。
1393: void
1394: m68030MMU::make_atc(m68030ATCLine *a)
1395: {
1396: std::string buf;
1397: uint32 paddr;
1398:
1399: a->data = 0;
1400: switch (m_type) {
1401: case INVALID: // 無効
1402: a->data |= m68030ATCLine::BUSERROR;
1.1.1.6 root 1403: MMULOG(3, 2, "make_atc: type=INVALID -> BusErr");
1.1 root 1404: return;
1405:
1406: case NORMAL: // ノーマル
1407: case INDIRECT: // 間接
1408: paddr = (m_descsize == 4) ? m_desc1 : m_desc2;
1.1.1.6 root 1409: MMULOG(3, 2, "make_atc: type=NORMAL paddr=$%08x", paddr & 0xffffff00);
1.1 root 1410: break;
1411:
1412: case EARLY: // アーリーターミネーション
1413: paddr = (m_descsize == 4) ? m_desc1 : m_desc2;
1414: buf = string_format("make_atc: type=EARLY paddr=$%08x",
1415: paddr & 0xffffff00);
1416:
1417: // 残ってるビットも足して返す
1418: for (int i = x + 1; i <= TID; i++) {
1419: if (cpu->mmu_tc.tix[i] > 0) {
1420: paddr |= m_lv[i] << cpu->mmu_tc.shift[i];
1421: buf += string_format(" +%s=%08x", m_lvname[i], paddr);
1422: }
1423: }
1.1.1.6 root 1424: MMULOG(3, 2, "%s", buf.c_str());
1.1 root 1425: break;
1426: default:
1.1.1.8 ! root 1427: PANIC("corrupted m_type=%d", (int)m_type);
1.1 root 1428: }
1429:
1430: // PS の部分は反映しない
1431: a->paddr = paddr & cpu->mmu_tc.lmask;
1432:
1433: //if (m_ci) a->data |= m68030ATCLine::CINHIBIT;
1434: if (m_wp)
1435: a->data |= m68030ATCLine::WPROTECT;
1436: if (m_m)
1437: a->data |= m68030ATCLine::MODIFIED;
1438: }
1439:
1440: // make_atc() と同様にテーブルサーチの結果から物理ページアドレスを返す。
1441: // バスエラーになるケースなら (uint64)-1 を返す。
1442: // デバッガアクセスなので、VM に一切干渉しない。
1443: uint64
1444: m68030MMU::make_atc_debugger()
1445: {
1446: uint64 paddr;
1447:
1448: switch (m_type) {
1449: case INVALID: // 無効
1450: return (uint64)-1;
1451: break;
1452:
1453: case NORMAL: // ノーマル
1454: case INDIRECT: // 間接
1455: paddr = (m_descsize == 4) ? m_desc1 : m_desc2;
1456: paddr &= 0xffffff00;
1457: break;
1458:
1459: case EARLY: // アーリーターミネーション
1460: paddr = (m_descsize == 4) ? m_desc1 : m_desc2;
1461: paddr &= 0xffffff00;
1462: // 残ってるビットも足して返す
1463: for (int i = x + 1; i <= TID; i++) {
1464: if (cpu->mmu_tc.tix[i] > 0) {
1465: paddr |= m_lv[i] << cpu->mmu_tc.shift[i];
1466: }
1467: }
1468: break;
1469: default:
1.1.1.8 ! root 1470: PANIC("corrupted m_type=%d", (int)m_type);
1.1 root 1471: }
1472: return paddr;
1473: }
1474:
1475: // 物理メモリからの読み込み。
1476: // 正常に読み込めれば 32bit の値。バスエラーなら (uint64)-1 を返す。
1477: uint64
1478: m68030MMU::phys_read_32(uint32 addr)
1479: {
1480: m68kbus backup;
1481: uint64 data;
1482:
1483: // バス情報を一旦退避
1484: backup = cpu->bus;
1485:
1486: // 物理バスアクセス
1.1.1.8 ! root 1487: cpu->bus.ssw = M68K::SSW_BUS_R | M68K::FC_SD;
! 1488: data = cpu->mainbus->Read32(addr);
1.1 root 1489: if ((int64)data < 0)
1490: return data;
1491:
1492: // バス情報を復元
1493: cpu->bus = backup;
1494: return data;
1495: }
1496:
1497: // 物理メモリへの書き込み。
1498: // 正常に書き込めれば 0、バスエラーなら (uint64)-1 を返す。
1499: uint64
1500: m68030MMU::phys_write_32(uint32 addr, uint32 data)
1501: {
1502: m68kbus backup;
1503: uint64 berr;
1504:
1505: // バス情報を一旦退避
1506: backup = cpu->bus;
1507:
1508: // 物理バスアクセス
1.1.1.8 ! root 1509: cpu->bus.ssw = M68K::SSW_BUS_W | M68K::FC_SD;
! 1510: berr = cpu->mainbus->Write32(addr, data);
1.1 root 1511: if ((int64)berr < 0)
1512: return berr;
1513:
1514: // バス情報を復元
1515: cpu->bus = backup;
1516: return 0;
1517: }
1518:
1519: // ディスクリプタ表示用の文字列を返す。
1520: // m_descsize によって m_desc1, m_desc2 を適切に文字列にする。
1521: std::string
1522: m68030MMU::sprintf_desc()
1523: {
1524: std::string buf;
1525:
1526: if (m_descsize == 4) {
1527: buf = string_format("%08x", m_desc1);
1528: } else {
1529: buf = string_format("%08x_%08x", m_desc1, m_desc2);
1530: }
1531:
1532: // フラグの出現条件がややこしいので注意
1533: int dt = GET_DT(m_desc1);
1534: buf += string_format(" (%s%s%s%c%c)",
1535: ((m_descsize == 4) ? "x" : ((m_desc1 & MMU_DESC_S) ? "S" : "-")),
1536: ((dt != DT_PAGE) ? "x" : ((m_desc1 & MMU_DESC_CI) ? "C" : "-")),
1537: ((dt != DT_PAGE) ? "x" : ((m_desc1 & MMU_DESC_M) ? "M" : "-")),
1538: (m_desc1 & MMU_DESC_U) ? 'U' : '-',
1539: (m_desc1 & MMU_DESC_WP) ? 'W' : '-'
1540: );
1541:
1542: return buf;
1543: }
1544:
1545: // ディスクリプタタイプ文字列 (デバッグ用)
1546: const char *
1547: m68030MMU::dtname(uint32 dt)
1548: {
1549: static char buf[32];
1550: switch (dt) {
1551: case DT_INVALID: return "invalid";
1.1.1.4 root 1552: case DT_PAGE: return "page";
1.1 root 1553: case DT_VALID4: return "valid4";
1554: case DT_VALID8: return "valid8";
1555: }
1556: sprintf(buf, "(invalid DT %d)", dt);
1557: return buf;
1558: }
1559:
1560: // デバッグ用文字列
1561: const char * const m68030MMU::m_lvname[MAX_LV] = {
1562: "TIA",
1563: "TIB",
1564: "TIC",
1565: "TID",
1566: "FCL", // この順ではないが、便宜上ここにおいてある
1567: };
1568:
1569: //
1570: // アドレス変換
1571: //
1572:
1573: // 論理アドレスが TT0/TT1 どちらかと一致すれば true を返す。
1574: // 一致しなければ false を返す。
1575: // 高速化のため mmu_tt_quick による評価は呼び出し側で行なっている。
1.1.1.8 ! root 1576: bool
! 1577: MPU680x0Device::CheckTT() const
1.1 root 1578: {
1579: bool ci;
1580: int match;
1581:
1582: match = 0;
1583: ci = false;
1584: for (int i = 0; i < 2; i++) {
1.1.1.8 ! root 1585: const m68030TT& tt = mmu_tt[i];
! 1586: if (tt.Match(bus.ssw_laddr)) {
1.1 root 1587: // 一致した
1588: match += i + 1;
1589: ci |= tt.ci != 0;
1.1.1.8 ! root 1590: MMULOG(3, 1, "%s: TT%d match", __func__, i);
1.1 root 1591: }
1592: }
1593:
1594: // CI は計算はするけど現状未実装なので放置
1595: (void)ci;
1596:
1597: // 一致したら PA <- LA
1598: if (match != 0) {
1.1.1.8 ! root 1599: MMULOG(3, 0, "%s: result %08x (match TT%s)", __func__,
! 1600: bus.laddr,
1.1 root 1601: (match == 3) ? "0 and TT1" : ((match == 1) ? "0" : "1"));
1602: return true;
1603: }
1604: return false;
1605: }
1606:
1607: // フェッチ用のアドレス変換を行う。
1608: // 変換できれば true、バスエラーなら false を返す。
1609: bool
1.1.1.8 ! root 1610: MPU680x0Device::TranslateFetch()
1.1 root 1611: {
1612: // 状態表示
1.1.1.8 ! root 1613: MMULOG(3, 0, "%s: enter %c:$%08x pc=$%08x", __func__,
! 1614: (bus.GetFC() & 0x04) ? 'S' : 'U',
! 1615: bus.laddr,
! 1616: ppc);
1.1 root 1617:
1618: // まず TT をチェック
1.1.1.8 ! root 1619: if (__predict_false(mmu_tt_quick[bus.laddr >> 24] != 0)) {
! 1620: if (CheckTT()) {
1.1 root 1621: return true;
1622: }
1623: }
1624:
1625: // ATC からアドレスを取得
1.1.1.8 ! root 1626: if (mmu_tc.e) {
! 1627: const m68030ATCLine& a = atc.fill_fetch();
1.1 root 1628: if (a.IsBusError()) {
1.1.1.8 ! root 1629: MMULOG(3, 0, "%s: result BusErr (ATC:B)", __func__);
1.1 root 1630: return false;
1631: }
1632:
1.1.1.8 ! root 1633: bus.paddr = a.GetPAddr();
! 1634: bus.paddr |= bus.laddr & mmu_tc.pgmask;
! 1635: //bus.ci = a->ci;
1.1 root 1636: }
1637:
1.1.1.8 ! root 1638: MMULOG(3, 0, "%s: result $%08x", __func__, bus.paddr);
1.1 root 1639: return true;
1640: }
1641:
1642: // リード用のアドレス変換を行う。
1643: // 変換できれば true、バスエラーなら false を返す。
1644: bool
1.1.1.8 ! root 1645: MPU680x0Device::TranslateRead()
1.1 root 1646: {
1647: // 状態表示
1.1.1.8 ! root 1648: MMULOG(3, 0, "%s: enter %c:$%08x pc=%c:$%08x", __func__,
! 1649: (bus.GetFC() & 0x04) ? 'S' : 'U',
! 1650: bus.laddr,
! 1651: IsSuper() ? 'S' : 'U',
! 1652: ppc);
1.1 root 1653:
1654: // まず TT をチェック
1.1.1.8 ! root 1655: if (__predict_false(mmu_tt_quick[bus.laddr >> 24] != 0)) {
! 1656: if (CheckTT()) {
1.1 root 1657: return true;
1658: }
1659: }
1660:
1661: // ATC からアドレスを取得
1.1.1.8 ! root 1662: if (mmu_tc.e) {
! 1663: const m68030ATCLine& a = atc.fill_read();
1.1 root 1664: if (a.IsBusError()) {
1.1.1.8 ! root 1665: MMULOG(3, 0, "%s: result BusErr (ATC:B)", __func__);
1.1 root 1666: return false;
1667: }
1668:
1.1.1.8 ! root 1669: bus.paddr = a.GetPAddr();
! 1670: bus.paddr |= bus.laddr & mmu_tc.pgmask;
! 1671: //bus.ci = a->ci;
1.1 root 1672: }
1673:
1.1.1.8 ! root 1674: MMULOG(3, 0, "%s: result $%08x", __func__, bus.paddr);
1.1 root 1675: return true;
1676: }
1677:
1678: // ライト用のアドレス変換を行う。
1679: // 変換できれば true、バスエラーなら false を返す。
1680: bool
1.1.1.8 ! root 1681: MPU680x0Device::TranslateWrite()
1.1 root 1682: {
1683: // 状態表示
1.1.1.8 ! root 1684: MMULOG(3, 0, "%s: enter %c:$%08x pc=%c:$%08x", __func__,
! 1685: (bus.GetFC() & 0x04) ? 'S' : 'U',
! 1686: bus.laddr,
! 1687: IsSuper() ? 'S' : 'U',
! 1688: ppc);
1.1 root 1689:
1690: // まず TT をチェック
1.1.1.8 ! root 1691: if (__predict_false(mmu_tt_quick[bus.laddr >> 24] != 0)) {
! 1692: if (CheckTT()) {
1.1 root 1693: return true;
1694: }
1695: }
1696:
1697: // ATC からアドレスを取得
1.1.1.8 ! root 1698: if (mmu_tc.e) {
! 1699: const m68030ATCLine& a = atc.fill_write();
1.1 root 1700: if (a.IsBusError()) {
1.1.1.8 ! root 1701: MMULOG(3, 0, "%s: result BusErr (ATC:B)", __func__);
1.1 root 1702: return false;
1703: }
1704: if (a.IsWProtect()) {
1705: // Write アクセスで WP が立ってたらバスエラー
1.1.1.8 ! root 1706: MMULOG(3, 0, "%s: result Buserr (ATC:WP)", __func__);
1.1 root 1707: return false;
1708: }
1709:
1.1.1.8 ! root 1710: bus.paddr = a.GetPAddr();
! 1711: bus.paddr |= bus.laddr & mmu_tc.pgmask;
! 1712: //bus.ci = a->ci;
1.1 root 1713: }
1714:
1.1.1.8 ! root 1715: MMULOG(3, 0, "%s: result $%08x", __func__, bus.paddr);
1.1 root 1716: return true;
1717: }
1718:
1719: // ピーク用のアドレス変換を行う。
1720: // ATC にエントリが見付からない場合、do_search が true ならテーブル
1721: // サーチまで行う。false ならテーブルサーチせずに帰る。
1722: // 変換できれば対応する物理アドレスを、バスエラーなら (uint64)-1 を返す。
1723: uint64
1.1.1.8 ! root 1724: MPU680x0Device::TranslatePeek(uint32 laddr, uint fc, bool do_search)
1.1 root 1725: {
1726: uint64 paddr;
1727:
1728: // 状態表示
1.1.1.8 ! root 1729: MMULOG(3, 0, "%s: enter %c:$%08x", __func__,
1.1 root 1730: (fc & 0x04) ? 'S' : 'U',
1731: laddr);
1732:
1733: // まず TT をチェック
1734: paddr = laddr;
1.1.1.8 ! root 1735: if (__predict_false(mmu_tt_quick[laddr >> 24] != 0)) {
! 1736: uint64 ssw_laddr = ((uint64)(M68K::SSW_BUS_R | fc) << 32) | laddr;
1.1.1.5 root 1737: for (int i = 0; i < 2; i++) {
1.1.1.8 ! root 1738: m68030TT& tt = mmu_tt[i];
1.1.1.5 root 1739: if (tt.Match(ssw_laddr)) {
1740: // 一致した。
1741: // CI はここでは使わないため、一致したことだけわかればよい
1.1.1.8 ! root 1742: MMULOG(3, 0, "%s: result $%08x (match tt)",
! 1743: __func__, (uint32)paddr);
1.1.1.5 root 1744: return paddr;
1745: }
1.1 root 1746: }
1747: }
1748:
1749: // 次に TC (ATC と MMU テーブルサーチ)。
1.1.1.8 ! root 1750: if (mmu_tc.e) {
1.1 root 1751: // ATC からこっそりアドレスを取得
1.1.1.8 ! root 1752: const m68030ATCLine *a;
! 1753: a = atc.fill_peek(laddr & mmu_tc.lmask, fc);
! 1754: if (a != NULL) {
! 1755: paddr = a->GetPAddr();
! 1756: paddr |= laddr & mmu_tc.pgmask;
! 1757: MMULOG(3, 0, "%s: result $%08x (match atc)",
! 1758: __func__, (uint32)paddr);
1.1 root 1759: return paddr;
1760: }
1761:
1762: // 見付からなかったのでこっそりテーブルサーチ。
1763: if (do_search) {
1.1.1.8 ! root 1764: // mmu.search() はさすがに bus を使うので事前に退避。
! 1765: m68kbus backup = bus;
1.1 root 1766:
1.1.1.8 ! root 1767: bus.laddr = laddr;
! 1768: bus.ssw = fc;
! 1769: m68030MMU mmu(this);
1.1 root 1770: mmu.m_debugger = true;
1.1.1.8 ! root 1771: mmu.search(7);
1.1 root 1772: paddr = mmu.make_atc_debugger();
1773: // リストア
1.1.1.8 ! root 1774: bus = backup;
1.1 root 1775:
1776: if ((int64)paddr >= 0) {
1.1.1.8 ! root 1777: paddr |= laddr & mmu_tc.pgmask;
! 1778: MMULOG(3, 0, "%s: result $%08x (table search)",
! 1779: __func__, (uint32)paddr);
1.1 root 1780: return paddr;
1781: }
1782: }
1.1.1.5 root 1783:
1784: // TC が有効だがヒットしなかったらバスエラー
1.1.1.8 ! root 1785: MMULOG(3, 0, "%s: result BusErr", __func__);
1.1.1.5 root 1786: return (uint64)-1;
1.1 root 1787: }
1788:
1.1.1.5 root 1789: // TT が無効かまたは有効でもヒットせず、
1790: // かつ TC も無効だったら (こっちは「有効でヒットせず」は含まない)、
1791: // 論理アドレスをそのまま返す
1.1.1.8 ! root 1792: MMULOG(3, 0, "%s: result $%08x (no translation)", __func__, laddr);
1.1.1.5 root 1793: return laddr;
1.1 root 1794: }
1795:
1796: //
1797: // 命令
1798: //
1799:
1.1.1.8 ! root 1800: // ir2 の下位5ビットから FC を返す。
1.1 root 1801: // 不当パターンなら C++ の例外をスローする。
1.1.1.8 ! root 1802: uint32
! 1803: MPU680x0Device::get_fc()
1.1 root 1804: {
1.1.1.8 ! root 1805: uint fcfield = ir2 & 0x1f;
1.1 root 1806:
1807: if (fcfield == 0) {
1.1.1.8 ! root 1808: return reg.sfc;
1.1 root 1809: } else if (fcfield == 1) {
1.1.1.8 ! root 1810: return reg.dfc;
1.1 root 1811: } else if (fcfield < 0x08) {
1812: // break;
1813: } else if (fcfield < 0x10) {
1.1.1.8 ! root 1814: return reg.D[fcfield & 7] & 7;
1.1 root 1815: } else if (fcfield < 0x18) {
1816: return fcfield & 7;
1817: }
1818: // 不当命令
1.1.1.8 ! root 1819: throw M68K::EXCEP_ILLEGAL;
1.1 root 1820: }
1821:
1822: // MMU 不当命令 (2ワード目で確定)
1.1.1.8 ! root 1823: void
! 1824: MPU680x0Device::mmu_op_illg2()
1.1 root 1825: {
1.1.1.8 ! root 1826: putlog(1, "MMU illegal instruction %04x %04x", ir, ir2);
! 1827: Exception(M68K::EXCEP_FLINE);
1.1 root 1828: }
1829:
1830: // PFLUSH fc,#mask 命令 (EA を持たない方)
1831: void
1.1.1.8 ! root 1832: MPU680x0Device::mmu_op_pflush()
1.1 root 1833: {
1834: uint32 mask;
1835: uint32 fc;
1836:
1.1.1.8 ! root 1837: mask = (ir2 >> 5) & 7;
! 1838: fc = get_fc();
! 1839: atc.flush(fc, mask);
1.1 root 1840: }
1841:
1842: // PFLUSH fc,#mask,ea 命令
1843: void
1.1.1.8 ! root 1844: MPU680x0Device::mmu_op_pflush_ea()
1.1 root 1845: {
1846: uint32 ea;
1847: uint32 mask;
1848: uint32 fc;
1849:
1.1.1.8 ! root 1850: ea = cea_copro();
! 1851: mask = (ir2 >> 5) & 7;
! 1852: fc = get_fc();
! 1853: atc.flush(fc, mask, ea);
1.1 root 1854: }
1855:
1856: // PLOADR/PLOADW 命令
1857: void
1.1.1.8 ! root 1858: MPU680x0Device::mmu_op_pload()
1.1 root 1859: {
1860: uint32 ea;
1861: uint32 fc;
1862:
1.1.1.8 ! root 1863: if ((ir2 & 0x01e0) != 0) {
! 1864: mmu_op_illg2();
1.1 root 1865: return;
1866: }
1.1.1.8 ! root 1867: ea = cea_copro();
! 1868: fc = get_fc();
1.1 root 1869:
1870: // 実効アドレスを論理アドレスとする ATC を作成。
1871: // ってこれでいいのか?
1.1.1.8 ! root 1872: bus.laddr = ea;
! 1873: if ((ir2 & 0x0200)) {
! 1874: bus.ssw = M68K::SSW_BUS_R | fc;
! 1875: atc.fill_read();
1.1 root 1876: } else {
1.1.1.8 ! root 1877: bus.ssw = M68K::SSW_BUS_W | fc;
! 1878: atc.fill_write();
1.1 root 1879: }
1880: }
1881:
1882: // PTESTR/PTESTW 命令
1883: void
1.1.1.8 ! root 1884: MPU680x0Device::mmu_op_ptest()
1.1 root 1885: {
1.1.1.8 ! root 1886: uint level = (ir2 >> 10) & 7;
! 1887: uint rw = (ir2 & 0x0200) ? M68K::SSW_BUS_R : M68K::SSW_BUS_W;
! 1888: uint rn = (ir2 >> 5) & 0xf;
1.1 root 1889: uint32 ea;
1890: uint32 fc;
1891: uint16 mmusr;
1892:
1.1.1.8 ! root 1893: ea = cea_copro();
! 1894: fc = get_fc();
! 1895: mmusr = 0;
1.1 root 1896:
1897: if (level == 0) {
1.1.1.8 ! root 1898: if (rn != 0) {
! 1899: // レベル0で An 指定なら Fライン例外
! 1900: mmu_op_illg2();
! 1901: return;
! 1902: }
1.1 root 1903:
1.1.1.8 ! root 1904: // laddr は IS と PS のところを落としたもの。
! 1905: // ssw_laddr のアドレスは IS を落とさないもの (PSは不問)。
! 1906: uint64 ssw_laddr = ((uint64)(rw | fc) << 32) | ea;
! 1907: uint32 laddr = ea & mmu_tc.lmask;
! 1908:
! 1909: const m68030ATCLine *a = atc.fill_peek(laddr, fc);
! 1910: if (a) {
! 1911: // ATC に見付かった。Modified の状態を返す。
! 1912: if (a->IsBusError()) {
! 1913: mmusr |= m68030MMUSR::B;
! 1914: } else if (a->IsWProtect()) {
! 1915: mmusr |= m68030MMUSR::W;
! 1916: } else if (a->IsModified()) {
! 1917: mmusr |= m68030MMUSR::M;
! 1918: }
! 1919: } else {
! 1920: // ATC に見付からなかった。Invalid を立てる。
! 1921: mmusr = m68030MMUSR::I;
! 1922: }
! 1923:
! 1924: // どちらにしても TT を評価。
! 1925: for (int i = 0; i < 2; i++) {
! 1926: m68030TT& tt = mmu_tt[i];
! 1927: if (tt.Match(ssw_laddr)) {
! 1928: mmusr |= m68030MMUSR::T;
! 1929: }
1.1 root 1930: }
1931: } else {
1.1.1.8 ! root 1932: // レベル 1-7 ならテーブルサーチを実行。
! 1933:
! 1934: bus.laddr = ea;
! 1935: bus.ssw = rw | fc;
! 1936: m68030MMU table(this);
! 1937: table.m_ptest = true;
! 1938: table.search(level);
! 1939:
1.1 root 1940: if (table.m_berr) {
1941: mmusr |= m68030MMUSR::B;
1942: }
1.1.1.8 ! root 1943: if (table.m_l) {
! 1944: // XXX not tested
! 1945: mmusr |= m68030MMUSR::L;
! 1946: }
! 1947: if (table.m_s && (fc & 4)) {
! 1948: // XXX not tested
! 1949: mmusr |= m68030MMUSR::S;
! 1950: }
! 1951: if (table.m_wp) {
! 1952: mmusr |= m68030MMUSR::W;
! 1953: }
! 1954: if (table.m_type == INVALID) {
! 1955: mmusr |= m68030MMUSR::I;
! 1956: }
! 1957: if (table.m_m) {
! 1958: mmusr |= m68030MMUSR::M;
! 1959: }
! 1960: // N を求める。
! 1961: // もともとそういう風には出来ていないので逆算している。
! 1962: int n;
! 1963: if (mmu_tc.fcl) {
! 1964: // たぶんファンクションテーブルで1段消費する? (未確認)
! 1965: if (table.x == FCL) {
! 1966: n = 1;
! 1967: } else {
! 1968: n = table.x + 2;
! 1969: }
! 1970: } else {
! 1971: n = table.x + 1;
! 1972: }
! 1973: mmusr |= n;
! 1974:
! 1975: // アドレスレジスタ指定があれば、最後のディスクリプタアドレスを返す。
! 1976: // rn は有効なら 8-15。
! 1977: if (rn != 0) {
! 1978: // XXX 途中でバスエラーが起きるケースは未実装
! 1979: if (table.m_berr == false) {
! 1980: reg.R[rn] = table.m_lastaddr;
! 1981: }
! 1982: }
1.1 root 1983: }
1984:
1.1.1.8 ! root 1985: SetMMUSR(mmusr);
1.1 root 1986: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.