364 lines
9.6 KiB
C++
Executable File
364 lines
9.6 KiB
C++
Executable File
/*
|
|
* Author: Dirk W. Hoffmann. All rights reserved.
|
|
*
|
|
* 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; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* 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, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
*/
|
|
|
|
#include "C64.h"
|
|
|
|
VirtualComponent::VirtualComponent()
|
|
{
|
|
name = "Unnamed component";
|
|
debugLevel = DEBUG_LEVEL;
|
|
running = false;
|
|
suspendCounter = 0;
|
|
traceMode = false;
|
|
logfile = NULL;
|
|
snapshotItems = NULL;
|
|
subComponents = NULL;
|
|
snapshotSize = 0;
|
|
}
|
|
|
|
VirtualComponent::~VirtualComponent()
|
|
{
|
|
// debug(2, "Terminated\n");
|
|
|
|
if (subComponents)
|
|
delete [] subComponents;
|
|
|
|
if (snapshotItems)
|
|
delete [] snapshotItems;
|
|
|
|
if (logfile)
|
|
fclose(logfile);
|
|
}
|
|
|
|
void
|
|
VirtualComponent::setC64(C64 *c64)
|
|
{
|
|
this->c64 = c64;
|
|
if (subComponents != NULL)
|
|
for (unsigned i = 0; subComponents[i] != NULL; i++)
|
|
subComponents[i]->setC64(c64);
|
|
}
|
|
|
|
void
|
|
VirtualComponent::reset()
|
|
{
|
|
// Reset all sub components
|
|
if (subComponents != NULL)
|
|
for (unsigned i = 0; subComponents[i] != NULL; i++)
|
|
subComponents[i]->reset();
|
|
|
|
// Clear snapshot items marked with 'CLEAR_ON_RESET'
|
|
if (snapshotItems != NULL)
|
|
for (unsigned i = 0; snapshotItems[i].data != NULL; i++)
|
|
if (snapshotItems[i].flags & CLEAR_ON_RESET)
|
|
memset(snapshotItems[i].data, 0, snapshotItems[i].size);
|
|
|
|
setTraceMode(false);
|
|
|
|
debug(2, "Resetting...\n");
|
|
|
|
}
|
|
|
|
void
|
|
VirtualComponent::ping()
|
|
{
|
|
// Ping all sub components
|
|
if (subComponents != NULL)
|
|
for (unsigned i = 0; subComponents[i] != NULL; i++)
|
|
subComponents[i]->ping();
|
|
}
|
|
|
|
void
|
|
VirtualComponent::run()
|
|
{
|
|
running = true;
|
|
}
|
|
|
|
bool
|
|
VirtualComponent::isRunning()
|
|
{
|
|
return running;
|
|
}
|
|
|
|
void
|
|
VirtualComponent::halt()
|
|
{
|
|
running = false;
|
|
}
|
|
|
|
bool
|
|
VirtualComponent::isHalted()
|
|
{
|
|
return !running;
|
|
}
|
|
|
|
void
|
|
VirtualComponent::suspend()
|
|
{
|
|
debug(2, "Suspending...\n");
|
|
if (suspendCounter == 0) {
|
|
suspendedState = isRunning();
|
|
halt();
|
|
}
|
|
suspendCounter++;
|
|
|
|
assert(suspendCounter > 0);
|
|
}
|
|
|
|
void
|
|
VirtualComponent::resume()
|
|
{
|
|
debug(2, "Resuming...\n");
|
|
suspendCounter--;
|
|
if (suspendCounter == 0 && suspendedState == true)
|
|
run();
|
|
|
|
assert(suspendCounter >= 0);
|
|
}
|
|
|
|
void
|
|
VirtualComponent::dumpState()
|
|
{
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------------------------
|
|
// Printing messages
|
|
// ---------------------------------------------------------------------------------------------
|
|
|
|
void
|
|
VirtualComponent::msg(const char *fmt, ...)
|
|
{
|
|
char buf[256];
|
|
va_list ap;
|
|
va_start(ap, fmt);
|
|
vsnprintf(buf, sizeof(buf), fmt, ap);
|
|
va_end(ap);
|
|
fprintf(logfile ? logfile : stderr, "%s", buf);
|
|
}
|
|
|
|
void
|
|
VirtualComponent::msg(int level, const char *fmt, ...)
|
|
{
|
|
if (level > debugLevel)
|
|
return;
|
|
|
|
char buf[256];
|
|
va_list ap;
|
|
va_start(ap, fmt);
|
|
vsnprintf(buf, sizeof(buf), fmt, ap);
|
|
va_end(ap);
|
|
fprintf(logfile ? logfile : stderr, "%s", buf);
|
|
}
|
|
|
|
void
|
|
VirtualComponent::debug(const char *fmt, ...)
|
|
{
|
|
char buf[256];
|
|
va_list ap;
|
|
va_start(ap, fmt);
|
|
vsnprintf(buf, sizeof(buf), fmt, ap);
|
|
va_end(ap);
|
|
fprintf(logfile ? logfile : stderr, "%s: %s", name, buf);
|
|
}
|
|
|
|
void
|
|
VirtualComponent::debug(int level, const char *fmt, ...)
|
|
{
|
|
if (level > debugLevel)
|
|
return;
|
|
|
|
char buf[256];
|
|
va_list ap;
|
|
va_start(ap, fmt);
|
|
vsnprintf(buf, sizeof(buf), fmt, ap);
|
|
va_end(ap);
|
|
fprintf(logfile ? logfile : stderr, "%s: %s", name, buf);
|
|
}
|
|
|
|
void
|
|
VirtualComponent::warn(const char *fmt, ...)
|
|
{
|
|
char buf[256];
|
|
va_list ap;
|
|
va_start(ap, fmt);
|
|
vsnprintf(buf, sizeof(buf), fmt, ap);
|
|
va_end(ap);
|
|
fprintf(logfile ? logfile : stderr, "%s: WARNING: %s", name, buf);
|
|
}
|
|
|
|
void
|
|
VirtualComponent::panic(const char *fmt, ...)
|
|
{
|
|
char buf[256];
|
|
va_list ap;
|
|
va_start(ap, fmt);
|
|
vsnprintf(buf, sizeof(buf), fmt, ap);
|
|
va_end(ap);
|
|
fprintf(logfile ? logfile : stderr, "%s: PANIC: %s", name, buf);
|
|
|
|
assert(0);
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------------------------
|
|
// Snapshots
|
|
// ---------------------------------------------------------------------------------------------
|
|
|
|
void
|
|
VirtualComponent::registerSnapshotItems(SnapshotItem *items, unsigned length) {
|
|
|
|
assert(items != NULL);
|
|
assert(length % sizeof(SnapshotItem) == 0);
|
|
|
|
unsigned i, numItems = length / sizeof(SnapshotItem);
|
|
|
|
// Allocate new array on heap and copy array data
|
|
snapshotItems = new SnapshotItem[numItems];
|
|
std::copy(items, items + numItems, &snapshotItems[0]);
|
|
|
|
// Determine size of snapshot on disk
|
|
for (i = snapshotSize = 0; snapshotItems[i].data != NULL; i++)
|
|
snapshotSize += snapshotItems[i].size;
|
|
}
|
|
|
|
void
|
|
VirtualComponent::registerSubComponents(VirtualComponent **components, unsigned length) {
|
|
|
|
assert(components != NULL);
|
|
assert(length % sizeof(VirtualComponent *) == 0);
|
|
|
|
unsigned numItems = length / sizeof(VirtualComponent *);
|
|
|
|
debug(2, "Registering %d components\n", numItems);
|
|
|
|
// Allocate new array on heap and copy array data
|
|
subComponents = new VirtualComponent*[numItems];
|
|
std::copy(components, components + numItems, &subComponents[0]);
|
|
|
|
// for (unsigned i = 0; subComponents[i] != NULL; i++)
|
|
// printf("%s ", subComponents[i]->name);
|
|
|
|
}
|
|
|
|
uint32_t
|
|
VirtualComponent::stateSize()
|
|
{
|
|
uint32_t result = snapshotSize;
|
|
|
|
if (subComponents != NULL)
|
|
for (unsigned i = 0; subComponents[i] != NULL; i++)
|
|
result += subComponents[i]->stateSize();
|
|
|
|
return result;
|
|
}
|
|
|
|
void
|
|
VirtualComponent::loadFromBuffer(uint8_t **buffer)
|
|
{
|
|
uint8_t *old = *buffer;
|
|
|
|
debug(3, " Loading internal state (%d bytes) ...\n", VirtualComponent::stateSize());
|
|
|
|
// Load internal state of sub components
|
|
if (subComponents != NULL)
|
|
for (unsigned i = 0; subComponents[i] != NULL; i++)
|
|
subComponents[i]->loadFromBuffer(buffer);
|
|
|
|
// Load own internal state
|
|
void *data; size_t size; int flags;
|
|
for (unsigned i = 0; snapshotItems != NULL && snapshotItems[i].data != NULL; i++) {
|
|
|
|
data = snapshotItems[i].data;
|
|
flags = snapshotItems[i].flags & 0x0F;
|
|
size = snapshotItems[i].size;
|
|
|
|
if (flags == 0) { // Auto detect size
|
|
|
|
switch (snapshotItems[i].size) {
|
|
case 1: *(uint8_t *)data = read8(buffer); break;
|
|
case 2: *(uint16_t *)data = read16(buffer); break;
|
|
case 4: *(uint32_t *)data = read32(buffer); break;
|
|
case 8: *(uint64_t *)data = read64(buffer); break;
|
|
default: readBlock(buffer, (uint8_t *)data, size);
|
|
}
|
|
|
|
} else { // Format is specified manually
|
|
|
|
switch (flags) {
|
|
case BYTE_FORMAT: readBlock(buffer, (uint8_t *)data, size); break;
|
|
case WORD_FORMAT: readBlock16(buffer, (uint16_t *)data, size); break;
|
|
case DOUBLE_WORD_FORMAT: readBlock32(buffer, (uint32_t *)data, size); break;
|
|
case QUAD_WORD_FORMAT: readBlock64(buffer, (uint64_t *)data, size); break;
|
|
default: assert(0);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (*buffer - old != VirtualComponent::stateSize()) {
|
|
panic("loadFromBuffer: Snapshot size is wrong.");
|
|
assert(false);
|
|
}
|
|
}
|
|
|
|
void
|
|
VirtualComponent::saveToBuffer(uint8_t **buffer)
|
|
{
|
|
uint8_t *old = *buffer;
|
|
|
|
debug(3, " Saving internal state (%d bytes) ...\n", VirtualComponent::stateSize());
|
|
|
|
// Save internal state of sub components
|
|
if (subComponents != NULL) {
|
|
for (unsigned i = 0; subComponents[i] != NULL; i++)
|
|
subComponents[i]->saveToBuffer(buffer);
|
|
}
|
|
|
|
// Save own internal state
|
|
void *data; size_t size; int flags;
|
|
for (unsigned i = 0; snapshotItems != NULL && snapshotItems[i].data != NULL; i++) {
|
|
|
|
data = snapshotItems[i].data;
|
|
flags = snapshotItems[i].flags & 0x0F;
|
|
size = snapshotItems[i].size;
|
|
|
|
if (flags == 0) { // Auto detect size
|
|
|
|
switch (snapshotItems[i].size) {
|
|
case 1: write8(buffer, *(uint8_t *)data); break;
|
|
case 2: write16(buffer, *(uint16_t *)data); break;
|
|
case 4: write32(buffer, *(uint32_t *)data); break;
|
|
case 8: write64(buffer, *(uint64_t *)data); break;
|
|
default: writeBlock(buffer, (uint8_t *)data, size);
|
|
}
|
|
|
|
} else { // Format is specified manually
|
|
|
|
switch (flags) {
|
|
case BYTE_FORMAT: writeBlock(buffer, (uint8_t *)data, size); break;
|
|
case WORD_FORMAT: writeBlock16(buffer, (uint16_t *)data, size); break;
|
|
case DOUBLE_WORD_FORMAT: writeBlock32(buffer, (uint32_t *)data, size); break;
|
|
case QUAD_WORD_FORMAT: writeBlock64(buffer, (uint64_t *)data, size); break;
|
|
default: assert(0);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (*buffer - old != VirtualComponent::stateSize()) {
|
|
panic("saveToBuffer: Snapshot size is wrong.");
|
|
assert(false);
|
|
}
|
|
} |