|
|
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 "m68040mmu.h"
9:
10: uint32
11: MPU68040Device::fetch_2()
12: {
13: busaddr addr = busaddr(reg.pc) | fc_inst | BusAddr::Size2;
14: busdata bd = read_data(addr);
15: reg.pc += 2;
16: return bd.Data();
17: }
18:
19: uint32
20: MPU68040Device::fetch_4()
21: {
22: busaddr addr = busaddr(reg.pc) | fc_inst | BusAddr::Size4;
23: busdata bd = read_data(addr);
24: reg.pc += 4;
25: return bd.Data();
26: }
27:
28: // read_1,2,4() の共通部分。ミスアライン可。
29: // バスエラーが起きると例外 M68K::EXCEP_BUSERR をスローする。
30: uint32
31: MPU68040Device::read_data(busaddr addr)
32: {
33: busdata data = read_nocache(addr);
34: if (__predict_false(data.IsBusErr())) {
35: bus.laddr = addr;
36: bus.size = addr.GetSize();
37: throw M68K::EXCEP_BUSERR;
38: }
39: return data.Data();
40: }
41:
42: // キャッシュ無効時の読み込み。ミスアライン可。
43: // バスエラーも busdata を返す。
44: busdata
45: MPU68040Device::read_nocache(busaddr addr)
46: {
47: // デバイスは、addr の下位ビットによらず、自身のデバイスのポートサイズ分
48: // のデータと、その応答サイズ(自分のポートサイズ) を Size フィールドに
49: // セットして返してくる。
50: //
51: // MPU(68040) は、A1-A0、残りバイト数、デバイスの応答サイズの情報から
52: // 受け取ったデータバスのうち適切なところを切り出して使う。
53:
54: bool span_page = false;
55: uint32 data = 0;
56: for (;;) {
57: bus.laddr = addr;
58: bus.paddr = addr;
59: if (__predict_false(TranslateRead() == false)) {
60: bus.atcfault = true;
61: // ATC フォールトが2ページ目で起きたか。
62: bus.atcfault2 = span_page;
63: return BusData::BusErr;
64: }
65: busdata bd = read_phys();
66: if (__predict_false(bd.IsBusErr())) {
67: return bd;
68: }
69:
70: uint32 reqsize = addr.GetSize();
71: // デバイスのポートサイズ(応答サイズ)
72: uint32 portsize = bd.GetSize();
73: // 今回のアドレスオフセット
74: uint32 offset = addr.Addr() & (portsize - 1);
75: uint32 datasize = portsize - offset;
76: uint32 tmp = bd.Data();
77: // 下詰めされたデータに対するマスク
78: uint32 mask = 0xffffffffU >> ((4 - datasize) * 8);
79: // 今回必要なところ
80: tmp &= mask;
81: if (datasize == reqsize) {
82: data |= tmp;
83: break;
84: } else if (datasize > reqsize) {
85: tmp >>= (datasize - reqsize) * 8;
86: data |= tmp;
87: break;
88: } else {
89: tmp <<= (reqsize - datasize) * 8;
90: data |= tmp;
91: }
92:
93: uint32 oldaddr = addr.Addr();
94: addr += datasize;
95: reqsize -= datasize;
96: addr.ChangeSize(reqsize);
97:
98: if (__predict_false(((addr.Addr() ^ oldaddr) & ~mmu_tc->page_mask))) {
99: span_page = true;
100: }
101: }
102: return data;
103: }
104:
105: // write_1,2,4() の共通部分。ミスアライン可。
106: // バスエラーが起きると例外 M68K::EXCEP_BUSERR をスローする。
107: void
108: MPU68040Device::write_data(busaddr addr, uint32 data)
109: {
110: busaddr origaddr = addr;
111: uint32 origdata = data;
112:
113: bool span_page = false;
114: for (;;) {
115: bus.laddr = addr;
116: bus.paddr = addr;
117: if (__predict_false(TranslateWrite() == false)) {
118: bus.atcfault = true;
119: // ATC フォールトが2ページ目で起きたか。
120: bus.atcfault2 = span_page;
121: break;
122: }
123: busdata bd = write_phys(data);
124: if (__predict_false(bd.IsBusErr())) {
125: break;
126: }
127: uint32 reqsize = addr.GetSize();
128: uint32 portsize = bd.GetSize();
129: uint32 offset = addr.Addr() & (portsize - 1);
130: uint32 datasize = portsize - offset;
131: if (datasize >= reqsize) {
132: // ここが成功して終了。
133: return;
134: }
135:
136: addr += datasize;
137: reqsize -= datasize;
138: addr.ChangeSize(reqsize);
139: data &= (1U << (reqsize * 8)) - 1;
140:
141: if (((addr.Addr() ^ origaddr.Addr()) & ~mmu_tc->page_mask) != 0) {
142: span_page = true;
143: }
144: }
145:
146: // 報告するのは先頭のアドレス。
147: bus.laddr.ChangeAddr(origaddr.Addr());
148: bus.size = origaddr.GetSize();
149: bus.data = origdata;
150: throw M68K::EXCEP_BUSERR;
151: }
152:
153: // CACR レジスタ書き込み。
154: void
155: MPU68040Device::SetCACR(uint32 data)
156: {
157: // とりあえず
158: reg.cacr = data & M68040::CACR_MASK;
159: }
160:
161: // リセット例外の CPU 固有部分。
162: void
163: MPU68040Device::ResetCache()
164: {
165: SetCACR(0);
166: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.