|
|
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 root 7: // 論理アクセス
8:
9: //
10: // 1回の(アラインド)物理アクセスを担当するマクロ。
11: // これらは続く _mmu テンプレートで使用する。
12: // goto を含むことに注意。gcc 拡張式(?)に注意。
1.1.1.2 root 13: // mmu_translate_* は fetch, read, write の3種だが、vm_phys_ は
1.1 root 14: // read, write しかないことに注意。物理バスに FC0 と FC1、つまりプログラム
15: // 空間かどうかの情報は出していないため。
16: //
17:
18: #define FETCH(size) ({ \
19: cpu->bus.paddr = cpu->bus.laddr; \
20: if (use_mmu && m68030_mmu_translate_fetch(cpu) == false) \
21: goto buserr; \
1.1.1.2 root 22: uint64 data_ = vm_phys_read_##size(cpu->bus.paddr); \
1.1 root 23: if ((int64)data_ < 0) \
24: goto buserr; \
25: data_; /* これが戻り値 */ \
26: })
27:
28: #define READ(size) ({ \
29: cpu->bus.paddr = cpu->bus.laddr; \
30: if (use_mmu && m68030_mmu_translate_read(cpu) == false) \
31: goto buserr; \
1.1.1.2 root 32: uint64 data_ = vm_phys_read_##size(cpu->bus.paddr); \
1.1 root 33: if ((int64)data_ < 0) \
34: goto buserr; \
35: data_; /* これが戻り値 */ \
36: })
37:
38: #define WRITE(size, data) ({ \
39: cpu->bus.paddr = cpu->bus.laddr; \
40: if (use_mmu && m68030_mmu_translate_write(cpu) == false) \
41: goto buserr; \
1.1.1.2 root 42: int64 berr_ = vm_phys_write_##size(cpu->bus.paddr, (data)); \
1.1 root 43: if (berr_ < 0) \
44: goto buserr; \
45: 0; /* 戻り値不要だけど一応 */ \
46: })
47:
48: // バスエラー時に SSW をセットする。
49: // m68030_*_NN_mmu() 関数の下請け。
50: static inline void
51: SET_SSW(m68kcpu *cpu, bool use_mmu, uint size)
52: {
53: // サイズを設定
54: cpu->bus.ssw &= ~SSW_SIZE_MASK;
55: cpu->bus.ssw |= size;
56:
57: if (use_mmu) {
58: // データアクセスなら再試行のため DataFault ビットをセット。
59: // 命令アクセスなら RB をセット。
60: if ((cpu->bus.ssw & FC_DATA)) {
61: cpu->bus.ssw |= SSW_DF;
62: } else {
63: cpu->bus.ssw |= SSW_RB;
64: }
65: }
66: }
67:
68: //
69: // MMU を考慮した下請けテンプレート。
70: // 1回分のミスアラインドありのアクセスを担当。
71: //
72:
73: template<bool use_mmu> uint32
74: m68030_fetch_16_mmu(m68kcpu *cpu)
75: {
76: uint64 data;
77:
78: data = FETCH(16);
79: // XXX バスエラー時に PC をインクリメントするタイミングは?
80: RegPC += 2;
81:
82: return data;
83:
84: buserr:
85: SET_SSW(cpu, use_mmu, SSW_SIZE_WORD);
86: throw M68K_EXCEP_BUSERR;
87: }
88:
89: template<bool use_mmu> uint32
90: m68030_fetch_32_mmu(m68kcpu *cpu)
91: {
92: uint64 data;
93:
94: if ((cpu->bus.laddr & 3) == 0) {
95: data = FETCH(32);
96: } else {
97: uint64 h, l;
98:
99: h = FETCH(16);
100: cpu->bus.laddr += 2;
101:
102: l = FETCH(16);
103: data = (h << 16) | l;
104: }
105: // XXX バスエラー時に PC をインクリメントするタイミングは?
106: RegPC += 4;
107: return data;
108:
109: buserr:
110: SET_SSW(cpu, use_mmu, SSW_SIZE_LONG);
111: throw M68K_EXCEP_BUSERR;
112: }
113:
114: template<bool use_mmu> uint32
115: m68030_read_8_mmu(m68kcpu *cpu)
116: {
117: uint64 data;
118:
119: data = READ(8);
120:
121: if (1)
122: cpulog(2, "m68030_read_8 %08X -> %02X", cpu->bus.laddr, (uint32)data);
123: return data;
124:
125: buserr:
126: SET_SSW(cpu, use_mmu, SSW_SIZE_BYTE);
127: throw M68K_EXCEP_BUSERR;
128: }
129:
130: template<bool use_mmu> uint32
131: m68030_read_16_mmu(m68kcpu *cpu)
132: {
133: uint64 data;
134:
135: if ((cpu->bus.laddr & 1) == 0) {
136: data = READ(16);
137: } else {
138: uint64 h, l;
139:
140: h = READ(8);
141: cpu->bus.laddr += 1;
142:
143: l = READ(8);
144: data = (h << 8) | l;
145: }
146:
147: if (1)
148: cpulog(2, "m68030_read_16 %08X -> %04X", cpu->bus.laddr, (uint32)data);
149: return data;
150:
151: buserr:
152: SET_SSW(cpu, use_mmu, SSW_SIZE_WORD);
153: throw M68K_EXCEP_BUSERR;
154: }
155:
156: template<bool use_mmu> uint32
157: m68030_read_32_mmu(m68kcpu *cpu)
158: {
159: uint64 data;
160:
161: if ((cpu->bus.laddr & 3) == 0) {
162: data = READ(32);
163: } else if ((cpu->bus.laddr & 1) == 0) {
164: uint64 h, l;
165:
166: h = READ(16);
167: cpu->bus.laddr += 2;
168:
169: l = READ(16);
170: data = (h << 16) | l;
171: } else {
172: uint64 h, m, l;
173:
174: h = READ(8);
175: cpu->bus.laddr += 1;
176:
177: m = READ(16);
178: cpu->bus.laddr += 2;
179:
180: l = READ(8);
181: data = (h << 24) | (m << 8) | l;
182: }
183:
184: if (1)
185: cpulog(2, "m68030_read_32 %08X -> %08X", cpu->bus.laddr, (uint32)data);
186: return data;
187:
188: buserr:
189: SET_SSW(cpu, use_mmu, SSW_SIZE_LONG);
190: throw M68K_EXCEP_BUSERR;
191: }
192:
193: template<bool use_mmu> void
194: m68030_write_8_mmu(m68kcpu *cpu)
195: {
196: uint32 data = cpu->bus.data;
197:
198: if (1)
199: cpulog(2, "m68030_write_8 %08X <- %02X", cpu->bus.laddr, data);
200:
201: WRITE(8, data);
202: return;
203:
204: buserr:
205: SET_SSW(cpu, use_mmu, SSW_SIZE_BYTE);
206: throw M68K_EXCEP_BUSERR;
207: }
208:
209: template<bool use_mmu> void
210: m68030_write_16_mmu(m68kcpu *cpu)
211: {
212: uint32 data = cpu->bus.data;
213:
214: if (1)
215: cpulog(2, "m68030_write_16 %08X <- %04X", cpu->bus.laddr, data);
216:
217: if ((cpu->bus.laddr & 1) == 0) {
218: WRITE(16, data);
219: } else {
220: WRITE(8, data >> 8);
221:
222: cpu->bus.laddr += 1;
223: WRITE(8, data & 0xff);
224: }
225: return;
226:
227: buserr:
228: SET_SSW(cpu, use_mmu, SSW_SIZE_WORD);
229: throw M68K_EXCEP_BUSERR;
230: }
231:
232: template<bool use_mmu> void
233: m68030_write_32_mmu(m68kcpu *cpu)
234: {
235: uint32 data = cpu->bus.data;
236:
237: if (1)
238: cpulog(2, "m68030_write_32 %08X <- %08X", cpu->bus.laddr, data);
239:
240: if ((cpu->bus.laddr & 3) == 0) {
241: WRITE(32, data);
242: } else if ((cpu->bus.laddr & 1) == 0) {
243: WRITE(16, data >> 16);
244:
245: cpu->bus.laddr += 2;
246: WRITE(16, data & 0xffff);
247: } else {
248: WRITE(8, data >> 24);
249:
250: cpu->bus.laddr += 1;
251: WRITE(16, (data >> 8) & 0xffff);
252:
253: cpu->bus.laddr += 2;
254: WRITE(8, data & 0xff);
255: }
256: return;
257:
258: buserr:
259: SET_SSW(cpu, use_mmu, SSW_SIZE_LONG);
260: throw M68K_EXCEP_BUSERR;
261: }
262:
263: // m68030_{fetch,read,write}_NN() と m68030_{read,write}_NN_fc() の共通部分。
264: // fetch には FC 指定版はないので分ける必要は本来ないけど対称性のため。
265: // cpu->bus に必要な情報はセットされている。
266: // _bus 接尾辞はバスアクセスというより bus 構造体を使ったアクセスという感じ。
267:
268: static inline uint32
269: m68030_fetch_16_bus(m68kcpu *cpu)
270: {
271: if (cpu->mmu_enable) {
272: return m68030_fetch_16_mmu<true>(cpu);
273: } else {
274: return m68030_fetch_16_mmu<false>(cpu);
275: }
276: }
277:
278: static inline uint32
279: m68030_fetch_32_bus(m68kcpu *cpu)
280: {
281: if (cpu->mmu_enable) {
282: return m68030_fetch_32_mmu<true>(cpu);
283: } else {
284: return m68030_fetch_32_mmu<false>(cpu);
285: }
286: }
287:
288: static uint32
289: m68030_read_8_bus(m68kcpu *cpu)
290: {
291: if(1)cpulog(2, "%s $%08x", __func__, cpu->bus.laddr);
292: if (cpu->mmu_enable) {
293: return m68030_read_8_mmu<true>(cpu);
294: } else {
295: return m68030_read_8_mmu<false>(cpu);
296: }
297: }
298:
299: static uint32
300: m68030_read_16_bus(m68kcpu *cpu)
301: {
302: if(1)cpulog(2, "%s $%08x", __func__, cpu->bus.laddr);
303: if (cpu->mmu_enable) {
304: return m68030_read_16_mmu<true>(cpu);
305: } else {
306: return m68030_read_16_mmu<false>(cpu);
307: }
308: }
309:
310: static uint32
311: m68030_read_32_bus(m68kcpu *cpu)
312: {
313: if(1)cpulog(2, "%s $%08x", __func__, cpu->bus.laddr);
314: if (cpu->mmu_enable) {
315: return m68030_read_32_mmu<true>(cpu);
316: } else {
317: return m68030_read_32_mmu<false>(cpu);
318: }
319: }
320:
321: static void
322: m68030_write_8_bus(m68kcpu *cpu)
323: {
324: if(1)cpulog(2, "%s $%08x", __func__, cpu->bus.laddr);
325: if (cpu->mmu_enable) {
326: m68030_write_8_mmu<true>(cpu);
327: } else {
328: m68030_write_8_mmu<false>(cpu);
329: }
330: }
331:
332: static void
333: m68030_write_16_bus(m68kcpu *cpu)
334: {
335: if(1)cpulog(2, "%s $%08x", __func__, cpu->bus.laddr);
336: if (cpu->mmu_enable) {
337: m68030_write_16_mmu<true>(cpu);
338: } else {
339: m68030_write_16_mmu<false>(cpu);
340: }
341: }
342:
343: static void
344: m68030_write_32_bus(m68kcpu *cpu)
345: {
346: if(1)cpulog(2, "%s $%08x", __func__, cpu->bus.laddr);
347: if (cpu->mmu_enable) {
348: m68030_write_32_mmu<true>(cpu);
349: } else {
350: m68030_write_32_mmu<false>(cpu);
351: }
352: }
353:
354: //
355: // CPU 内部からのメモリアクセスは常にこの8つ (またはこれを呼び出すヘルパー
356: // 関数) を呼ぶこと。
357: // uint32 m68030_fetch_{16,32}(cpu)
358: // uint32 m68030_read_{8,16,32}(cpu, laddr)
359: // void m68030_write_{8,16,32}(cpu, laddr, data)
360: //
361:
362: uint32
363: m68030_fetch_16(m68kcpu *cpu)
364: {
365: cpu->bus.ssw = SSW_BUS_R | cpu->bus.fc2 | FC_PROG;
366: cpu->bus.laddr = RegPC;
367: return m68030_fetch_16_bus(cpu);
368: }
369:
370: uint32
371: m68030_fetch_32(m68kcpu *cpu)
372: {
373: cpu->bus.ssw = SSW_BUS_R | cpu->bus.fc2 | FC_PROG;
374: cpu->bus.laddr = RegPC;
375: return m68030_fetch_32_bus(cpu);
376: }
377:
378: uint32
379: m68030_read_8(m68kcpu *cpu, uint32 addr)
380: {
381: cpu->bus.ssw = SSW_BUS_R | cpu->bus.fc2 | FC_DATA;
382: cpu->bus.laddr = addr;
383: return m68030_read_8_bus(cpu);
384: }
385:
386: uint32
387: m68030_read_16(m68kcpu *cpu, uint32 addr)
388: {
389: cpu->bus.ssw = SSW_BUS_R | cpu->bus.fc2 | FC_DATA;
390: cpu->bus.laddr = addr;
391: return m68030_read_16_bus(cpu);
392: }
393:
394: uint32
395: m68030_read_32(m68kcpu *cpu, uint32 addr)
396: {
397: cpu->bus.ssw = SSW_BUS_R | cpu->bus.fc2 | FC_DATA;
398: cpu->bus.laddr = addr;
399: return m68030_read_32_bus(cpu);
400: }
401:
402: void
403: m68030_write_8(m68kcpu *cpu, uint32 addr, uint32 data)
404: {
405: cpu->bus.ssw = SSW_BUS_W | cpu->bus.fc2 | FC_DATA;
406: cpu->bus.laddr = addr;
407: cpu->bus.data = data;
408: m68030_write_8_bus(cpu);
409: }
410:
411: void
412: m68030_write_16(m68kcpu *cpu, uint32 addr, uint32 data)
413: {
414: cpu->bus.ssw = SSW_BUS_W | cpu->bus.fc2 | FC_DATA;
415: cpu->bus.laddr = addr;
416: cpu->bus.data = data;
417: m68030_write_16_bus(cpu);
418: }
419:
420: void
421: m68030_write_32(m68kcpu *cpu, uint32 addr, uint32 data)
422: {
423: cpu->bus.ssw = SSW_BUS_W | cpu->bus.fc2 | FC_DATA;
424: cpu->bus.laddr = addr;
425: cpu->bus.data = data;
426: m68030_write_32_bus(cpu);
427: }
428:
429: //
430: // MOVES 用の FC 指定版。
431: // 通常アクセスが現在の FC 空間に対してだが、
432: // こちらは SFC/DFC で指定された FC 空間に対してアクセスする。
433: //
434:
435: uint32
436: m68030_read_8_fc(m68kcpu *cpu, uint32 addr)
437: {
438: cpu->bus.ssw = SSW_BUS_R | RegSFC;
439: cpu->bus.laddr = addr;
440: return m68030_read_8_bus(cpu);
441: }
442:
443: uint32
444: m68030_read_16_fc(m68kcpu *cpu, uint32 addr)
445: {
446: cpu->bus.ssw = SSW_BUS_R | RegSFC;
447: cpu->bus.laddr = addr;
448: return m68030_read_16_bus(cpu);
449: }
450:
451: uint32
452: m68030_read_32_fc(m68kcpu *cpu, uint32 addr)
453: {
454: cpu->bus.ssw = SSW_BUS_R | RegSFC;
455: cpu->bus.laddr = addr;
456: return m68030_read_32_bus(cpu);
457: }
458:
459: void
460: m68030_write_8_fc(m68kcpu *cpu, uint32 addr, uint32 data)
461: {
462: cpu->bus.ssw = SSW_BUS_W | RegDFC;
463: cpu->bus.laddr = addr;
464: cpu->bus.data = data;
465: m68030_write_8_bus(cpu);
466: }
467:
468: void
469: m68030_write_16_fc(m68kcpu *cpu, uint32 addr, uint32 data)
470: {
471: cpu->bus.ssw = SSW_BUS_W | RegDFC;
472: cpu->bus.laddr = addr;
473: cpu->bus.data = data;
474: m68030_write_16_bus(cpu);
475: }
476:
477: void
478: m68030_write_32_fc(m68kcpu *cpu, uint32 addr, uint32 data)
479: {
480: cpu->bus.ssw = SSW_BUS_W | RegDFC;
481: cpu->bus.laddr = addr;
482: cpu->bus.data = data;
483: m68030_write_32_bus(cpu);
484: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.