VirtualBox

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

Last change on this file since 82254 was 81765, checked in by vboxsync, 5 years ago

Devices: Use new volatile SSM getters and enum macros. bugref:9218

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