mpw/cpu/CpuIntegration.c

390 lines
11 KiB
C

/*=========================================================================*/
/* Fellow */
/* Initialization of 68000 core */
/* Integrates the 68k emulation with custom chips */
/* */
/* Author: Petter Schau */
/* */
/* Copyright (C) 1991, 1992, 1996 Free Software Foundation, Inc. */
/* */
/* 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, 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 "defs.h"
#include "fellow.h"
#include "fmem.h"
#include "CpuModule.h"
#include "CpuIntegration.h"
#include "CpuModule_Internal.h"
#include "bus.h"
#include "fileops.h"
#include "interrupt.h"
jmp_buf cpu_integration_exception_buffer;
uint32_t cpu_integration_chip_interrupt_number;
/* Cycles spent by chips (Blitter) as a result of an instruction */
static uint32_t cpu_integration_chip_cycles;
static uint32_t cpu_integration_chip_slowdown;
/*===========================================================================*/
/* CPU properties */
/*===========================================================================*/
uint32_t cpu_integration_speed; // The speed as expressed in the fellow configuration settings
uint32_t cpu_integration_speed_multiplier; // The cycle multiplier used to adjust the cpu-speed, calculated from cpu_integration_speed
cpu_integration_models cpu_integration_model; // The cpu model as expressed in the fellow configuration settings
/*===========================================================================*/
/* CPU properties */
/*===========================================================================*/
void cpuIntegrationSetSpeed(uint32_t speed)
{
cpu_integration_speed = speed;
}
uint32_t cpuIntegrationGetSpeed(void)
{
return cpu_integration_speed;
}
static void cpuIntegrationSetSpeedMultiplier(uint32_t multiplier)
{
cpu_integration_speed_multiplier = multiplier;
}
static uint32_t cpuIntegrationGetSpeedMultiplier(void)
{
return cpu_integration_speed_multiplier;
}
void cpuIntegrationCalculateMultiplier(void)
{
uint32_t multiplier = 12;
switch (cpuGetModelMajor())
{
case 0:
multiplier = 12;
break;
case 1:
multiplier = 12;
break;
case 2:
multiplier = 11;
break;
case 3:
multiplier = 11;
break;
}
if (cpuIntegrationGetSpeed() >= 8) cpuIntegrationSetSpeedMultiplier(multiplier);
else if (cpuIntegrationGetSpeed() >= 4) cpuIntegrationSetSpeedMultiplier(multiplier - 1);
else if (cpuIntegrationGetSpeed() >= 2) cpuIntegrationSetSpeedMultiplier(multiplier - 2);
else if (cpuIntegrationGetSpeed() >= 1) cpuIntegrationSetSpeedMultiplier(multiplier - 3);
else cpuIntegrationSetSpeedMultiplier(multiplier - 4);
}
BOOLE cpuIntegrationSetModel(cpu_integration_models model)
{
BOOLE needreset = (cpu_integration_model != model);
cpu_integration_model = model;
switch (cpu_integration_model)
{
case M68000: cpuSetModel(0, 0); break;
case M68010: cpuSetModel(1, 0); break;
case M68020: cpuSetModel(2, 0); break;
case M68030: cpuSetModel(3, 0); break;
case M68EC20: cpuSetModel(2, 1); break;
case M68EC30: cpuSetModel(3, 1); break;
}
return needreset;
}
cpu_integration_models cpuIntegrationGetModel(void)
{
return cpu_integration_model;
}
void cpuIntegrationSetChipCycles(uint32_t chip_cycles)
{
cpu_integration_chip_cycles = chip_cycles;
}
uint32_t cpuIntegrationGetChipCycles(void)
{
return cpu_integration_chip_cycles;
}
void cpuIntegrationSetChipSlowdown(uint32_t chip_slowdown)
{
cpu_integration_chip_slowdown = chip_slowdown;
}
uint32_t cpuIntegrationGetChipSlowdown(void)
{
return cpu_integration_chip_slowdown;
}
void cpuIntegrationSetChipInterruptNumber(uint32_t chip_interrupt_number)
{
cpu_integration_chip_interrupt_number = chip_interrupt_number;
}
uint32_t cpuIntegrationGetChipInterruptNumber(void)
{
return cpu_integration_chip_interrupt_number;
}
// A wrapper for cpuSetIrqLevel that restarts the
// scheduling of cpu events if the cpu was stoppped
void cpuIntegrationSetIrqLevel(uint32_t new_interrupt_level, uint32_t chip_interrupt_number)
{
if (cpuSetIrqLevel(new_interrupt_level))
{
cpuEvent.cycle = busGetCycle();
}
cpuIntegrationSetChipInterruptNumber(chip_interrupt_number);
}
/*=========================================*/
/* Exception mid-instruction exit function */
/*=========================================*/
void cpuIntegrationMidInstructionExceptionFunc(void)
{
longjmp(cpu_integration_exception_buffer, -1);
}
/*===================================================*/
/* Handles reset exception event from the cpu-module */
/*===================================================*/
void cpuIntegrationResetExceptionFunc(void)
{
fellowSoftReset();
}
/*=========*/
/* Logging */
/*=========*/
#ifdef CPU_INSTRUCTION_LOGGING
FILE *CPUINSTRUCTIONLOG;
int cpu_disable_instruction_log = TRUE;
void cpuInstructionLogOpen(void)
{
if (CPUINSTRUCTIONLOG == NULL)
{
char filename[MAX_PATH];
fileopsGetGenericFileName(filename, "WinFellow", "cpuinstructions.log");
CPUINSTRUCTIONLOG = fopen(filename, "w");
}
}
void cpuIntegrationPrintBusCycle(void)
{
fprintf(CPUINSTRUCTIONLOG, "%I64u:%.5u ", bus.frame_no, bus.cycle);
}
void cpuIntegrationInstructionLogging(void)
{
char saddress[256], sdata[256], sinstruction[256], soperands[256];
if (cpu_disable_instruction_log) return;
cpuInstructionLogOpen();
/*
fprintf(CPUINSTRUCTIONLOG,
"D0:%.8X D1:%.8X D2:%.8X D3:%.8X D4:%.8X D5:%.8X D6:%.8X D7:%.8X\n",
cpuGetDReg(0),
cpuGetDReg(1),
cpuGetDReg(2),
cpuGetDReg(3),
cpuGetDReg(4),
cpuGetDReg(5),
cpuGetDReg(6),
cpuGetDReg(7));
fprintf(CPUINSTRUCTIONLOG,
"A0:%.8X A1:%.8X A2:%.8X A3:%.8X A4:%.8X A5:%.8X A6:%.8X A7:%.8X\n",
cpuGetAReg(0),
cpuGetAReg(1),
cpuGetAReg(2),
cpuGetAReg(3),
cpuGetAReg(4),
cpuGetAReg(5),
cpuGetAReg(6),
cpuGetAReg(7));
*/
saddress[0] = '\0';
sdata[0] = '\0';
sinstruction[0] = '\0';
soperands[0] = '\0';
cpuDisOpcode(cpuGetPC(), saddress, sdata, sinstruction, soperands);
fprintf(CPUINSTRUCTIONLOG, "SSP:%.6X USP:%.6X SP:%.4X %s %s\t%s\t%s\n", cpuGetSspDirect(), cpuGetUspDirect(), cpuGetSR(), saddress, sdata, sinstruction, soperands);
}
void cpuIntegrationExceptionLogging(char *description, uint32_t original_pc, uint16_t opcode)
{
if (cpu_disable_instruction_log) return;
cpuInstructionLogOpen();
cpuIntegrationPrintBusCycle();
fprintf(CPUINSTRUCTIONLOG, "%s for opcode %.4X at PC %.8X from PC %.8X\n", description, opcode, original_pc, cpuGetPC());
}
void cpuIntegrationInterruptLogging(uint32_t level, uint32_t vector_address)
{
if (cpu_disable_instruction_log) return;
cpuInstructionLogOpen();
cpuIntegrationPrintBusCycle();
fprintf(CPUINSTRUCTIONLOG, "Irq %u to %.6X (%s)\n", level, vector_address, interruptGetInterruptName(cpuIntegrationGetChipInterruptNumber()));
}
#endif
void cpuIntegrationExecuteInstructionEventHandler68000Fast(void)
{
uint32_t cycles = cpuExecuteInstruction();
if (cpuGetStop())
{
cpuEvent.cycle = BUS_CYCLE_DISABLE;
}
else
{
cpuEvent.cycle += ((cycles*cpuIntegrationGetChipSlowdown())>>1) + cpuIntegrationGetChipCycles();
}
cpuIntegrationSetChipCycles(0);
}
void cpuIntegrationExecuteInstructionEventHandler68000General(void)
{
uint32_t cycles = 0;
uint32_t time_used = 0;
do
{
cycles = cpuExecuteInstruction();
cycles = cycles*cpuIntegrationGetChipSlowdown(); // Compensate for blitter time
time_used += (cpuIntegrationGetChipCycles()<<12) + (cycles<<cpuIntegrationGetSpeedMultiplier());
}
while (time_used < 8192 && !cpuGetStop());
if (cpuGetStop())
{
cpuEvent.cycle = BUS_CYCLE_DISABLE;
}
else
{
cpuEvent.cycle += (time_used>>12);
}
cpuIntegrationSetChipCycles(0);
}
void cpuIntegrationExecuteInstructionEventHandler68020(void)
{
uint32_t time_used = 0;
do
{
cpuExecuteInstruction();
time_used += (cpuIntegrationGetChipCycles()<<12) + (4<<cpuIntegrationGetSpeedMultiplier());
}
while (time_used < 8192 && !cpuGetStop());
if (cpuGetStop())
{
cpuEvent.cycle = BUS_CYCLE_DISABLE;
}
else
{
cpuEvent.cycle += (time_used>>12);
}
cpuIntegrationSetChipCycles(0);
}
void cpuIntegrationSetDefaultConfig(void)
{
cpuIntegrationSetModel(M68000);
cpuIntegrationSetChipCycles(0);
cpuIntegrationSetChipSlowdown(1);
cpuIntegrationSetSpeed(4);
cpuSetCheckPendingInterruptsFunc(interruptRaisePending);
cpuSetMidInstructionExceptionFunc(cpuIntegrationMidInstructionExceptionFunc);
cpuSetResetExceptionFunc(cpuIntegrationResetExceptionFunc);
#ifdef CPU_INSTRUCTION_LOGGING
cpuSetInstructionLoggingFunc(cpuIntegrationInstructionLogging);
cpuSetExceptionLoggingFunc(cpuIntegrationExceptionLogging);
cpuSetInterruptLoggingFunc(cpuIntegrationInterruptLogging);
#endif
}
/*=========================*/
/* Fellow lifecycle events */
/*=========================*/
void cpuIntegrationSaveState(FILE *F)
{
cpuSaveState(F);
fwrite(&cpu_integration_chip_slowdown, sizeof(cpu_integration_chip_slowdown), 1, F);
// Everything else is configuration options which will be set when the associated config-file is loaded.
}
void cpuIntegrationLoadState(FILE *F)
{
cpuLoadState(F);
fread(&cpu_integration_chip_slowdown, sizeof(cpu_integration_chip_slowdown), 1, F);
// Everything else is configuration options which will be set when the associated config-file is loaded.
}
void cpuIntegrationEmulationStart(void)
{
cpuIntegrationCalculateMultiplier();
}
void cpuIntegrationEmulationStop(void)
{
}
void cpuIntegrationHardReset(void)
{
cpuIntegrationSetChipCycles(0);
cpuIntegrationSetChipSlowdown(1);
cpuSetInitialPC(memoryInitialPC());
cpuSetInitialSP(memoryInitialSP());
cpuHardReset();
}
void cpuIntegrationStartup(void)
{
cpuStartup();
cpuIntegrationSetDefaultConfig();
cpuCreateMulTimeTables();
}
void cpuIntegrationShutdown(void)
{
cpuProfileWrite();
}