|
|
1.1.1.2 ! root 1: // ! 2: // nono ! 3: // Copyright (C) 2020 nono project ! 4: // Licensed under nono-license.txt ! 5: // ! 6: 1.1 root 7: #include "header.h" 8: #include <stdint.h> 9: #include <vector> 10: 11: // "device.h" の IODevice をリンクしてしまうと、芋づる式に依存オブジェクトが 12: // 増えてしまい収拾つかなくなるので、ダミークラスを用意する。 13: // なので、ここの実装は本物の IODevice のそれと同期しないといけない…。 14: class IODevice 15: { 16: public: 17: IODevice() {} 18: virtual ~IODevice() {} 19: 20: virtual uint64 Read8(uint32 addr) { return 0xef; } 21: virtual uint64 Read16(uint32 addr) { 22: return (Read8(addr) << 8) | (Read8(addr + 1)); 23: } 24: virtual uint64 Read32(uint32 addr) { 25: return (Read16(addr) << 16) | (Read16(addr + 2)); 26: } 27: virtual uint64 Write8(uint32 addr, uint32 data) { return 0; } 28: virtual uint64 Write16(uint32 addr, uint32 data) { 29: uint64 r; 30: r = Write8(addr, data >> 8); 31: r |= Write8(addr + 1, data & 0xff); 32: return r; 33: } 34: virtual uint64 Write32(uint32 addr, uint32 data) { 35: uint64 r; 36: r = Write16(addr, data >> 16); 37: r |= Write16(addr + 2, data & 0xffff); 38: return r; 39: } 40: virtual uint64 Peek8(uint32 addr) { return 0xff; } 41: }; 42: 43: #define SELFTEST 44: #include "busio.h" 45: 46: class TestByteDev : public IODevice 47: { 48: public: 49: TestByteDev() {} 50: virtual ~TestByteDev() {} 51: 52: static const uint32 NPORT = 4; 53: uint32 reg[NPORT] {}; 54: uint64 Read(uint32 addr) { 55: if ((int32)reg[addr] < 0) 56: return (uint64)-1; 57: return reg[addr]; 58: } 59: uint64 Write(uint32 addr, uint32 data) { 60: reg[addr] = data; 61: return 0; 62: } 63: uint64 Peek(uint32 addr) { 64: if ((int32)reg[addr] < 0) 65: return (uint64)-1; 66: return reg[addr]; 67: } 68: }; 69: 70: class TestWordDev : public IODevice 71: { 72: public: 73: TestWordDev() {} 74: virtual ~TestWordDev() {} 75: 76: static const uint32 NPORT = 4; 77: uint32 reg[NPORT] {}; 78: uint64 Read(uint32 addr) { 79: if ((int32)reg[addr] < 0) 80: return (uint64)-1; 81: return reg[addr]; 82: } 83: uint64 Write(uint32 addr, uint32 data) { 84: reg[addr] = data; 85: return 0; 86: } 87: uint64 Peek(uint32 addr) { 88: if ((int32)reg[addr] < 0) 89: return (uint64)-1; 90: return reg[addr]; 91: } 92: }; 93: 94: // テストデータ 95: // expected[] の1エントリは1バイトを表す(WordDevの時も同様)。 96: #define E ((uint64)-1) 97: #define F (0xff) 1.1.1.2 ! root 98: static struct testdata { 1.1 root 99: const char *name; 100: std::vector<uint64> expected; 101: } testdata_b[] = { 102: { "BusIO_B", { 103: 1, 2, 3, 4, 1, 2, 3, 4, 104: } }, 105: { "BusIO_BB", { 106: 1, 1, 2, 2, 3, 3, 4, 4, 1, 1, 2, 2, 3, 3, 4, 4, 107: } }, 108: { "BusIO_BBBB", { 109: 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 110: 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 111: } }, 112: { "BusIO_BE", { 113: 1, E, 2, E, 3, E, 4, E, 1, E, 2, E, 3, E, 4, E, 114: } }, 115: { "BusIO_EB", { 116: E, 1, E, 2, E, 3, E, 4, E, 1, E, 2, E, 3, E, 4, 117: } }, 1.1.1.2 ! root 118: { "BusIO_FB", { ! 119: F, 1, F, 2, F, 3, F, 4, F, 1, F, 2, F, 3, F, 4, ! 120: } }, 1.1 root 121: { "BusIO_BFFF", { 122: 1, F, F, F, 2, F, F, F, 3, F, F, F, 4, F, F, F, 123: 1, F, F, F, 2, F, F, F, 3, F, F, F, 4, F, F, F, 124: } }, 125: }, testdata_w[] = { 126: { "BusIO_W", { 127: 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8, 128: } }, 129: { "BusIO_WW", { 130: 1, 2, 1, 2, 3, 4, 3, 4, 5, 6, 5, 6, 7, 8, 7, 8, 131: 1, 2, 1, 2, 3, 4, 3, 4, 5, 6, 5, 6, 7, 8, 7, 8, 132: } }, 133: { "BusIO_WF", { 134: 1, 2, F, F, 3, 4, F, F, 5, 6, F, F, 7, 8, F, F, 135: 1, 2, F, F, 3, 4, F, F, 5, 6, F, F, 7, 8, F, F, 136: } }, 137: }; 138: 139: void fail(const char *fmt, ...) __printflike(1, 2); 140: void 141: fail(const char *fmt, ...) 142: { 143: va_list ap; 144: 145: printf(" FAIL: "); 146: va_start(ap, fmt); 147: vprintf(fmt, ap); 148: va_end(ap); 149: } 150: 151: template<typename T> void 152: do_test(struct testdata *test, T *dev) 153: { 154: printf("%s\n", test->name); 155: 156: // デバイス側に読み出し元データをセット。 157: // 元データは常にバイト単位で列挙してあるので、ターゲットデバイスの 158: // サイズによってセット方法が変わる。 159: if (dynamic_cast<TestByteDev*>(dev)) { 160: for (int i = 0; i < dev->NPORT; i++) { 161: dev->reg[i] = (i + 1); 162: } 163: } else { 164: for (int i = 0, j = 0; i < dev->NPORT; i++) { 165: uint32 data; 166: data = (++j) << 8; 167: data |= (++j); 168: dev->reg[i] = data; 169: } 170: } 171: 172: // Read8 のテスト 173: for (int i = 0; i < test->expected.size(); i++) { 174: uint64 act = dev->Read8(i); 175: uint64 exp = test->expected[i]; 176: if (act != exp) { 177: fail("%s::Read8(%d) expects %02" PRIx64 " but %02" PRIx64 "\n", 178: test->name, i, exp, act); 179: } 180: } 181: // Read16 のテスト 182: for (int i = 0; i < test->expected.size(); i += 2) { 183: uint64 act = dev->Read16(i); 184: uint64 e0 = test->expected[i + 0]; 185: uint64 e1 = test->expected[i + 1]; 186: uint64 exp; 187: if ((int64)e0 < 0 && (int64)e1 < 0) { 188: // 両方バスエラーならバスエラー? 189: exp = (int64)-1; 190: } else { 191: // そうでなければバスエラー側は 0xff ? 192: exp = (((uint8)e0) << 8) | ((uint8)e1); 193: } 194: if (act != exp) { 195: fail("%s::Read16(%d) expects %04" PRIx64 " but %04" PRIx64 "\n", 196: test->name, i, exp, act); 197: } 198: } 199: // Read32 のテスト 200: for (int i = 0; i < test->expected.size(); i += 4) { 201: uint64 act = dev->Read32(i); 202: uint64 e0 = test->expected[i + 0]; 203: uint64 e1 = test->expected[i + 1]; 204: uint64 e2 = test->expected[i + 2]; 205: uint64 e3 = test->expected[i + 3]; 206: uint64 exp; 207: if ((int64)e0 < 0 && (int64)e1 < 0 && (int64)e2 < 0 && (int64)e3 < 0) { 208: // 全部バスエラーならバスエラー? 209: exp = (int64)-1; 210: } else { 211: // そうでなければバスエラー部分だけ 0xff ? 212: e0 = (uint8)e0 << 24; 213: e1 = (uint8)e1 << 16; 214: e2 = (uint8)e2 << 8; 215: e3 = (uint8)e3; 216: exp = (uint64)(uint32)(e0 | e1 | e2 | e3); 217: } 218: if (act != exp) { 219: fail("%s::Read32(%d) expects %08" PRIx64 " but %08" PRIx64 "\n", 220: test->name, i, exp, act); 221: } 222: } 223: // Peek8 のテスト 224: for (int i = 0; i < test->expected.size(); i++) { 225: uint64 act = dev->Peek8(i); 226: uint64 exp = test->expected[i]; 227: if (act != exp) { 228: fail("%s::Peek8(%d) expects %02" PRIx64 " but %02" PRIx64 "\n", 229: test->name, i, exp, act); 230: } 231: } 232: 233: // Write 系のテストはちょっと保留。 234: } 235: 236: int 237: main() 238: { 239: do_test<TestByteDev>(&testdata_b[0], new BusIO_B<TestByteDev>()); 240: do_test<TestByteDev>(&testdata_b[1], new BusIO_BB<TestByteDev>()); 241: do_test<TestByteDev>(&testdata_b[2], new BusIO_BBBB<TestByteDev>()); 242: do_test<TestByteDev>(&testdata_b[3], new BusIO_BE<TestByteDev>()); 243: do_test<TestByteDev>(&testdata_b[4], new BusIO_EB<TestByteDev>()); 1.1.1.2 ! root 244: do_test<TestByteDev>(&testdata_b[5], new BusIO_FB<TestByteDev>()); ! 245: do_test<TestByteDev>(&testdata_b[6], new BusIO_BFFF<TestByteDev>()); 1.1 root 246: 247: do_test<TestWordDev>(&testdata_w[0], new BusIO_W<TestWordDev>()); 248: do_test<TestWordDev>(&testdata_w[1], new BusIO_WW<TestWordDev>()); 249: do_test<TestWordDev>(&testdata_w[2], new BusIO_WF<TestWordDev>()); 250: return 0; 251: } 252: 253: // リンカを通すためのダミー 254: void 255: panic(const char *funcname, const char *fmt, ...) 256: { 257: va_list ap; 258: 259: printf("panic: %s: ", funcname); 260: va_start(ap, fmt); 261: vprintf(fmt, ap); 262: va_end(ap); 263: exit(1); 264: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.