|
|
1.1 root 1: //
2: // nono
3: // Copyright (C) 2024 nono project
4: // Licensed under nono-license.txt
5: //
6:
7: #include "mpu680x0.h"
8: #include "mainbus.h"
9: #include "m68040mmu.h"
10: #include "m88200.h"
11:
12: // 読み込みのアドレス変換を行う。
13: bool
14: MPU68040Device::TranslateRead()
15: {
16: m68040TT *tt;
17: m68040ATC *atc;
18:
19: putlog(3, "TranslateRead %c.$%08x",
20: (bus.laddr.IsSuper() ? 'S' : 'U'), bus.laddr.Addr());
21:
22: // まず TT をチェック。
23: if (bus.laddr.IsData()) {
24: atc = atc_data.get();
25: tt = CheckTT(mmu_dtt);
26: } else {
27: atc = atc_inst.get();
28: tt = CheckTT(mmu_itt);
29: }
30: if (tt != NULL) {
31: putlog(3, "TranslateRead %s matched", tt->GetName());
32: return true;
33: }
34:
35: // TC がオフならここで終わり。
36: if (__predict_false(mmu_tc->e == false)) {
37: putlog(3, "TranslateRead TC:E OFF");
38: return true;
39: }
40:
41: return LookupATC(*atc);
42: }
43:
44: // 書き込みのアドレス変換を行う。
45: bool
46: MPU68040Device::TranslateWrite()
47: {
48: putlog(3, "TranslateWrite %c.$%08x",
49: (bus.laddr.IsSuper() ? 'S' : 'U'), bus.laddr.Addr());
50:
51: // まず TT をチェック。
52: m68040TT *tt = CheckTT(mmu_dtt);
53: if (tt) {
54: if (tt->w) {
55: putlog(3, "TranslateWrite %s matched (WriteProtected)",
56: tt->GetName());
57: return false;
58: } else {
59: putlog(3, "TranslateWrite %s matched", tt->GetName());
60: return true;
61: }
62: }
63:
64: // TC がオフならここで終わり。
65: if (__predict_false(mmu_tc->e == false)) {
66: putlog(3, "TranslateWrite TC:E OFF");
67: return true;
68: }
69:
70: m68040ATC *atc = atc_data.get();
71: return LookupATC(*atc);
72: }
73:
74: // *TTn にマッチすれば、マッチした方のポインタを返す。
75: // マッチしなければ NULL を返す。
76: m68040TT *
77: MPU68040Device::CheckTT(std::array<std::unique_ptr<m68040TT>, 2>& ttbase) const
78: {
79: for (int n = 0; n < 2; n++) {
80: m68040TT *tt = ttbase[n].get();
81: if (tt->Match(bus.laddr)) {
82: return tt;
83: }
84: }
85: return NULL;
86: }
87:
88: // ATC を検索する。
89: bool
90: MPU68040Device::LookupATC(m68040ATC& atc)
91: {
92: m68040ATCEntry *entry;
93: uint32 tag;
94: uint32 idx;
95: int n;
96:
97: // ATC のタグに使う論理アドレスはページサイズによって区切る位置が変わる。
98: // インデックスは本来タグの比較には使わないが、
99: // 表示の際にはインデックス部分がないとだいぶ意味が分からないのと、
100: // 4KB/page なら 16進数で下から 4桁目をインデックスで補完出来るからいいが
101: // 8KB/page の時にはつらいので、最初からタグに含めておく。
102: //
103: // 3 2 1 0
104: // 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
105: // +-+-------------------------------+-------+-----------------------+
106: // |S| Logical Address (16bit) | Index | Page Offset (4KB/page)|
107: // +-+-------------------------------+-------+-----------------------+
108: // :<-- FC2 + LAddress (+ Index) = 21bit --->:
109: //
110: // +-+-----------------------------+-------+-------------------------+
111: // |S| Logical Address (15bit) | Index | Page Offset (8KB/page)|
112: // +-+-----------------------------+-------+-------------------------+
113: // :<-- FC2 + LAddress (+ Index) = 20bit ->:
114: //
115: // タグはこの位置までシフト(とマスク)したもの。
116: // 3 2 1 0
117: // 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
118: // +-----+-+---------------------------------------+-------------+--+
119: // | 0 |S| Logical Address + Index (19/20bit) : | 0 |~V|
120: // +-----+-+---------------------------------------+-------------+--+
121:
122: idx = (bus.laddr.Addr() >> mmu_tc->tic_shift) & 0xf;
123: tag = (bus.laddr.Get() >> 4) & atc.tag_mask; // FC2+Addr(+Index)
124: m68040ATCSet& set = atc.sets[idx];
125:
126: // このセットから探す。
127: for (n = 0; n < set.entry.size(); n++) {
128: entry = &set.entry[n];
129: if (entry->tag == tag) {
130: if (entry->MatchStatus(bus.laddr)) {
131: // 見付かった。
132: goto found;
133: } else {
134: break;
135: }
136: }
137: }
138:
139: // 空きラインか、空いてなければ生贄を差し出す。
140: n = set.GetEntry();
141: entry = &set.entry[n];
142: entry->tag = tag;
143:
144: // テーブルサーチを行い、エントリを更新する。
145: // (true なら entry を埋めて帰ってきてる)
146: if (Search(entry) == false) {
147: entry->Invalidate();
148: putlog(3, " LookupATC invalid");
149: return false;
150: }
151:
152: // このエントリで再度ステータスが一致するか。(タグは一致している)
153: if (entry->MatchStatus(bus.laddr) == false) {
154: putlog(3, " LookupATC entry not matched");
155: return false;
156: }
157: found:
158: // 見付かったので bus.paddr を更新。
159: set.LRU = m88200CacheSet::TryUseLine(set.LRU, n);
160: uint32 offset = bus.laddr.Addr() & ~mmu_tc->page_mask;
161: bus.paddr.ChangeAddr(entry->paddr | offset);
162: putlog(3, " result $%08x", bus.paddr.Addr());
163: return true;
164: }
165:
166: // laddr がこのエントリの各種ステータスにマッチするか調べる。
167: // タグが一致している状態で呼ぶこと。
168: bool
169: m68040ATCEntry::MatchStatus(busaddr laddr) const
170: {
171: if (IsResident() == false) {
172: return false;
173: }
174: if (laddr.IsSuper() == false && IsSuperProtected()) {
175: return false;
176: }
177: if (laddr.IsWrite() && IsWriteProtected()) {
178: return false;
179: }
180: return true;
181: }
182:
183: // 更新用に空きエントリか、空きがなければどれかを差し出す。
184: int
185: m68040ATCSet::GetEntry() const
186: {
187: for (int i = 0; i < 4; i++) {
188: if (entry[i].IsValid() == false) {
189: return i;
190: }
191: }
192:
193: int oldest = m88200CacheSet::TryGetOldestLine(LRU);
194: return oldest;
195: }
196:
197: // テーブルサーチを行う。
198: // 成功すると entry を埋めて true を返す。
199: // 失敗すると false を返す (呼び出し側で entry を無効にすること)。
200: bool
201: MPU68040Device::Search(m68040ATCEntry *entry)
202: {
203: uint32 base;
204: uint32 idx;
205: uint32 mask;
206: uint32 addr;
207: uint32 desc;
208:
209: busaddr laddr = bus.laddr;
210: bool is_write = laddr.IsWrite();
211:
212: putlog(3, " Search %c.$%08x", (laddr.IsSuper() ? 'S' : 'U'), laddr.Addr());
213:
214: // FC2 からルートポインタを決定。
215: // XXX FC2 なのかこれからアクセスする空間の FC なのか。
216: base = laddr.IsSuper() ? reg.srp40 : reg.urp40;
217:
218: // 第1、第2 レベルのディスクリプタを処理。
219: idx = laddr.Addr() >> 25;
220: mask = 0xfffffe00;
221: for (int lv = 0; lv < 2; lv++) {
222: addr = base + idx * 4;
223: putlog(4, " root=$%08x [$%02x] descaddr=$%08x", base, idx, addr);
224:
225: busdata bd = read_phys_4(addr);
226: if (__predict_false(bd.IsBusErr())) {
227: putlog(4, " BusErr (on read desc)");
228: return false;
229: }
230: desc = bd.Data();
231:
232: if (__predict_false(loglevel >= 4)) {
233: static const char *udtname[] = {
234: "Invalid", "Invalid", "Resident", "Resident",
235: };
236: uint32 dt = desc & m68040MMU::DESC_DT;
237: putlogn(" desc=$%08x %c%c DT%u(%s)", desc,
238: ((desc & m68040MMU::DESC_U) ? 'U' : '-'),
239: ((desc & m68040MMU::DESC_W) ? 'W' : '-'),
240: dt, udtname[dt]);
241: }
242:
243: // UDT はビット1 が %0 なら無効。
244: if ((desc & 2) == 0) {
245: putlog(4, " invalid");
246: return false;
247: }
248:
249: // U が立ってなければ U を立てて更新。
250: if ((desc & m68040MMU::DESC_U) == 0) {
251: desc |= m68040MMU::DESC_U;
252: bd = write_phys_4(addr, desc);
253: if (__predict_false(bd.IsBusErr())) {
254: putlog(4, " BusErr (on writeback U)");
255: return false;
256: }
257: }
258:
259: if (__predict_false(is_write) && (desc & m68040MMU::DESC_W)) {
260: putlog(4, " write protected");
261: return false;
262: }
263:
264: // 次の段へ。
265: base = desc & mask;
266: idx = (laddr.Addr() >> 18) & 0x7f;
267: mask = mmu_tc->table_mask;
268: }
269:
270: // ページディスクリプタを処理。
271: idx = (laddr.Addr() >> mmu_tc->tic_shift) & mmu_tc->tic_mask;
272: addr = base + idx * 4;
273: putlog(4, " root=$%08x [$%02x] descaddr=$%08x", base, idx, addr);
274: busdata bd = read_phys_4(addr);
275: if (__predict_false(bd.IsBusErr())) {
276: putlog(4, " BusErr (on read desc)");
277: return false;
278: }
279: desc = bd.Data();
280: uint32 pdt = desc & m68040MMU::DESC_DT;
281:
282: if (__predict_false(loglevel >= 4)) {
283: static const char *pdtname[] = {
284: "Invalid", "Resident", "Indirect", "Resident",
285: };
286: putlogn(" desc=$%08x %c%c%c%c%c CM%u DT%u(%s)", desc,
287: ((desc & m68040MMU::DESC_G) ? 'G' : '-'),
288: ((desc & m68040MMU::DESC_S) ? 'S' : '-'),
289: ((desc & m68040MMU::DESC_M) ? 'M' : '-'),
290: ((desc & m68040MMU::DESC_U) ? 'U' : '-'),
291: ((desc & m68040MMU::DESC_W) ? 'W' : '-'),
292: ((desc & m68040MMU::DESC_CM) >> 5),
293: pdt, pdtname[pdt]);
294: }
295:
296: // PDT は %00 なら無効。
297: if (__predict_false(pdt == m68040MMU::PDT_INVALID)) {
298: putlog(4, " invalid");
299: return false;
300: } else if (__predict_false(pdt == m68040MMU::PDT_INDIRECT)) {
301: PANIC("indirect descriptor");
302: }
303:
304: if (__predict_true(is_write == false)) {
305: // 読み込みなら、U を立てるかどうか。
306: if ((desc & m68040MMU::DESC_U) == 0) {
307: desc |= m68040MMU::DESC_U;
308: bd = write_phys_4(addr, desc);
309: if (__predict_false(bd.IsBusErr())) {
310: putlog(4, " BusErr (on writeback U)");
311: return false;
312: }
313: }
314: } else {
315: // 書き込みなら、U と M と WP。
316: uint32 olddesc = desc;
317: if ((desc & m68040MMU::DESC_U) == 0) {
318: desc |= m68040MMU::DESC_U;
319: }
320: if ((desc & (m68040MMU::DESC_M | m68040MMU::DESC_W)) == 0) {
321: desc |= m68040MMU::DESC_M;
322: }
323: if (olddesc != desc) {
324: bd = write_phys_4(addr, desc);
325: if (__predict_false(bd.IsBusErr())) {
326: putlog(4, " BusErr (on writeback U)");
327: return false;
328: }
329: }
330:
331: if ((desc & m68040MMU::DESC_W)) {
332: putlog(4, " write protected");
333: return false;
334: }
335: }
336:
337: entry->paddr = desc & mmu_tc->page_mask;
338: entry->desc = desc;
339: putlog(3, " frame addr $%08x", entry->paddr);
340: return true;
341: }
342:
343: // ピーク用のアドレス変換を行う。
344: // 変換できれば対応する物理アドレスを、バスエラーなら BusErr を返す。
345: // テーブルサーチを行ったら TableSearched ビットを立てる。
346: busaddr
347: MPU68040Device::TranslatePeek(busaddr laddr)
348: {
349: const m68040TT *tt;
350:
351: // TT を自前でサーチ。
352: if (laddr.IsData()) {
353: tt = CheckTT(mmu_dtt);
354: } else {
355: tt = CheckTT(mmu_itt);
356: }
357: if (__predict_false(tt != NULL)) {
358: if (tt->Match(laddr)) {
359: return laddr;
360: }
361: }
362:
363: if (__predict_false(mmu_tc->e == false)) {
364: return laddr;
365: }
366:
367: // ATC を自前でサーチ。
368: const m68040ATC *atc;
369: if (laddr.IsData()) {
370: atc = atc_data.get();
371: } else {
372: atc = atc_inst.get();
373: }
374: uint32 idx = (laddr.Addr() >> mmu_tc->tic_shift) & 0xf;
375: uint32 tag = (laddr.Get() >> 4) & atc->tag_mask; // FC2+Addr(+Index)
376: const m68040ATCSet& set = atc->sets[idx];
377: for (const auto& entry : set.entry) {
378: if (entry.tag == tag) {
379: if (entry.MatchStatus(laddr)) {
380: // 見付かった。
381: uint32 offset = laddr.Addr() & ~mmu_tc->page_mask;
382: laddr.ChangeAddr(entry.paddr | offset);
383: return laddr;
384: } else {
385: break;
386: }
387: }
388: }
389:
390: // ATC になければ、テーブルサーチ相当を自前で行う。
391: laddr |= BusAddr::TableSearched;
392: bool is_write = laddr.IsWrite();
393: uint32 desc;
394:
395: // FC2 からルートポインタを決定。
396: uint32 base = laddr.IsSuper() ? reg.srp40 : reg.urp40;
397:
398: // 第1レベル。
399: idx = laddr.Addr() >> 25;
400: desc = PeekDesc(base, idx);
401: // UDT はビット1 が %0 なら無効。
402: if ((desc & 2) == 0) {
403: return BusAddr::BusErr;
404: }
405: if (__predict_false(is_write) && (desc & 4)) {
406: return BusAddr::BusErr;
407: }
408: base = desc & 0xfffffe00;
409:
410: // 第2レベル。
411: idx = (laddr.Addr() >> 18) & 0x7f;
412: desc = PeekDesc(base, idx);
413: // UDT はビット1 が %0 なら無効。
414: if ((desc & 2) == 0) {
415: return BusAddr::BusErr;
416: }
417: if (__predict_false(is_write) && (desc & 4)) {
418: return BusAddr::BusErr;
419: }
420: base = desc & mmu_tc->table_mask;
421:
422: // ページディスクリプタ。
423: idx = (laddr.Addr() >> mmu_tc->tic_shift) & mmu_tc->tic_mask;
424: desc = PeekDesc(base, idx);
425: // PDT は %00 なら無効。
426: uint32 pdt = desc & m68040MMU::DESC_DT;
427: if (pdt == m68040MMU::PDT_INVALID) {
428: return BusAddr::BusErr;
429: } else if (__predict_false(pdt == m68040MMU::PDT_INDIRECT)) {
430: PANIC("indirect descriptor");
431: }
432: if (__predict_false(is_write) && (desc & 4)) {
433: return BusAddr::BusErr;
434: }
435:
436: uint32 paddr = (desc & mmu_tc->page_mask)
437: | (laddr.Addr() & ~mmu_tc->page_mask);
438: laddr.ChangeAddr(paddr);
439: return laddr;
440: }
441:
442: // base[idx] からディスクリプタを副作用なく読み出す。(デバッガ用)
443: // U フラグは更新しない。
444: // バスエラーが起きれば 0 を返す (ディスクリプタの下位2ビットが %00 なら
445: // 無効を示すので)。
446: uint32
447: MPU68040Device::PeekDesc(uint32 base, uint32 idx)
448: {
449: uint32 addr = base + idx * 4;
450: uint64 data = mainbus->Peek4(addr);
451: if ((int64)data < 0) {
452: return 0;
453: }
454: return data;
455: }
456:
457: // 現在の TC:E、TT:E の状態に応じてアドレス変換の有無を切り替える。
458: // mmu_enable ならアドレス変換ありのバスアクセスを使う。see m68030bus.cpp
459: void
460: MPU68040Device::mmu_enable_changed()
461: {
462: bool enable;
463:
464: // TC、ITT*、DTT* のいずれかが有効ならアドレス変換あり。
465: enable = (reg.tc40 & m68040TC::E);
466: enable |= mmu_itt[0]->e || mmu_itt[1]->e;
467: enable |= mmu_dtt[0]->e || mmu_dtt[1]->e;
468:
469: // 変化した時だけ
470: if (mmu_enable && !enable) {
471: // 無効にする
472: mmu_enable = false;
473: putlog(1, "MMU Translation Disabled");
474: } else if (!mmu_enable && enable) {
475: // 有効にする
476: mmu_enable = true;
477: putlog(1, "MMU Translation Enabled");
478: }
479: }
480:
481: // *TTn レジスタへの書き込み。
482: void
483: MPU68040Device::SetTT(m68040TT *tt, uint32 data)
484: {
485: *tt->reg = (data & m68040TT::MASK);
486: putlog(1, "%s <- $%08x", tt->GetName(), *tt->reg);
487:
488: tt->base = (data & m68040TT::LBASE_MASK);
489: tt->mask = (~data & m68040TT::LMASK_MASK) << 8;
490: tt->e = (data & m68040TT::E);
491: tt->s_ign = (data & m68040TT::S_IGN);
492: tt->s_fc2 = (data & m68040TT::S_FC2);
493: tt->u = (data & m68040TT::U_MASK);
494: tt->cm = (data & m68040TT::CM) >> 5;
495: tt->w = (data & m68040TT::W);
496:
497: mmu_enable_changed();
498: }
499:
500: void
501: MPU68040Device::SetSRP(uint32 data)
502: {
503: // とりあえず
504: reg.srp40 = data & m68040RP::ADDR_MASK;
505: putlog(1, "SRP <- $%08x", reg.srp40);
506: }
507:
508: void
509: MPU68040Device::SetURP(uint32 data)
510: {
511: // とりあえず
512: reg.urp40 = data & m68040RP::ADDR_MASK;
513: putlog(1, "URP <- $%08x", reg.urp40);
514: }
515:
516: void
517: MPU68040Device::SetTC(uint32 data)
518: {
519: // とりあえず
520: reg.tc40 = data & m68040TC::MASK;
521: putlog(1, "TC <- $%04x", reg.tc40);
522:
523: mmu_tc->e = reg.tc40 & m68040TC::E;
524: if ((reg.tc40 & m68040TC::P) == 0) {
525: // 4KB/page
526: mmu_tc->ps4k = true;
527: mmu_tc->table_mask = 0xffffff00;
528: mmu_tc->tic_shift = 12;
529: mmu_tc->tic_mask = 0x0000003f;
530: mmu_tc->page_mask = 0xfffff000;
531: } else {
532: // 8KB/page
533: mmu_tc->ps4k = false;
534: mmu_tc->table_mask = 0xffffff80;
535: mmu_tc->tic_shift = 13;
536: mmu_tc->tic_mask = 0x0000001f;
537: mmu_tc->page_mask = 0xffffe000;
538: }
539:
540: // ページサイズと連動している ATC の変数もセット。
541: uint32 tag_mask = (mmu_tc->page_mask >> 4) | 0x1000'0000;
542: atc_inst->tag_mask = tag_mask;
543: atc_data->tag_mask = tag_mask;
544:
545: mmu_enable_changed();
546: }
547:
548: // リセット例外の CPU 固有部分。
549: void
550: MPU68040Device::ResetMMU()
551: {
552: mmu_tc->e = false;
553: mmu_itt[0]->e = false;
554: mmu_itt[1]->e = false;
555: mmu_dtt[0]->e = false;
556: mmu_dtt[1]->e = false;
557:
558: // ATC は影響を受けない。
559: }
560:
561: // *TT
562:
563: // コンストラクタ
564: m68040TT::m68040TT(const char *name_, uint32 *reg_)
565: {
566: name = name_;
567: reg = reg_;
568: }
569:
570: // デストラクタ
571: m68040TT::~m68040TT()
572: {
573: }
574:
575: // addr がマッチすれば true を返す。
576: bool
577: m68040TT::Match(busaddr addr) const
578: {
579: if (__predict_true(e == false)) {
580: return false;
581: }
582: if (s_ign == false) {
583: if (addr.IsSuper() != s_fc2) {
584: return false;
585: }
586: }
587: if ((addr.Addr() & mask) != base) {
588: return false;
589: }
590:
591: // 一致した。
592: return true;
593: }
594:
595: // ATC
596:
597: // ATC の指定の権限空間をすべて無効にする。
598: void
599: m68040ATC::Flush(bool s, bool only_non_global)
600: {
601: uint32 target = s ? 0x1000'0000 : 0;
602:
603: // G only_non_global
604: // --- ---
605: // 0 0 invalidate
606: // 0 1 invalidate
607: // 1 0 invalidate
608: // 1 1 nop
609:
610: for (auto& set : sets) {
611: for (auto& entry : set.entry) {
612: // S/U と Valid ビットのみ比較。
613: if ((entry.tag & 0x1000'0001) == target) {
614: if (only_non_global == false || entry.IsGlobal() == false) {
615: entry.Invalidate();
616: }
617: }
618: }
619: }
620: }
621:
622: // ATC の指定の空間+アドレスを無効にする。
623: void
624: m68040ATC::Flush(busaddr addr, bool only_non_global)
625: {
626: uint32 tag = (addr.Get() >> 4) & tag_mask;
627:
628: for (auto& set : sets) {
629: for (auto& entry : set.entry) {
630: // S/U、アドレス、Valid ビットすべてを比較。
631: if (entry.tag == tag) {
632: if (only_non_global == false || entry.IsGlobal() == false) {
633: entry.Invalidate();
634: }
635: }
636: }
637: }
638: }
639:
640: // モニター更新 (68040 ATC)
641: void
642: MPU68040Device::MonitorUpdateATC(Monitor *, TextScreen& screen)
643: {
644: int x = 62;
645:
646: // 0 1 2 3 4 5
647: // 012345678901234567890123456789012345678901234567890123456789
648: // IDX TagAddr PAddr Stat IDX TagAddr PAddr Stat
649: // [0] S.12345'000 12345'000 --- [1] S.12345'000 12345'000 ---
650:
651: screen.Clear();
652: screen.Puts(0, 0, "<Data ATC>");
653: screen.Puts(x, 0, "<Instruction ATC>");
654: for (int i = 0; i < 4; i++) {
655: screen.Puts(i * 30 + (i & 2), 1, "IDX TagAddr PAddr Stat");
656: }
657: MonitorUpdateATC1(screen, 0, atc_data.get());
658: MonitorUpdateATC1(screen, x, atc_inst.get());
659: }
660:
661: void
662: MPU68040Device::MonitorUpdateATC1(TextScreen& screen, int x,
663: const m68040ATC *atc)
664: {
665: int y = 2;
666:
667: for (uint i = 0; i < atc->sets.size(); i++) {
668: const m68040ATCSet& set = atc->sets[i];
669: screen.Print(x, y, "[%x]", i);
670:
671: // 古い順に取り出して 3-0 の順序をつける。(新しい順に表示するため)
672: int order[4];
673: uint tmpL = set.LRU;
674: for (int j = 3; j >= 0; j--) {
675: int line = m88200CacheSet::TryGetOldestLine(tmpL);
676: order[j] = line;
677: tmpL = m88200CacheSet::TryUseLine(tmpL, line);
678: }
679:
680: for (int j = 0; j < set.entry.size(); j++) {
681: int line = order[j];
682: const m68040ATCEntry& entry = set.entry[line];
683: TA attr = entry.IsValid() ? TA::Normal : TA::Disable;
684: screen.Print(x + 4, y, attr,
685: "%c.%05x'000 %05x'000 %c%c%c",
686: (entry.IsSuper() ? 'S' : 'U'),
687: ((entry.tag >> 8) & 0xfffff),
688: entry.paddr >> 12,
689: ((entry.desc & m68040MMU::DESC_G) ? 'G' : '-'),
690: ((entry.desc & m68040MMU::DESC_S) ? 'S' : '-'),
691: ((entry.desc & m68040MMU::DESC_W) ? 'W' : '-'));
692: y++;
693: }
694:
695: if (i == 7) {
696: x += 30;
697: y = 2;
698: }
699: }
700: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.