VirtualBox

source: vbox/trunk/src/VBox/Devices/Network/testcase/tstDevEEPROM.cpp@ 98172

Last change on this file since 98172 was 98172, checked in by vboxsync, 20 months ago

Devices/Network: Wrapped the cppunit tests tstDevEEPROM and tstDevPhy to IPRT testing.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 14.4 KB
Line 
1/* $Id: tstDevEEPROM.cpp 98172 2023-01-21 13:01:48Z vboxsync $ */
2/** @file
3 * EEPROM 93C46 unit tests.
4 */
5
6/*
7 * Copyright (C) 2007-2023 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * SPDX-License-Identifier: GPL-3.0-only
26 */
27
28
29/*********************************************************************************************************************************
30* Header Files *
31*********************************************************************************************************************************/
32#ifdef USE_CPPUNIT
33# include <cppunit/ui/text/TestRunner.h>
34# include <cppunit/extensions/HelperMacros.h>
35#else
36# include "CppUnitEmulation.h"
37#endif
38#include <VBox/vmm/pdmdev.h>
39#include "../DevEEPROM.h"
40
41
42/*********************************************************************************************************************************
43* Global Variables *
44*********************************************************************************************************************************/
45static const uint16_t g_abInitialContent[] =
46{
47 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
48 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f,
49 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017,
50 0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f,
51 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
52 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f,
53 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
54 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f
55};
56
57
58/**
59 * Test fixture for 93C46-compatible EEPROM device emulation.
60 */
61class EEPROMTest
62#ifdef USE_CPPUNIT
63 : public CppUnit::TestFixture
64#endif
65{
66 CPPUNIT_TEST_SUITE( tstDevEEPROM );
67
68 CPPUNIT_TEST( testRead );
69 CPPUNIT_TEST( testSequentialRead );
70 CPPUNIT_TEST( testWrite );
71 CPPUNIT_TEST( testWriteAll );
72 CPPUNIT_TEST( testWriteDisabled );
73 CPPUNIT_TEST( testErase );
74 CPPUNIT_TEST( testEraseAll );
75
76 CPPUNIT_TEST_SUITE_END();
77
78private:
79 enum Wires { DO=8, DI=4, CS=2, SK=0x01 };
80 enum OpCodes {
81 READ_OPCODE = 0x6,
82 WRITE_OPCODE = 0x5,
83 ERASE_OPCODE = 0x7,
84 EWDS_OPCODE = 0x10, // erase/write disable
85 WRAL_OPCODE = 0x11, // write all
86 ERAL_OPCODE = 0x12, // erase all
87 EWEN_OPCODE = 0x13 // erase/write enable
88 };
89 enum BitWidths {
90 READ_OPCODE_BITS = 3,
91 WRITE_OPCODE_BITS = 3,
92 ERASE_OPCODE_BITS = 3,
93 EWDS_OPCODE_BITS = 5,
94 WRAL_OPCODE_BITS = 5,
95 ERAL_OPCODE_BITS = 5,
96 EWEN_OPCODE_BITS = 5,
97 READ_ADDR_BITS = 6,
98 WRITE_ADDR_BITS = 6,
99 ERASE_ADDR_BITS = 6,
100 EWDS_ADDR_BITS = 4,
101 WRAL_ADDR_BITS = 4,
102 ERAL_ADDR_BITS = 4,
103 EWEN_ADDR_BITS = 4,
104 DATA_BITS = 16
105 };
106
107 EEPROM93C46 *eeprom;
108
109 // Helper methods
110 void shiftOutBits(uint16_t data, uint16_t count);
111 uint16_t shiftInBits(uint16_t count);
112 void getReady();
113 void standby();
114 void stop();
115 uint16_t readAt(uint16_t addr);
116 bool writeTo(uint16_t addr, uint16_t value);
117 void writeOpAddr(int opCode, int opCodeBits, uint16_t addr, int addrBits);
118 void writeData(uint16_t value) { shiftOutBits(value, DATA_BITS); }
119 bool waitForCompletion();
120
121public:
122 void setUp()
123 {
124 eeprom = new EEPROM93C46;
125 eeprom->init(g_abInitialContent);
126 }
127
128 void tearDown()
129 {
130 delete eeprom;
131 }
132
133 void testSize()
134 {
135 CPPUNIT_ASSERT_EQUAL( sizeof(g_abInitialContent), (size_t)EEPROM93C46::SIZE );
136 }
137
138 void testRead()
139 {
140 getReady();
141 for ( uint32_t wordAddr=0; wordAddr < EEPROM93C46::SIZE; wordAddr++ ) {
142 shiftOutBits(READ_OPCODE, READ_OPCODE_BITS);
143 shiftOutBits(wordAddr, READ_ADDR_BITS);
144
145 CPPUNIT_ASSERT_EQUAL( g_abInitialContent[wordAddr], (uint16_t)wordAddr );
146 CPPUNIT_ASSERT_EQUAL( g_abInitialContent[wordAddr], shiftInBits(DATA_BITS) );
147 standby();
148 }
149 stop();
150 }
151
152 void testSequentialRead()
153 {
154 getReady();
155 shiftOutBits(READ_OPCODE, READ_OPCODE_BITS);
156 shiftOutBits(0, READ_ADDR_BITS);
157 for ( int wordAddr=0; wordAddr < EEPROM93C46::SIZE; wordAddr++ ) {
158 CPPUNIT_ASSERT_EQUAL( g_abInitialContent[wordAddr], shiftInBits(DATA_BITS) );
159 }
160 stop();
161 }
162
163 void testWrite()
164 {
165 //unused: int i;
166 uint16_t wordAddr;
167
168 getReady();
169 // Enable write
170 writeOpAddr(EWEN_OPCODE, EWEN_OPCODE_BITS, 0, EWEN_ADDR_BITS);
171 standby();
172
173 for ( wordAddr=0; wordAddr < EEPROM93C46::SIZE; wordAddr++ ) {
174 //writeOpAddr(WRITE_OPCODE, WRITE_OPCODE_BITS, (uint16_t)wordAddr, WRITE_ADDR_BITS);
175 writeTo(wordAddr, 0x3F00 - (wordAddr<<8));
176 standby();
177
178 if (!waitForCompletion()) {
179 CPPUNIT_FAIL("EEPROM write was not completed");
180 stop();
181 return;
182 }
183 standby();
184 }
185
186 // Disable write
187 writeOpAddr(EWDS_OPCODE, EWDS_OPCODE_BITS, 0, EWDS_ADDR_BITS);
188
189 stop();
190
191 // Now check the result
192 getReady();
193 writeOpAddr(READ_OPCODE, READ_OPCODE_BITS, 0, READ_ADDR_BITS);
194 for ( wordAddr=0; wordAddr < EEPROM93C46::SIZE; wordAddr++ ) {
195 CPPUNIT_ASSERT_EQUAL((uint16_t)(0x3F00 - (wordAddr<<8)), shiftInBits(DATA_BITS) );
196 }
197 stop();
198 }
199
200 void testWriteDisabled()
201 {
202 getReady();
203
204 uint16_t addr = 0;
205 uint16_t oldValue = readAt(addr);
206 stop();
207 getReady();
208 if (writeTo(addr, ~oldValue)) {
209 // Write appears to be successful -- continue
210 CPPUNIT_ASSERT_EQUAL(oldValue, readAt(addr));
211 }
212 else {
213 CPPUNIT_FAIL("EEPROM write was not completed");
214 }
215 stop();
216 }
217
218 void testErase()
219 {
220 int i;
221 uint16_t addr = 0x1F;
222
223 getReady();
224 // Enable write
225 shiftOutBits(EWEN_OPCODE, EWEN_OPCODE_BITS);
226 shiftOutBits(0, EWEN_ADDR_BITS);
227 standby();
228
229 if (writeTo(addr, addr)) {
230 stop();
231 getReady();
232 // Write successful -- continue
233 CPPUNIT_ASSERT_EQUAL(addr, readAt(addr));
234 stop();
235 getReady();
236
237 shiftOutBits(ERASE_OPCODE, ERASE_OPCODE_BITS);
238 shiftOutBits(addr, ERASE_ADDR_BITS);
239
240 standby();
241
242 for (i = 0; i < 200; i++) {
243 if (eeprom->read() & DO)
244 break;
245 //usec_delay(50);
246 }
247
248 if (i == 200) {
249 CPPUNIT_FAIL("EEPROM erase was not completed");
250 stop();
251 return;
252 }
253
254 standby();
255
256 shiftOutBits(EWDS_OPCODE, EWDS_OPCODE_BITS);
257 shiftOutBits(0, EWDS_ADDR_BITS);
258
259 stop();
260 getReady();
261 CPPUNIT_ASSERT_EQUAL((uint16_t)0xFFFF, readAt(addr));
262 }
263 else {
264 CPPUNIT_FAIL("EEPROM write was not completed");
265 }
266 stop();
267 }
268
269 void testWriteAll()
270 {
271 uint16_t addr;
272
273 getReady();
274 // Enable write
275 writeOpAddr(EWEN_OPCODE, EWEN_OPCODE_BITS, 0, EWEN_ADDR_BITS);
276 standby();
277 // Fill all memory
278 writeOpAddr(WRAL_OPCODE, WRAL_OPCODE_BITS, 0, WRAL_ADDR_BITS);
279 writeData(0xABBA);
280 standby();
281
282 if (waitForCompletion()) {
283 stop();
284 getReady();
285 // Write successful -- verify all memory
286 for ( addr=0; addr < EEPROM93C46::SIZE; addr++ ) {
287 CPPUNIT_ASSERT_EQUAL((uint16_t)0xABBA, readAt(addr));
288 }
289 }
290 else {
291 CPPUNIT_FAIL("EEPROM write was not completed");
292 }
293 stop();
294 }
295
296 void testEraseAll()
297 {
298 //unused: int i;
299 uint16_t addr = 0x1F;
300
301 getReady();
302 // Enable write
303 writeOpAddr(EWEN_OPCODE, EWEN_OPCODE_BITS, 0, EWEN_ADDR_BITS);
304 standby();
305 // Fill all memory
306 writeOpAddr(WRITE_OPCODE, WRITE_OPCODE_BITS, addr, WRITE_ADDR_BITS);
307 writeData(0);
308 standby();
309
310 if (waitForCompletion()) {
311 stop();
312 getReady();
313 // Write successful -- verify random location
314 CPPUNIT_ASSERT_EQUAL((uint16_t)0, readAt(addr));
315 stop();
316 getReady();
317
318 writeOpAddr(ERAL_OPCODE, ERAL_OPCODE_BITS, addr, ERAL_ADDR_BITS);
319 standby();
320
321 if (!waitForCompletion()) {
322 CPPUNIT_FAIL("EEPROM erase was not completed");
323 stop();
324 return;
325 }
326
327 standby();
328
329 writeOpAddr(EWDS_OPCODE, EWDS_OPCODE_BITS, 0, EWDS_ADDR_BITS);
330 stop();
331
332 getReady();
333 for ( addr=0; addr < EEPROM93C46::SIZE; addr++ ) {
334 CPPUNIT_ASSERT_EQUAL((uint16_t)0xFFFF, readAt(addr));
335 }
336 }
337 else {
338 CPPUNIT_FAIL("EEPROM write was not completed");
339 }
340 stop();
341 }
342};
343
344/**
345 * shiftOutBits - Shift data bits our to the EEPROM
346 * @hw: pointer to the EEPROM object
347 * @data: data to send to the EEPROM
348 * @count: number of bits to shift out
349 *
350 * We need to shift 'count' bits out to the EEPROM. So, the value in the
351 * "data" parameter will be shifted out to the EEPROM one bit at a time.
352 * In order to do this, "data" must be broken down into bits.
353 **/
354void EEPROMTest::shiftOutBits(uint16_t data, uint16_t count) {
355 uint32_t wires = eeprom->read();
356 uint32_t mask;
357
358 mask = 0x01 << (count - 1);
359 wires &= ~DO;
360
361 do {
362 wires &= ~DI;
363
364 if (data & mask)
365 wires |= DI;
366
367 eeprom->write(wires);
368
369 // Raise clock
370 eeprom->write(wires |= SK);
371 // Lower clock
372 eeprom->write(wires &= ~SK);
373
374 mask >>= 1;
375 } while (mask);
376
377 wires &= ~DI;
378 eeprom->write(wires);
379}
380
381/**
382 * shiftInBits - Shift data bits in from the EEPROM
383 * @count: number of bits to shift in
384 *
385 * In order to read a register from the EEPROM, we need to shift 'count' bits
386 * in from the EEPROM. Bits are "shifted in" by raising the clock input to
387 * the EEPROM (setting the SK bit), and then reading the value of the data out
388 * "DO" bit. During this "shifting in" process the data in "DI" bit should
389 * always be clear.
390 **/
391uint16_t EEPROMTest::shiftInBits(uint16_t count)
392{
393 uint32_t wires;
394 uint32_t i;
395 uint16_t data;
396
397 wires = eeprom->read();
398
399 wires &= ~(DO | DI);
400 data = 0;
401
402 for (i = 0; i < count; i++) {
403 data <<= 1;
404 // Raise clock
405 eeprom->write(wires |= SK);
406
407 wires = eeprom->read();
408
409 wires &= ~DI;
410 if (wires & DO)
411 data |= 1;
412
413 // Lower clock
414 eeprom->write(wires &= ~SK);
415 }
416
417 return data;
418}
419
420/**
421 * getReady - Prepares EEPROM for read/write
422 *
423 * Setups the EEPROM for reading and writing.
424 **/
425void EEPROMTest::getReady()
426{
427 unsigned wires = eeprom->read();
428 /* Clear SK and DI */
429 eeprom->write(wires &= ~(DI | SK));
430 /* Set CS */
431 eeprom->write(wires | CS);
432}
433
434/**
435 * standby - Return EEPROM to standby state
436 *
437 * Return the EEPROM to a standby state.
438 **/
439void EEPROMTest::standby()
440{
441 unsigned wires = eeprom->read();
442
443 eeprom->write(wires &= ~(CS | SK));
444
445 // Raise clock
446 eeprom->write(wires |= SK);
447
448 // Select EEPROM
449 eeprom->write(wires |= CS);
450
451 // Lower clock
452 eeprom->write(wires &= ~SK);
453}
454
455/**
456 * stop - Terminate EEPROM command
457 *
458 * Terminates the current command by inverting the EEPROM's chip select pin.
459 **/
460void EEPROMTest::stop()
461{
462 unsigned wires = eeprom->read();
463
464 eeprom->write(wires &= ~(CS | DI));
465 // Raise clock
466 eeprom->write(wires |= SK);
467 // Lower clock
468 eeprom->write(wires &= ~SK);
469}
470
471/**
472 * readAt - Read a word at specified address
473 * @addr: address to read
474 *
475 * Returns the value of the word specified in 'addr' parameter.
476 **/
477uint16_t EEPROMTest::readAt(uint16_t addr)
478{
479 getReady();
480 shiftOutBits(READ_OPCODE, READ_OPCODE_BITS);
481 shiftOutBits(addr, READ_ADDR_BITS);
482
483 uint16_t value = shiftInBits(DATA_BITS);
484 stop();
485
486 return value;
487}
488
489/**
490 * writeTo - Write a word to specified address
491 * @addr: address to write to
492 * @value: value to store
493 *
494 * Returns false if write did not complete.
495 *
496 * Note: Make sure EEPROM is selected and writable before attempting
497 * to write. Use getReady() and stop() to select/deselect
498 * EEPROM.
499 **/
500bool EEPROMTest::writeTo(uint16_t addr, uint16_t value)
501{
502 writeOpAddr(WRITE_OPCODE, WRITE_OPCODE_BITS, addr, WRITE_ADDR_BITS);
503 writeData(value);
504 standby();
505 return waitForCompletion();
506}
507
508
509/**
510 * waitForCompletion - Wait until EEPROM clears the busy bit
511 *
512 * Returns false if the EEPROM is still busy.
513 */
514bool EEPROMTest::waitForCompletion() {
515 for (int i = 0; i < 200; i++) {
516 if (eeprom->read() & DO) {
517 standby();
518 return true;
519 }
520 // Wait 50 usec;
521 }
522
523 return false;
524}
525
526/**
527 * writeOpAddr - Write an opcode and address
528 * @opCode: operation code
529 * @opCodeBits: number of bits in opCode
530 * @addr: address to write to
531 * @addrBits: number of bits in address
532 **/
533void EEPROMTest::writeOpAddr(int opCode, int opCodeBits, uint16_t addr, int addrBits)
534{
535 shiftOutBits(opCode, opCodeBits);
536 shiftOutBits(addr, addrBits);
537}
538
539int main()
540{
541#ifdef USE_CPPUNIT
542 CppUnit::TextUi::TestRunner runner;
543 runner.addTest( EEPROMTest::suite() );
544 return runner.run() ? 0 : 1;
545#else
546 EEPROMTest Test;
547 return Test.run();
548#endif
549}
550
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette