PERROR CGame::interruptCheck( ) { PERROR error = errorSuccess; UINT8 response = 0; errorCustom->code = ERROR_SUCCESS; errorCustom->description = "OK:"; for (int i = 0 ; i < 4 ; i++) { error = m_cpu->waitForInterrupt(m_interrupt, 3000); if (FAILED(error)) { break; } if (!m_interruptAutoVector) { error = m_cpu->acknowledgeInterrupt(&response); if (FAILED(error)) { break; } CHECK_VALUE_UINT8_BREAK(error, String("Int"), i, m_interruptResponse, response); } error = m_cpu->waitForInterrupt(m_interrupt, 0); if (SUCCESS(error)) { error = errorUnexpected; break; } else { error = errorSuccess; } } return error; }
// // Performs all the RAM checks on the region supplied to the object. // PERROR CRamCheck::checkRandomAccess( const RAM_REGION *ramRegion ) { PERROR error = errorSuccess; UINT8 dataBusWidth = m_cpu->dataBusWidth(ramRegion->start); UINT8 dataAccessWidth = m_cpu->dataAccessWidth(ramRegion->start); UINT32 regionLength = (ramRegion->end - ramRegion->start) / ramRegion->step; UINT32 countLength = (regionLength * 3) / (dataBusWidth * ramRegion->step); // // This function only works with at least byte-wide memory. // Use a duplicate entry in the RAM_REGION for the byte-wide representation. // if ((ramRegion->mask != 0x00FF) && (ramRegion->mask != 0xFF00) && (ramRegion->mask != 0xFFFF)) { return errorNotImplemented; } // // Clear the region first to all 0. // This will also perform any bank switch. // error = write(ramRegion, 0); if (FAILED(error)) { return error; } // // Outer loop to periodically reset the region back to 0 to restart // with different seeds for the address & data values. // for (UINT8 cycle = 0 ; (cycle < 8) && SUCCESS(error) ; cycle++) { // // Pass 1 - write/read/verify, random access // randomSeed(ramRegion->start + ramRegion->step + ramRegion->mask + cycle); // // The length & step are used for the iteration count as a means to equalize the random access // density no matter what the size of the RAM. // for (UINT32 count = 0 ; count < countLength ; count++ ) { UINT32 address = (((UINT32) random(regionLength)) * (dataBusWidth * ramRegion->step)) + ramRegion->start; UINT16 expData = (((address + cycle) * 3) ^ ((address + cycle) / 5)); UINT16 recData = 0; // For 16-bit we just use the same value for hi & lo. expData = (expData & 0xFF) | (expData << 8); // // Pause to make sure the data is actually held valid. // This is done to help detect DRAM refresh failure. // if ((count % (countLength / 4)) == 0) { delay(cycle * 200); } // // Add in some blind writes to let the writes accumulate // a bit more agressively to fill in the memory with data. // if (count & 2) { error = m_cpu->memoryWrite(address, expData); if (FAILED(error)) { break; } continue; } // Read what's there. error = m_cpu->memoryRead(address, &recData); if (FAILED(error)) { break; } expData &= ramRegion->mask; recData &= ramRegion->mask; // If we a read a 0 then write out a value. if (recData == 0) { error = m_cpu->memoryWrite(address, expData); if (FAILED(error)) { break; } continue; } if (dataAccessWidth == 1) { CHECK_VALUE_UINT8_BREAK(error, ramRegion->location, address, expData, recData); } else if (dataAccessWidth == 2) { CHECK_VALUE_UINT16_BREAK(error, ramRegion->location, address, expData, recData); } else { error = errorNotImplemented; break; } // // Add in an optional clear after verify. // This is less agressive than the blind one to that // on average data accumulates in the RAM // if (count & 4) { error = m_cpu->memoryWrite(address, 0); if (FAILED(error)) { break; } } } // // Add in a variable delay between cycles. // This is to detect a very specific failure mode encountered on TMS4060 // DRAM used on Space Invaders where the RAM fails a few seconds after the // data is written. // delay(cycle * 300); // // Pass 2 - verify/clear entire contents, random access // randomSeed(ramRegion->start + ramRegion->step + ramRegion->mask + cycle); // // The length & step are used for the iteration count as a means to equalize the random access // density no matter what the size of the RAM. // for (UINT32 count = 0 ; count < countLength ; count++ ) { UINT32 address = (((UINT32) random(regionLength)) * (dataBusWidth * ramRegion->step)) + ramRegion->start; UINT16 expData = (((address + cycle) * 3) ^ ((address + cycle) / 5)); UINT16 recData = 0; // For 16-bit we just use the same value for hi & lo. expData = (expData & 0xFF) | (expData << 8); // Read what's there. error = m_cpu->memoryRead(address, &recData); if (FAILED(error)) { break; } expData &= ramRegion->mask; recData &= ramRegion->mask; // Nothing to verify if 0 if (recData == 0) { continue; } if (dataAccessWidth == 1) { CHECK_VALUE_UINT8_BREAK(error, ramRegion->location, address, expData, recData); } else if (dataAccessWidth == 2) { CHECK_VALUE_UINT16_BREAK(error, ramRegion->location, address, expData, recData); } else { error = errorNotImplemented; break; } error = m_cpu->memoryWrite(address, 0); if (FAILED(error)) { break; } } } return error; }