mirror of
https://github.com/JorjBauer/aiie.git
synced 2025-02-27 08:29:15 +00:00
minor improvements on the debugger interface for the SDL build
This commit is contained in:
parent
03cdfdbc14
commit
b8d83843b7
@ -40,6 +40,7 @@ Debugger::Debugger()
|
|||||||
|
|
||||||
sd = socket(AF_INET, SOCK_STREAM, 0);
|
sd = socket(AF_INET, SOCK_STREAM, 0);
|
||||||
cd = -1;
|
cd = -1;
|
||||||
|
breakpoint = 0;
|
||||||
|
|
||||||
optval=1;
|
optval=1;
|
||||||
setsockopt(sd, SOL_SOCKET, SO_REUSEADDR,
|
setsockopt(sd, SOL_SOCKET, SO_REUSEADDR,
|
||||||
@ -72,29 +73,6 @@ void Debugger::step()
|
|||||||
static char buf[256];
|
static char buf[256];
|
||||||
|
|
||||||
if (cd != -1) {
|
if (cd != -1) {
|
||||||
bzero(buf,256);
|
|
||||||
int n = read( cd,buf,255 );
|
|
||||||
|
|
||||||
if (n < 0) {
|
|
||||||
// error
|
|
||||||
close(cd);
|
|
||||||
cd = -1;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (n > 0) {
|
|
||||||
if (buf[0] == 'c') {
|
|
||||||
// Continue - close connection
|
|
||||||
close(cd);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// ... ?
|
|
||||||
// b - set breakpoint
|
|
||||||
// s - step over
|
|
||||||
// S - step out
|
|
||||||
// c - continue (close connection)
|
|
||||||
// d - disassemble @ current PC
|
|
||||||
}
|
|
||||||
|
|
||||||
// Print the status back out the socket
|
// Print the status back out the socket
|
||||||
uint8_t p = g_cpu->flags;
|
uint8_t p = g_cpu->flags;
|
||||||
@ -124,11 +102,70 @@ void Debugger::step()
|
|||||||
buf[1] = 10;
|
buf[1] = 10;
|
||||||
write(cd, buf, 2);
|
write(cd, buf, 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (breakpoint && g_cpu->pc != breakpoint) {
|
||||||
|
// Running until we reach the breakpoint
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
bzero(buf,256);
|
||||||
|
int n = read( cd,buf,255 );
|
||||||
|
|
||||||
|
if (n < 0) {
|
||||||
|
// error
|
||||||
|
close(cd);
|
||||||
|
cd = -1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (n > 0) {
|
||||||
|
if (buf[0] == 'c') {
|
||||||
|
// Continue - close connection
|
||||||
|
close(cd);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (buf[0] == 'b') {
|
||||||
|
// FIXME: set breakpoint
|
||||||
|
if (buf[1] == ' ' &&
|
||||||
|
buf[2] == '0' &&
|
||||||
|
buf[3] == 'x') {
|
||||||
|
// Hex
|
||||||
|
breakpoint = strtol(&buf[4], NULL, 16);
|
||||||
|
} else if (buf[1] == ' ' &&
|
||||||
|
buf[2] == '$') {
|
||||||
|
// Also hex
|
||||||
|
breakpoint = strtol(&buf[3], NULL, 16);
|
||||||
|
} else if (sscanf(buf, "b %d", &breakpoint) == 1) {
|
||||||
|
// decimal
|
||||||
|
} else {
|
||||||
|
breakpoint = 0;
|
||||||
|
}
|
||||||
|
if (breakpoint) {
|
||||||
|
snprintf(buf, sizeof(buf), "Breakpoint set to 0x%X\012\015", breakpoint);
|
||||||
|
write(cd, buf, strlen(buf));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ... ?
|
||||||
|
// b - set breakpoint
|
||||||
|
// s - step over
|
||||||
|
// S - step out
|
||||||
|
// c - continue (close connection)
|
||||||
|
// d - disassemble @ current PC
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Debugger::setSocket(int fd)
|
void Debugger::setSocket(int fd)
|
||||||
{
|
{
|
||||||
|
printf("New debugger session established\n");
|
||||||
cd = fd;
|
cd = fd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Debugger::active()
|
||||||
|
{
|
||||||
|
return (cd != -1);
|
||||||
|
}
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
#define __DEBUGGER_H
|
#define __DEBUGGER_H
|
||||||
|
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
|
#include <inttypes.h>
|
||||||
|
|
||||||
class Debugger {
|
class Debugger {
|
||||||
public:
|
public:
|
||||||
@ -10,12 +11,14 @@ class Debugger {
|
|||||||
|
|
||||||
void setSocket(int cliSock);
|
void setSocket(int cliSock);
|
||||||
void step();
|
void step();
|
||||||
|
bool active();
|
||||||
|
|
||||||
// private:
|
// private:
|
||||||
int sd; // server (listener)
|
int sd; // server (listener)
|
||||||
int cd; // client (connected to us)
|
int cd; // client (connected to us)
|
||||||
pthread_t listenThreadID;
|
pthread_t listenThreadID;
|
||||||
|
|
||||||
|
uint32_t breakpoint;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
206
sdl/aiie.cpp
206
sdl/aiie.cpp
@ -22,7 +22,6 @@
|
|||||||
|
|
||||||
//#define SHOWFPS
|
//#define SHOWFPS
|
||||||
//#define SHOWPC
|
//#define SHOWPC
|
||||||
//#define DEBUGCPU
|
|
||||||
//#define SHOWMEMPAGE
|
//#define SHOWMEMPAGE
|
||||||
|
|
||||||
BIOS bios;
|
BIOS bios;
|
||||||
@ -51,7 +50,8 @@ void writePrefs();
|
|||||||
|
|
||||||
void sigint_handler(int n)
|
void sigint_handler(int n)
|
||||||
{
|
{
|
||||||
send_rst = 1;
|
// If we want control-C to reset the machine, then set this here...
|
||||||
|
// send_rst = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void nonblock(int state)
|
void nonblock(int state)
|
||||||
@ -91,7 +91,7 @@ void write(void *arg, uint16_t address, uint8_t v)
|
|||||||
|
|
||||||
static void *cpu_thread(void *dummyptr) {
|
static void *cpu_thread(void *dummyptr) {
|
||||||
struct timespec currentTime;
|
struct timespec currentTime;
|
||||||
struct timespec nextCycleTime;
|
struct timespec nextSpeakerCycleTime;
|
||||||
uint32_t nextSpeakerCycle = 0;
|
uint32_t nextSpeakerCycle = 0;
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
@ -108,6 +108,12 @@ static void *cpu_thread(void *dummyptr) {
|
|||||||
do_gettime(&nextInstructionTime);
|
do_gettime(&nextInstructionTime);
|
||||||
|
|
||||||
printf("free-running\n");
|
printf("free-running\n");
|
||||||
|
|
||||||
|
// In this loop, we determine when the next CPU or Speaker event is;
|
||||||
|
// sleep until that event; and then perform the event. There are a
|
||||||
|
// number of maintenance tasks that also happen to be sure that
|
||||||
|
// peripherals are updated appropriately.
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
if (g_biosInterrupt) {
|
if (g_biosInterrupt) {
|
||||||
printf("BIOS blocking\n");
|
printf("BIOS blocking\n");
|
||||||
@ -134,117 +140,82 @@ static void *cpu_thread(void *dummyptr) {
|
|||||||
|
|
||||||
do_gettime(¤tTime);
|
do_gettime(¤tTime);
|
||||||
|
|
||||||
/* The speaker is our priority. The CPU runs in batches anyway,
|
// FIXME: these first two can go in their respective loops after execution
|
||||||
sometimes a little behind and sometimes a little ahead; but the
|
|
||||||
speaker has to be right on time. */
|
|
||||||
|
|
||||||
// Wait until nextSpeakerCycle
|
// Determine the next speaker runtime (nextSpeakerCycle).
|
||||||
timespec_add_cycles(&startTime, nextSpeakerCycle, &nextCycleTime);
|
// The speaker runs 48 cycles behind the CPU (an arbitrary number).
|
||||||
|
timespec_add_cycles(&startTime, nextSpeakerCycle-48, &nextSpeakerCycleTime);
|
||||||
|
|
||||||
struct timespec diff = tsSubtract(nextCycleTime, currentTime);
|
// Determine the next CPU runtime (nextInstructionTime)
|
||||||
if (diff.tv_sec >= 0 || diff.tv_nsec >= 0) {
|
timespec_add_cycles(&startTime, g_cpu->cycles, &nextInstructionTime);
|
||||||
nanosleep(&diff, NULL);
|
|
||||||
|
// Sleep until one of them is ready to run.
|
||||||
|
|
||||||
|
// tsSubtract doesn't return negatives; it bounds at zero. So if
|
||||||
|
// either result is zero then it's time to run something.
|
||||||
|
|
||||||
|
struct timespec cpudiff = tsSubtract(nextInstructionTime, currentTime);
|
||||||
|
struct timespec spkrdiff = tsSubtract(nextSpeakerCycleTime, currentTime);
|
||||||
|
|
||||||
|
struct timespec mindiff;
|
||||||
|
if (cpudiff.tv_sec < spkrdiff.tv_sec) {
|
||||||
|
memcpy(&mindiff, &cpudiff, sizeof(struct timespec));
|
||||||
|
} else if (spkrdiff.tv_sec < cpudiff.tv_sec) {
|
||||||
|
memcpy(&mindiff, &spkrdiff, sizeof(struct timespec));
|
||||||
|
} else if (cpudiff.tv_nsec < spkrdiff.tv_nsec) {
|
||||||
|
memcpy(&mindiff, &cpudiff, sizeof(struct timespec));
|
||||||
|
} else {
|
||||||
|
memcpy(&mindiff, &spkrdiff, sizeof(struct timespec));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mindiff.tv_sec > 0 || mindiff.tv_nsec > 0) {
|
||||||
|
// Sleep until the first of them is ready & loop...
|
||||||
|
nanosleep(&mindiff, NULL);
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Speaker runs 48 cycles behind the CPU (an arbitrary number)
|
// Now we know either the speaker or the CPU is ready to
|
||||||
if (nextSpeakerCycle >= 48) {
|
// run. Figure out which and run it.
|
||||||
timespec_add_cycles(&startTime, nextSpeakerCycle-48, &nextCycleTime);
|
|
||||||
uint64_t microseconds = nextCycleTime.tv_sec * 1000000 +
|
if (spkrdiff.tv_sec == 0 && spkrdiff.tv_nsec == 0) {
|
||||||
(double)nextCycleTime.tv_nsec / 1000.0;
|
// Run the speaker
|
||||||
|
|
||||||
|
uint64_t microseconds = nextSpeakerCycleTime.tv_sec * 1000000 +
|
||||||
|
(double)nextSpeakerCycleTime.tv_nsec / 1000.0;
|
||||||
g_speaker->maintainSpeaker(nextSpeakerCycle-48, microseconds);
|
g_speaker->maintainSpeaker(nextSpeakerCycle-48, microseconds);
|
||||||
|
|
||||||
|
nextSpeakerCycle++;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Bump speaker cycle for next go-round
|
if (cpudiff.tv_sec == 0 && cpudiff.tv_nsec == 0) {
|
||||||
nextSpeakerCycle++;
|
// Run the CPU
|
||||||
|
|
||||||
|
uint8_t executed = 0;
|
||||||
/* Next up is the CPU. */
|
if (debugger.active()) {
|
||||||
|
// With the debugger running, we need to single-step through
|
||||||
// tsSubtract doesn't return negatives; it bounds at 0.
|
// instructions.
|
||||||
diff = tsSubtract(nextInstructionTime, currentTime);
|
executed = g_cpu->Run(1);
|
||||||
|
} else {
|
||||||
uint8_t executed = 0;
|
// Otherwise we can run a bunch of instructions at once to
|
||||||
if (diff.tv_sec == 0 && diff.tv_nsec == 0) {
|
// save on the overhead.
|
||||||
#ifdef DEBUGCPU
|
executed = g_cpu->Run(24);
|
||||||
executed = g_cpu->Run(1);
|
}
|
||||||
#else
|
|
||||||
executed = g_cpu->Run(24);
|
|
||||||
#endif
|
|
||||||
// calculate the real time that we should be at now, and schedule
|
|
||||||
// that as our next instruction time
|
|
||||||
timespec_add_cycles(&startTime, g_cpu->cycles, &nextInstructionTime);
|
|
||||||
|
|
||||||
// The paddles need to be triggered in real-time on the CPU
|
// The paddles need to be triggered in real-time on the CPU
|
||||||
// clock. That happens from the VM's CPU maintenance poller.
|
// clock. That happens from the VM's CPU maintenance poller.
|
||||||
((AppleVM *)g_vm)->cpuMaintenance(g_cpu->cycles);
|
((AppleVM *)g_vm)->cpuMaintenance(g_cpu->cycles);
|
||||||
|
|
||||||
#ifdef DEBUGCPU
|
if (debugger.active()) {
|
||||||
debugger.step();
|
debugger.step();
|
||||||
#endif
|
}
|
||||||
|
|
||||||
if (send_rst) {
|
if (send_rst) {
|
||||||
cpuDebuggerRunning = true;
|
cpuDebuggerRunning = true;
|
||||||
|
|
||||||
#if 0
|
|
||||||
printf("Scheduling suspend request...\n");
|
|
||||||
wantSuspend = true;
|
|
||||||
#endif
|
|
||||||
#if 0
|
|
||||||
printf("Scheduling resume resume request...\n");
|
|
||||||
wantResume = true;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
printf("Sending reset\n");
|
printf("Sending reset\n");
|
||||||
g_cpu->Reset();
|
g_cpu->Reset();
|
||||||
|
|
||||||
// testing startup keyboard presses - perform Apple //e self-test
|
send_rst = 0;
|
||||||
//g_vm->getKeyboard()->keyDepressed(RA);
|
|
||||||
//g_vm->Reset();
|
|
||||||
//g_cpu->Reset();
|
|
||||||
//((AppleVM *)g_vm)->insertDisk(0, "disks/DIAGS.DSK");
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
// Swap disks
|
|
||||||
if (disk1name[0] && disk2name[0]) {
|
|
||||||
printf("Swapping disks\n");
|
|
||||||
|
|
||||||
printf("Inserting disk %s in drive 1\n", disk2name);
|
|
||||||
((AppleVM *)g_vm)->insertDisk(0, disk2name);
|
|
||||||
printf("Inserting disk %s in drive 2\n", disk1name);
|
|
||||||
((AppleVM *)g_vm)->insertDisk(1, disk1name);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
MMU *mmu = g_vm->getMMU();
|
|
||||||
|
|
||||||
printf("PC: 0x%X\n", g_cpu->pc);
|
|
||||||
for (int i=g_cpu->pc; i<g_cpu->pc + 0x100; i++) {
|
|
||||||
printf("0x%X ", mmu->read(i));
|
|
||||||
}
|
|
||||||
printf("\n");
|
|
||||||
|
|
||||||
printf("Dropping to monitor\n");
|
|
||||||
// drop directly to monitor.
|
|
||||||
g_cpu->pc = 0xff69; // "call -151"
|
|
||||||
mmu->read(0xC054); // make sure we're in page 1
|
|
||||||
mmu->read(0xC056); // and that hires is off
|
|
||||||
mmu->read(0xC051); // and text mode is on
|
|
||||||
mmu->read(0xC08A); // and we have proper rom in place
|
|
||||||
mmu->read(0xc008); // main zero-page
|
|
||||||
mmu->read(0xc006); // rom from cards
|
|
||||||
mmu->write(0xc002 + mmu->read(0xc014)? 1 : 0, 0xff); // make sure aux ram read and write match
|
|
||||||
mmu->write(0x20, 0); // text window
|
|
||||||
mmu->write(0x21, 40);
|
|
||||||
mmu->write(0x22, 0);
|
|
||||||
mmu->write(0x23, 24);
|
|
||||||
mmu->write(0x33, '>');
|
|
||||||
mmu->write(0x48, 0); // from 0xfb2f: part of text init
|
|
||||||
#endif
|
|
||||||
|
|
||||||
send_rst = 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -252,34 +223,6 @@ static void *cpu_thread(void *dummyptr) {
|
|||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
#if 0
|
|
||||||
// Timing consistency check
|
|
||||||
|
|
||||||
sleep(2); // kinda random, hopefully sloppy? - to make startTime != 0,0
|
|
||||||
printf("starting time consistency check\n");
|
|
||||||
do_gettime(&startTime);
|
|
||||||
for (int i=0; i<10000000; i++) {
|
|
||||||
|
|
||||||
// Calculate the time delta from startTime to cycle # i
|
|
||||||
timespec_add_cycles(&startTime, i, &nextInstructionTime);
|
|
||||||
|
|
||||||
// Recalculate the time difference between nextInstructionTime and startTime
|
|
||||||
struct timespec runtime = tsSubtract(nextInstructionTime, startTime);
|
|
||||||
|
|
||||||
// See if it's the same as cycles_since_time
|
|
||||||
double guesstimate = cycles_since_time(&runtime);
|
|
||||||
printf("cycle %d guesstimate %f\n", i, guesstimate);
|
|
||||||
if (guesstimate != i) {
|
|
||||||
printf("FAILED: cycle %d has guesstimate %f\n", i, guesstimate);
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
printf("All ok\n");
|
|
||||||
|
|
||||||
exit(1);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
SDL_Init(SDL_INIT_EVERYTHING);
|
SDL_Init(SDL_INIT_EVERYTHING);
|
||||||
|
|
||||||
g_speaker = new SDLSpeaker();
|
g_speaker = new SDLSpeaker();
|
||||||
@ -344,7 +287,9 @@ int main(int argc, char *argv[])
|
|||||||
// pthread_setschedparam(cpuThreadID, SCHED_RR, PTHREAD_MAX_PRIORITY);
|
// pthread_setschedparam(cpuThreadID, SCHED_RR, PTHREAD_MAX_PRIORITY);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint32_t lastCycleCount = -1;
|
||||||
while (1) {
|
while (1) {
|
||||||
|
|
||||||
if (g_biosInterrupt) {
|
if (g_biosInterrupt) {
|
||||||
printf("Invoking BIOS\n");
|
printf("Invoking BIOS\n");
|
||||||
if (bios.runUntilDone()) {
|
if (bios.runUntilDone()) {
|
||||||
@ -378,7 +323,7 @@ int main(int argc, char *argv[])
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static uint32_t usleepcycles = 16384; // step-down for display drawing. Dynamically updated based on FPS calculations.
|
static uint32_t usleepcycles = 16384*4; // step-down for display drawing. Dynamically updated based on FPS calculations.
|
||||||
|
|
||||||
// fill disk buffer when needed
|
// fill disk buffer when needed
|
||||||
((AppleVM*)g_vm)->disk6->fillDiskBuffer();
|
((AppleVM*)g_vm)->disk6->fillDiskBuffer();
|
||||||
@ -413,9 +358,9 @@ int main(int argc, char *argv[])
|
|||||||
g_display->debugMsg(buf);
|
g_display->debugMsg(buf);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (fps > 60) {
|
if (fps > 30 && usleepcycles < 0x3FFFFFFF) {
|
||||||
usleepcycles *= 2;
|
usleepcycles *= 2;
|
||||||
} else if (fps < 40) {
|
} else if (fps < 20 && usleepcycles > 0xF) {
|
||||||
usleepcycles /= 2;
|
usleepcycles /= 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -451,6 +396,15 @@ int main(int argc, char *argv[])
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
if (g_cpu->cycles == lastCycleCount) {
|
||||||
|
// If the CPU didn't advance during our last loop, then delay
|
||||||
|
// here; there can't be any substantial updates, so no need to
|
||||||
|
// beat up the host machine
|
||||||
|
|
||||||
|
usleep(100000);
|
||||||
|
} else {
|
||||||
|
lastCycleCount = g_cpu->cycles;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user