VirtualBox

source: vbox/trunk/src/VBox/Devices/Network/DevEEPROM.cpp@ 101359

Last change on this file since 101359 was 98172, checked in by vboxsync, 2 years 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: 8.8 KB
Line 
1/* $Id: DevEEPROM.cpp 98172 2023-01-21 13:01:48Z vboxsync $ */
2/** @file
3 * DevEEPROM - Microwire-compatible 64x16-bit 93C46 EEPROM Emulation.
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#define LOG_GROUP LOG_GROUP_DEV_E1000 /// @todo Add a EEPROM logging group.
29#include <VBox/log.h>
30#include <VBox/vmm/pdmdev.h>
31#include <iprt/string.h>
32#include "DevEEPROM.h"
33
34#define E1kLog(a) Log(a)
35
36/**
37 * Initialize EEPROM device.
38 *
39 * @param pu16Initial Initial EEPROM content (optional). The size of initial
40 * content must be sizeof(uint16_t)*EEPROM93C46::SIZE
41 * bytes.
42 */
43void EEPROM93C46::init(const uint16_t *pu16Initial)
44{
45 if ( pu16Initial )
46 memcpy(this->m_au16Data, pu16Initial, sizeof(this->m_au16Data));
47 else
48 memset(this->m_au16Data, 0, sizeof(this->m_au16Data));
49 m_fWriteEnabled = false;
50 m_u32InternalWires = 0;
51 m_eState = STANDBY;
52}
53
54/**
55 * Writes one word to specified location if write is enabled.
56 *
57 * @param u32Addr Address to write at
58 * @param u16Value Value to store
59 */
60void EEPROM93C46::storeWord(uint32_t u32Addr, uint16_t u16Value)
61{
62 if (m_fWriteEnabled) {
63 E1kLog(("EEPROM: Stored word %04x at %08x\n", u16Value, u32Addr));
64 m_au16Data[u32Addr] = u16Value;
65 }
66 m_u16Mask = DATA_MSB;
67}
68
69/**
70 * Reads one word at specified location.
71 *
72 * @returns True if read was successful.
73 *
74 * @param u32Addr Address to read from
75 * @param pu16Value Placeholder to store the value
76 */
77bool EEPROM93C46::readWord(uint32_t u32Addr, uint16_t *pu16Value)
78{
79 if (u32Addr < SIZE)
80 {
81 *pu16Value = m_au16Data[u32Addr];
82 return true;
83 }
84
85 return false;
86}
87
88/**
89 * Fetch next word pointer by m_u16Addr.
90 *
91 * m_u16Addr is advanced and mask is reset to support sequential reads.
92 *
93 * @returns New state
94 */
95EEPROM93C46::State EEPROM93C46::opRead()
96{
97 m_u16Word = m_au16Data[m_u16Addr];
98 E1kLog(("EEPROM: Reading word %04x at %08x\n", m_u16Word, m_u16Addr));
99 m_u16Addr = (m_u16Addr + 1) & ADDR_MASK;
100 m_u16Mask = DATA_MSB;
101 return WRITING_DO;
102}
103
104/**
105 * Write the value of m_u16Word to the location specified by m_u16Addr.
106 *
107 * @returns New state
108 *
109 * @remarks Need to wait for CS lower/raise to show busy/ready indication.
110 */
111EEPROM93C46::State EEPROM93C46::opWrite()
112{
113 storeWord(m_u16Addr, m_u16Word);
114 return WAITING_CS_FALL;
115}
116
117/**
118 * Overwrite the entire contents of EEPROM with the value of m_u16Word.
119 *
120 * @returns New state
121 *
122 * @remarks Need to wait for CS lower/raise to show busy/ready indication.
123 */
124EEPROM93C46::State EEPROM93C46::opWriteAll()
125{
126 for (unsigned i = 0; i < SIZE; i++)
127 storeWord(i, m_u16Word);
128 return WAITING_CS_FALL;
129}
130
131/**
132 * Decode opcode and address from 'opAddr' member.
133 *
134 * Decodes operation and executes it immediately if possible; otherwise, stores
135 * the decoded operation and address.
136 *
137 * @returns New state
138 */
139EEPROM93C46::State EEPROM93C46::opDecode()
140{
141 switch (m_u16Word>>6) {
142 case 3: /* ERASE */
143 storeWord(m_u16Word & ADDR_MASK, 0xFFFF);
144 return WAITING_CS_FALL;
145 case 2: /* READ */
146 m_eOp = OP_READ;
147 m_u16Addr = m_u16Word & ADDR_MASK;
148 return opRead(); /* Load first word */
149 case 1: /* WRITE */
150 m_eOp = OP_WRITE;
151 m_u16Addr = m_u16Word & ADDR_MASK;
152 m_u16Word = 0;
153 m_u16Mask = DATA_MSB;
154 return READING_DI;
155 case 0:
156 switch (m_u16Word>>4) {
157 case 0: /* ERASE/WRITE DISABLE */
158 m_fWriteEnabled = false;
159 return STANDBY;
160 case 1: /* WRITE ALL */
161 m_eOp = OP_WRITE_ALL;
162 m_u16Word = 0;
163 m_u16Mask = DATA_MSB;
164 return READING_DI;
165 case 2: /* ERASE ALL */
166 /* Re-use opWriteAll */
167 m_u16Word = 0xFFFF;
168 return opWriteAll();
169 case 3: /* ERASE/WRITE ENABLE */
170 m_fWriteEnabled = true;
171 return STANDBY;
172 }
173 }
174 return m_eState;
175}
176
177/**
178 * Set bits in EEPROM 4-wire interface.
179 *
180 * @param u32Wires Values of DI, CS, SK.
181 * @remarks The value of DO bit in 'u32Wires' is ignored.
182 */
183void EEPROM93C46::write(uint32_t u32Wires)
184{
185 if (u32Wires & WIRES_CS) {
186 if (!(m_u32InternalWires & WIRES_SK) && (u32Wires & WIRES_SK)) {
187 /* Positive edge of clock */
188 if (m_eState == STANDBY) {
189 if (u32Wires & WIRES_DI) {
190 m_eState = READING_DI;
191 m_eOp = OP_DECODE;
192 m_u16Mask = OPADDR_MSB;
193 m_u16Word = 0;
194 }
195 }
196 else {
197 if (m_eState == READING_DI) {
198 if (u32Wires & WIRES_DI) {
199 m_u16Word |= m_u16Mask;
200 }
201 }
202 else if (m_eState == WRITING_DO) {
203 m_u32InternalWires &= ~WIRES_DO;
204 if (m_u16Word & m_u16Mask) {
205 m_u32InternalWires |= WIRES_DO;
206 }
207 }
208 else return;
209 /* Next bit */
210 m_u16Mask >>= 1;
211 if (m_u16Mask == 0)
212 {
213 switch (this->m_eOp)
214 {
215 case OP_READ:
216 m_eState = opRead();
217 break;
218 case OP_WRITE:
219 m_eState = opWrite();
220 break;
221 case OP_WRITE_ALL:
222 m_eState = opWriteAll();
223 break;
224 case OP_DECODE:
225 m_eState = opDecode();
226 break;
227 default:
228 ;
229 }
230 }
231 }
232 }
233 else if (m_eState == WAITING_CS_RISE) {
234 m_u32InternalWires |= WIRES_DO; /* ready */
235 m_eState = STANDBY;
236 }
237 }
238 else {
239 switch(m_eState) {
240 case WAITING_CS_FALL:
241 m_eState = WAITING_CS_RISE;
242 m_u32InternalWires &= ~WIRES_DO; /* busy */
243 break;
244 case WAITING_CS_RISE:
245 break;
246 case READING_DI:
247 m_u32InternalWires &= ~WIRES_DO; /* Clear ready/busy status from DO. */
248 RT_FALL_THRU();
249 default:
250 m_eState = STANDBY;
251 break;
252 }
253 }
254 m_u32InternalWires &= WIRES_DO;
255 m_u32InternalWires |= u32Wires & ~WIRES_DO; /* Do not overwrite DO */
256}
257
258/**
259 * Read bits in EEPROM 4-wire interface.
260 *
261 * @returns Current values of DO, DI, CS, SK.
262 *
263 * @remarks Only DO is controlled by EEPROM, other bits are returned as they
264 * were written by 'write'.
265 */
266uint32_t EEPROM93C46::read()
267{
268 return m_u32InternalWires;
269}
270
271void EEPROM93C46::save(PCPDMDEVHLPR3 pHlp, PSSMHANDLE pSSM)
272{
273 pHlp->pfnSSMPutU8( pSSM, EEPROM93C46_SAVEDSTATE_VERSION);
274 Assert((uint32_t)m_eState < UINT32_C(256));
275 pHlp->pfnSSMPutU8( pSSM, (uint8_t)m_eState);
276 Assert((uint32_t)m_eOp < UINT32_C(256));
277 pHlp->pfnSSMPutU8( pSSM, (uint8_t)m_eOp);
278 pHlp->pfnSSMPutBool(pSSM, m_fWriteEnabled);
279 pHlp->pfnSSMPutU32( pSSM, m_u32InternalWires);
280 pHlp->pfnSSMPutU16( pSSM, m_u16Word);
281 pHlp->pfnSSMPutU16( pSSM, m_u16Mask);
282 pHlp->pfnSSMPutU16( pSSM, m_u16Addr);
283 pHlp->pfnSSMPutMem( pSSM, m_au16Data, sizeof(m_au16Data));
284}
285
286int EEPROM93C46::load(PCPDMDEVHLPR3 pHlp, PSSMHANDLE pSSM)
287{
288 uint8_t uVersion;
289 int rc = pHlp->pfnSSMGetU8(pSSM, &uVersion);
290 AssertRCReturn(rc, rc);
291 if (uVersion != EEPROM93C46_SAVEDSTATE_VERSION)
292 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
293
294 PDMDEVHLP_SSM_GET_ENUM8_RET(pHlp, pSSM, m_eState, EEPROM93C46::State);
295 PDMDEVHLP_SSM_GET_ENUM8_RET(pHlp, pSSM, m_eOp, EEPROM93C46::OP);
296 pHlp->pfnSSMGetBool(pSSM, &m_fWriteEnabled);
297 pHlp->pfnSSMGetU32( pSSM, &m_u32InternalWires);
298 pHlp->pfnSSMGetU16( pSSM, &m_u16Word);
299 pHlp->pfnSSMGetU16( pSSM, &m_u16Mask);
300 pHlp->pfnSSMGetU16( pSSM, &m_u16Addr);
301 return pHlp->pfnSSMGetMem( pSSM, m_au16Data, sizeof(m_au16Data));
302}
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