VirtualBox

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

Last change on this file since 37738 was 35346, checked in by vboxsync, 14 years ago

VMM reorg: Moving the public include files from include/VBox to include/VBox/vmm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 8.2 KB
Line 
1/* $Id: DevEEPROM.cpp 35346 2010-12-27 16:13:13Z vboxsync $ */
2/** @file
3 * DevEEPROM - Microware-compatible 64x16-bit 93C46 EEPROM Emulation.
4 */
5
6/*
7 * Copyright (C) 2007 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-1));
90 m_u16Mask = DATA_MSB;
91 return WRITING_DO;
92}
93
94/**
95 * Write the value of m_u16Word to the location specified by m_u16Addr.
96 *
97 * @returns New state
98 *
99 * @remarks Need to wait for CS lower/raise to show busy/ready indication.
100 */
101EEPROM93C46::State EEPROM93C46::opWrite()
102{
103 storeWord(m_u16Addr, m_u16Word);
104 return WAITING_CS_FALL;
105}
106
107/**
108 * Overwrite the entire contents of EEPROM with the value of m_u16Word.
109 *
110 * @returns New state
111 *
112 * @remarks Need to wait for CS lower/raise to show busy/ready indication.
113 */
114EEPROM93C46::State EEPROM93C46::opWriteAll()
115{
116 for (int i = 0; i < SIZE; i++)
117 storeWord(i, m_u16Word);
118 return WAITING_CS_FALL;
119}
120
121/**
122 * Decode opcode and address from 'opAddr' member.
123 *
124 * Decodes operation and executes it immediately if possible; otherwise, stores
125 * the decoded operation and address.
126 *
127 * @returns New state
128 */
129EEPROM93C46::State EEPROM93C46::opDecode()
130{
131 switch (m_u16Word>>6) {
132 case 3: /* ERASE */
133 storeWord(m_u16Word & ADDR_MASK, 0xFFFF);
134 return WAITING_CS_FALL;
135 case 2: /* READ */
136 m_eOp = OP_READ;
137 m_u16Addr = m_u16Word & ADDR_MASK;
138 return opRead(); /* Load first word */
139 case 1: /* WRITE */
140 m_eOp = OP_WRITE;
141 m_u16Addr = m_u16Word & ADDR_MASK;
142 m_u16Word = 0;
143 m_u16Mask = DATA_MSB;
144 return READING_DI;
145 case 0:
146 switch (m_u16Word>>4) {
147 case 0: /* ERASE/WRITE DISABLE */
148 m_fWriteEnabled = false;
149 return STANDBY;
150 case 1: /* WRITE ALL */
151 m_eOp = OP_WRITE_ALL;
152 m_u16Word = 0;
153 m_u16Mask = DATA_MSB;
154 return READING_DI;
155 case 2: /* ERASE ALL */
156 /* Re-use opWriteAll */
157 m_u16Word = 0xFFFF;
158 return opWriteAll();
159 case 3: /* ERASE/WRITE ENABLE */
160 m_fWriteEnabled = true;
161 return STANDBY;
162 }
163 }
164 return m_eState;
165}
166
167/**
168 * Set bits in EEPROM 4-wire interface.
169 *
170 * @param u32Wires Values of DI, CS, SK.
171 * @remarks The value of DO bit in 'u32Wires' is ignored.
172 */
173void EEPROM93C46::write(uint32_t u32Wires)
174{
175 if (u32Wires & WIRES_CS) {
176 if (!(m_u32InternalWires & WIRES_SK) && (u32Wires & WIRES_SK)) {
177 /* Positive edge of clock */
178 if (m_eState == STANDBY) {
179 if (u32Wires & WIRES_DI) {
180 m_eState = READING_DI;
181 m_eOp = OP_DECODE;
182 m_u16Mask = OPADDR_MSB;
183 m_u16Word = 0;
184 }
185 }
186 else {
187 if (m_eState == READING_DI) {
188 if (u32Wires & WIRES_DI) {
189 m_u16Word |= m_u16Mask;
190 }
191 }
192 else if (m_eState == WRITING_DO) {
193 m_u32InternalWires &= ~WIRES_DO;
194 if (m_u16Word & m_u16Mask) {
195 m_u32InternalWires |= WIRES_DO;
196 }
197 }
198 else return;
199 /* Next bit */
200 m_u16Mask >>= 1;
201 if (m_u16Mask == 0)
202 {
203 switch (this->m_eOp)
204 {
205 case OP_READ:
206 m_eState = opRead();
207 break;
208 case OP_WRITE:
209 m_eState = opWrite();
210 break;
211 case OP_WRITE_ALL:
212 m_eState = opWriteAll();
213 break;
214 case OP_DECODE:
215 m_eState = opDecode();
216 break;
217 default:
218 ;
219 }
220 }
221 }
222 }
223 else if (m_eState == WAITING_CS_RISE) {
224 m_u32InternalWires |= WIRES_DO; /* ready */
225 m_eState = STANDBY;
226 }
227 }
228 else {
229 switch(m_eState) {
230 case WAITING_CS_FALL:
231 m_eState = WAITING_CS_RISE;
232 m_u32InternalWires &= ~WIRES_DO; /* busy */
233 break;
234 case WAITING_CS_RISE:
235 break;
236 case READING_DI:
237 m_u32InternalWires &= ~WIRES_DO; /* Clear ready/busy status from DO. */
238 /* Fall through! */
239 default:
240 m_eState = STANDBY;
241 break;
242 }
243 }
244 m_u32InternalWires &= WIRES_DO;
245 m_u32InternalWires |= u32Wires & ~WIRES_DO; /* Do not overwrite DO */
246}
247
248/**
249 * Read bits in EEPROM 4-wire interface.
250 *
251 * @returns Current values of DO, DI, CS, SK.
252 *
253 * @remarks Only DO is controlled by EEPROM, other bits are returned as they
254 * were written by 'write'.
255 */
256uint32_t EEPROM93C46::read()
257{
258 return m_u32InternalWires;
259}
260
261void EEPROM93C46::save(PSSMHANDLE pSSM)
262{
263 SSMR3PutU8( pSSM, EEPROM93C46_SAVEDSTATE_VERSION);
264 SSMR3PutU8( pSSM, m_eState);
265 SSMR3PutU8( pSSM, m_eOp);
266 SSMR3PutBool(pSSM, m_fWriteEnabled);
267 SSMR3PutU32( pSSM, m_u32InternalWires);
268 SSMR3PutU16( pSSM, m_u16Word);
269 SSMR3PutU16( pSSM, m_u16Mask);
270 SSMR3PutU16( pSSM, m_u16Addr);
271 SSMR3PutMem( pSSM, m_au16Data, sizeof(m_au16Data));
272}
273
274int EEPROM93C46::load(PSSMHANDLE pSSM)
275{
276 int rc;
277 uint8_t uVersion;
278
279 rc = SSMR3GetU8(pSSM, &uVersion);
280 AssertRCReturn(rc, rc);
281 if (uVersion != EEPROM93C46_SAVEDSTATE_VERSION)
282 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
283
284 SSMR3GetU8( pSSM, (uint8_t*)&m_eState);
285 SSMR3GetU8( pSSM, (uint8_t*)&m_eOp);
286 SSMR3GetBool(pSSM, &m_fWriteEnabled);
287 SSMR3GetU32( pSSM, &m_u32InternalWires);
288 SSMR3GetU16( pSSM, &m_u16Word);
289 SSMR3GetU16( pSSM, &m_u16Mask);
290 SSMR3GetU16( pSSM, &m_u16Addr);
291 return SSMR3GetMem( pSSM, m_au16Data, sizeof(m_au16Data));
292}
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