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