VirtualBox

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

Last change on this file since 97441 was 96407, checked in by vboxsync, 2 years ago

scm copyright and license note update

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