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