From f215e02bf85f68d3a6106c2a1f4f7f063f819064 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Thu, 11 Apr 2024 10:17:27 +0200 Subject: Adding upstream version 7.0.14-dfsg. Signed-off-by: Daniel Baumann --- src/VBox/Devices/Network/DevEEPROM.cpp | 302 +++++++++++++++++++++++++++++++++ 1 file changed, 302 insertions(+) create mode 100644 src/VBox/Devices/Network/DevEEPROM.cpp (limited to 'src/VBox/Devices/Network/DevEEPROM.cpp') diff --git a/src/VBox/Devices/Network/DevEEPROM.cpp b/src/VBox/Devices/Network/DevEEPROM.cpp new file mode 100644 index 00000000..9353df89 --- /dev/null +++ b/src/VBox/Devices/Network/DevEEPROM.cpp @@ -0,0 +1,302 @@ +/* $Id: DevEEPROM.cpp $ */ +/** @file + * DevEEPROM - Microwire-compatible 64x16-bit 93C46 EEPROM Emulation. + */ + +/* + * Copyright (C) 2007-2023 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * SPDX-License-Identifier: GPL-3.0-only + */ + +#define LOG_GROUP LOG_GROUP_DEV_E1000 /// @todo Add a EEPROM logging group. +#include +#include +#include +#include "DevEEPROM.h" + +#define E1kLog(a) Log(a) + +/** + * Initialize EEPROM device. + * + * @param pu16Initial Initial EEPROM content (optional). The size of initial + * content must be sizeof(uint16_t)*EEPROM93C46::SIZE + * bytes. + */ +void EEPROM93C46::init(const uint16_t *pu16Initial) +{ + if ( pu16Initial ) + memcpy(this->m_au16Data, pu16Initial, sizeof(this->m_au16Data)); + else + memset(this->m_au16Data, 0, sizeof(this->m_au16Data)); + m_fWriteEnabled = false; + m_u32InternalWires = 0; + m_eState = STANDBY; +} + +/** + * Writes one word to specified location if write is enabled. + * + * @param u32Addr Address to write at + * @param u16Value Value to store + */ +void EEPROM93C46::storeWord(uint32_t u32Addr, uint16_t u16Value) +{ + if (m_fWriteEnabled) { + E1kLog(("EEPROM: Stored word %04x at %08x\n", u16Value, u32Addr)); + m_au16Data[u32Addr] = u16Value; + } + m_u16Mask = DATA_MSB; +} + +/** + * Reads one word at specified location. + * + * @returns True if read was successful. + * + * @param u32Addr Address to read from + * @param pu16Value Placeholder to store the value + */ +bool EEPROM93C46::readWord(uint32_t u32Addr, uint16_t *pu16Value) +{ + if (u32Addr < SIZE) + { + *pu16Value = m_au16Data[u32Addr]; + return true; + } + + return false; +} + +/** + * Fetch next word pointer by m_u16Addr. + * + * m_u16Addr is advanced and mask is reset to support sequential reads. + * + * @returns New state + */ +EEPROM93C46::State EEPROM93C46::opRead() +{ + m_u16Word = m_au16Data[m_u16Addr]; + E1kLog(("EEPROM: Reading word %04x at %08x\n", m_u16Word, m_u16Addr)); + m_u16Addr = (m_u16Addr + 1) & ADDR_MASK; + m_u16Mask = DATA_MSB; + return WRITING_DO; +} + +/** + * Write the value of m_u16Word to the location specified by m_u16Addr. + * + * @returns New state + * + * @remarks Need to wait for CS lower/raise to show busy/ready indication. + */ +EEPROM93C46::State EEPROM93C46::opWrite() +{ + storeWord(m_u16Addr, m_u16Word); + return WAITING_CS_FALL; +} + +/** + * Overwrite the entire contents of EEPROM with the value of m_u16Word. + * + * @returns New state + * + * @remarks Need to wait for CS lower/raise to show busy/ready indication. + */ +EEPROM93C46::State EEPROM93C46::opWriteAll() +{ + for (unsigned i = 0; i < SIZE; i++) + storeWord(i, m_u16Word); + return WAITING_CS_FALL; +} + +/** + * Decode opcode and address from 'opAddr' member. + * + * Decodes operation and executes it immediately if possible; otherwise, stores + * the decoded operation and address. + * + * @returns New state + */ +EEPROM93C46::State EEPROM93C46::opDecode() +{ + switch (m_u16Word>>6) { + case 3: /* ERASE */ + storeWord(m_u16Word & ADDR_MASK, 0xFFFF); + return WAITING_CS_FALL; + case 2: /* READ */ + m_eOp = OP_READ; + m_u16Addr = m_u16Word & ADDR_MASK; + return opRead(); /* Load first word */ + case 1: /* WRITE */ + m_eOp = OP_WRITE; + m_u16Addr = m_u16Word & ADDR_MASK; + m_u16Word = 0; + m_u16Mask = DATA_MSB; + return READING_DI; + case 0: + switch (m_u16Word>>4) { + case 0: /* ERASE/WRITE DISABLE */ + m_fWriteEnabled = false; + return STANDBY; + case 1: /* WRITE ALL */ + m_eOp = OP_WRITE_ALL; + m_u16Word = 0; + m_u16Mask = DATA_MSB; + return READING_DI; + case 2: /* ERASE ALL */ + /* Re-use opWriteAll */ + m_u16Word = 0xFFFF; + return opWriteAll(); + case 3: /* ERASE/WRITE ENABLE */ + m_fWriteEnabled = true; + return STANDBY; + } + } + return m_eState; +} + +/** + * Set bits in EEPROM 4-wire interface. + * + * @param u32Wires Values of DI, CS, SK. + * @remarks The value of DO bit in 'u32Wires' is ignored. + */ +void EEPROM93C46::write(uint32_t u32Wires) +{ + if (u32Wires & WIRES_CS) { + if (!(m_u32InternalWires & WIRES_SK) && (u32Wires & WIRES_SK)) { + /* Positive edge of clock */ + if (m_eState == STANDBY) { + if (u32Wires & WIRES_DI) { + m_eState = READING_DI; + m_eOp = OP_DECODE; + m_u16Mask = OPADDR_MSB; + m_u16Word = 0; + } + } + else { + if (m_eState == READING_DI) { + if (u32Wires & WIRES_DI) { + m_u16Word |= m_u16Mask; + } + } + else if (m_eState == WRITING_DO) { + m_u32InternalWires &= ~WIRES_DO; + if (m_u16Word & m_u16Mask) { + m_u32InternalWires |= WIRES_DO; + } + } + else return; + /* Next bit */ + m_u16Mask >>= 1; + if (m_u16Mask == 0) + { + switch (this->m_eOp) + { + case OP_READ: + m_eState = opRead(); + break; + case OP_WRITE: + m_eState = opWrite(); + break; + case OP_WRITE_ALL: + m_eState = opWriteAll(); + break; + case OP_DECODE: + m_eState = opDecode(); + break; + default: + ; + } + } + } + } + else if (m_eState == WAITING_CS_RISE) { + m_u32InternalWires |= WIRES_DO; /* ready */ + m_eState = STANDBY; + } + } + else { + switch(m_eState) { + case WAITING_CS_FALL: + m_eState = WAITING_CS_RISE; + m_u32InternalWires &= ~WIRES_DO; /* busy */ + break; + case WAITING_CS_RISE: + break; + case READING_DI: + m_u32InternalWires &= ~WIRES_DO; /* Clear ready/busy status from DO. */ + RT_FALL_THRU(); + default: + m_eState = STANDBY; + break; + } + } + m_u32InternalWires &= WIRES_DO; + m_u32InternalWires |= u32Wires & ~WIRES_DO; /* Do not overwrite DO */ +} + +/** + * Read bits in EEPROM 4-wire interface. + * + * @returns Current values of DO, DI, CS, SK. + * + * @remarks Only DO is controlled by EEPROM, other bits are returned as they + * were written by 'write'. + */ +uint32_t EEPROM93C46::read() +{ + return m_u32InternalWires; +} + +void EEPROM93C46::save(PCPDMDEVHLPR3 pHlp, PSSMHANDLE pSSM) +{ + pHlp->pfnSSMPutU8( pSSM, EEPROM93C46_SAVEDSTATE_VERSION); + Assert((uint32_t)m_eState < UINT32_C(256)); + pHlp->pfnSSMPutU8( pSSM, (uint8_t)m_eState); + Assert((uint32_t)m_eOp < UINT32_C(256)); + pHlp->pfnSSMPutU8( pSSM, (uint8_t)m_eOp); + pHlp->pfnSSMPutBool(pSSM, m_fWriteEnabled); + pHlp->pfnSSMPutU32( pSSM, m_u32InternalWires); + pHlp->pfnSSMPutU16( pSSM, m_u16Word); + pHlp->pfnSSMPutU16( pSSM, m_u16Mask); + pHlp->pfnSSMPutU16( pSSM, m_u16Addr); + pHlp->pfnSSMPutMem( pSSM, m_au16Data, sizeof(m_au16Data)); +} + +int EEPROM93C46::load(PCPDMDEVHLPR3 pHlp, PSSMHANDLE pSSM) +{ + uint8_t uVersion; + int rc = pHlp->pfnSSMGetU8(pSSM, &uVersion); + AssertRCReturn(rc, rc); + if (uVersion != EEPROM93C46_SAVEDSTATE_VERSION) + return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION; + + PDMDEVHLP_SSM_GET_ENUM8_RET(pHlp, pSSM, m_eState, EEPROM93C46::State); + PDMDEVHLP_SSM_GET_ENUM8_RET(pHlp, pSSM, m_eOp, EEPROM93C46::OP); + pHlp->pfnSSMGetBool(pSSM, &m_fWriteEnabled); + pHlp->pfnSSMGetU32( pSSM, &m_u32InternalWires); + pHlp->pfnSSMGetU16( pSSM, &m_u16Word); + pHlp->pfnSSMGetU16( pSSM, &m_u16Mask); + pHlp->pfnSSMGetU16( pSSM, &m_u16Addr); + return pHlp->pfnSSMGetMem( pSSM, m_au16Data, sizeof(m_au16Data)); +} -- cgit v1.2.3