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