# by James Hammons
# (C) 2012 Underground Software
#
-echo "Cross compiling for Win32..."
+#PREFIX=i686-pc-mingw32.static
+#echo "Cross compiling for Win32..."
+echo "Cross compiling for Win64..."
export PATH=/opt/mxe/usr/bin:$PATH
rm makefile-qt
-make CROSS=i686-pc-mingw32-
+#make CROSS=i686-pc-mingw32.static-
+make CROSS=x86_64-w64-mingw32.static-
#rel=`svn info | grep Revision | cut -f 2 -d ' '`
rel=`git log -1 --pretty=format:%ci | cut -d ' ' -f 1 | tr -d -`
cd release && upx -9v virtualjaguar.exe && zip -9v vj-$rel.zip virtualjaguar.exe
+
dsp_opcode_use[i] = 0;
}
+
void DSPReleaseTimeslice(void)
{
//This does absolutely nothing!!! !!! FIX !!!
dsp_releaseTimeSlice_flag = 1;
}
+
void dsp_build_branch_condition_table(void)
{
// Fill in the mirror table
}
}
+
uint8_t DSPReadByte(uint32_t offset, uint32_t who/*=UNKNOWN*/)
{
if (offset >= 0xF1A000 && offset <= 0xF1A0FF)
{
uint32_t data = DSPReadLong(offset & 0xFFFFFFFC, who);
- if ((offset&0x03)==0)
- return(data>>24);
- else
- if ((offset&0x03)==1)
- return((data>>16)&0xff);
- else
- if ((offset&0x03)==2)
- return((data>>8)&0xff);
- else
- if ((offset&0x03)==3)
- return(data&0xff);
+ if ((offset & 0x03) == 0)
+ return (data >> 24);
+ else if ((offset & 0x03) == 1)
+ return ((data >> 16) & 0xFF);
+ else if ((offset & 0x03) == 2)
+ return ((data >> 8) & 0xFF);
+ else if ((offset & 0x03) == 3)
+ return (data & 0xFF);
}
return JaguarReadByte(offset, who);
}
+
uint16_t DSPReadWord(uint32_t offset, uint32_t who/*=UNKNOWN*/)
{
if (offset >= 0xF1A000 && offset <= 0xF1A0FF)
return JaguarReadWord(offset, who);
}
+
uint32_t DSPReadLong(uint32_t offset, uint32_t who/*=UNKNOWN*/)
{
if (offset >= 0xF1A000 && offset <= 0xF1A0FF)
return JaguarReadLong(offset, who);
}
+
void DSPWriteByte(uint32_t offset, uint8_t data, uint32_t who/*=UNKNOWN*/)
{
if (offset >= 0xF1A000 && offset <= 0xF1A0FF)
WriteLog("DSP: WriteByte--Attempt to write to DSP register file by %s!\n", whoName[who]);
- if ((offset >= DSP_WORK_RAM_BASE) && (offset < DSP_WORK_RAM_BASE+0x2000))
+ if ((offset >= DSP_WORK_RAM_BASE) && (offset < DSP_WORK_RAM_BASE + 0x2000))
{
offset -= DSP_WORK_RAM_BASE;
dsp_ram_8[offset] = data;
}*/
return;
}
- if ((offset >= DSP_CONTROL_RAM_BASE) && (offset < DSP_CONTROL_RAM_BASE+0x20))
+ if ((offset >= DSP_CONTROL_RAM_BASE) && (offset < DSP_CONTROL_RAM_BASE + 0x20))
{
uint32_t reg = offset & 0x1C;
int bytenum = offset & 0x03;
}
// WriteLog("dsp: writing %.2x at 0x%.8x\n",data,offset);
//Should this *ever* happen??? Shouldn't we be saying "unknown" here???
+// Well, yes, it can. There are 3 MMU users after all: 68K, GPU & DSP...!
JaguarWriteByte(offset, data, who);
}
+
void DSPWriteWord(uint32_t offset, uint16_t data, uint32_t who/*=UNKNOWN*/)
{
if (offset >= 0xF1A000 && offset <= 0xF1A0FF)
JaguarWriteWord(offset, data, who);
}
+
//bool badWrite = false;
void DSPWriteLong(uint32_t offset, uint32_t data, uint32_t who/*=UNKNOWN*/)
{
JaguarWriteLong(offset, data, who);
}
+
//
// Update the DSP register file pointers depending on REGPAGE bit
//
#endif
}
+
//
// Check for and handle any asserted DSP IRQs
//
FlushDSPPipeline();
}
+
//
// Non-pipelined version...
//
//!!!!!!!!
}
+
//
// Set the specified DSP IRQ line to a given state
//
// GPUSetIRQLine(GPUIRQ_DSP, ASSERT_LINE);
}
+
bool DSPIsRunning(void)
{
return (DSP_RUNNING ? true : false);
}
+
void DSPInit(void)
{
// memory_malloc_secure((void **)&dsp_ram_8, 0x2000, "DSP work RAM");
DSPReset();
}
+
void DSPReset(void)
{
dsp_pc = 0x00F1B000;
*((uint32_t *)(&dsp_ram_8[i])) = rand();
}
+
void DSPDumpDisassembly(void)
{
char buffer[512];
}
}
+
void DSPDumpRegisters(void)
{
//Shoud add modulus, etc to dump here...
}
}
+
void DSPDone(void)
{
int i, j;
// JLH = James Hammons <jlhamm@acm.org>
//
// Who When What
-// --- ---------- -------------------------------------------------------------
+// --- ---------- ------------------------------------------------------------
// JLH 01/16/2010 Created this log ;-)
-// JLH 02/28/2010 Added functions to look inside .ZIP files and handle contents
+// JLH 02/28/2010 Added functions to look inside .ZIP files and handle
+// contents
// JLH 06/01/2012 Added function to check ZIP file CRCs against file DB
//
//
// Jaguar file loading
-// We do a more intelligent file analysis here instead of relying on (possible false)
-// file extensions which people don't seem to give two shits about anyway. :-(
+// We do a more intelligent file analysis here instead of relying on (possible
+// false) file extensions which people don't seem to give two shits about
+// anyway. :-(
//
bool JaguarLoadFile(char * path)
{
delete[] buffer;
// Maybe instead of this, we could try requiring the STUBULATOR ROM? Just a thought...
- // Try setting the vector to say, $1000 and putting an instruction there that loops forever:
+ // Try setting the vector to say, $1000 and putting an instruction there
+ // that loops forever:
// This kludge works! Yeah!
SET32(jaguarMainRAM, 0x10, 0x00001000); // Set Exception #4 (Illegal Instruction)
SET16(jaguarMainRAM, 0x1000, 0x60FE); // Here: bra Here
// JLH = James Hammons <jlhamm@acm.org>
//
// Who When What
-// --- ---------- -------------------------------------------------------------
+// --- ---------- ------------------------------------------------------------
// JLH 02/15/2010 Created this file
//
// JLH = James Hammons <jlhamm@acm.org>
//
// Who When What
-// --- ---------- -------------------------------------------------------------
+// --- ---------- ------------------------------------------------------------
// JLH 01/29/2010 Created this file
// JLH 06/23/2011 Added initial implementation
// JLH 10/14/2011 Fixed possibly missing final slash in paths
}
#warning "!!! Need to load settings from controller profile !!!"
+// We do this now, but not here. Need to fix this...
#if 0
for(int i=0; i<21; i++)
{
}
#warning "!!! Need to save settings to controller profile !!!"
+// We do this now, but not here. Need to fix this...
+#if 0
for(int i=0; i<21; i++)
{
// We need to find the right profile and load it up here...
vjs.p1KeyBindings[i] = controllerTab1->controllerWidget->keys[i];
// vjs.p2KeyBindings[i] = controllerTab2->controllerWidget->keys[i];
}
+#endif
}
// --- ---------- ------------------------------------------------------------
// JLH 06/23/2011 Created this file
// JLH 07/20/2011 Fixed a bunch of stuff
+// JLH 10/02/2014 Fixed even more stuff, related to the profile system
//
+/*
+To really fix this shit, we have to straighten out some stuff. So here goes:
+
+We have a database of profiles consisting of a device list (devices that have
+been seen already) and map list (consisting of a key into the device list, a
+human readable name, a preferred slot #, and a key/button mapping). This is a
+list that can hold up to 64 different profiles.
+
+We have a a list of attached gamepads in Gamepad::. There can be 8 at most
+attached any one time.
+
+There are two game port slots that a controller can be hooked into.
+
+So, what we need to do when configuring and/or using this system is this.
+
+ - Populate the device combobox with the list of attached devices from the
+ profile database.
+ - Populate the map to combobox with the profiles associated with that profile
+ device number.
+ - Save stuff when the user changes stuff (this happens already)
+*/
+
#include "controllertab.h"
#include "controllerwidget.h"
mapToList->addItem(tr("Controller #2"), CONTROLLER2);
mapToList->addItem(tr("Either one that's free"), CONTROLLER1 | CONTROLLER2);
}
-/*
-So now we come to implementation. When changing devices, could have a helper function
-in profile.cpp that fills the mapNameList combobox with the appropriate names/profile
-numbers.
-
-There needs to be some way of getting data from the ControllerWidget and the current
-profile.
-
-Gamepad will have to have some way of knowing which profile is mapped to which
-Jaguar controllers and filtering out everything else.
-
-Will have to have some intelligent handling of profiles when first run, to see first
-what is connected and second, to assign profiles to Jaguar controllers. In this
-case, keyboard is the lowest priority--if a controller is plugged in and assigned to
-the same Jaguar controller as a keyboard, the controller is used. Not sure what to
-do in the case of multiple controllers plugged in and assigned to the same Jaguar
-controller.
-
-Also, need a way to load/save profiles.
-
-Meaning of checkboxes: None checked == profile not used.
-1 checked == prefer connection to Jaguar controller X.
-2 checked == no preference, use any available.
-
-Single mapping cannot be deleted ("-" will be disabled). Can always add, up to the max
-limit of profiles (MAX_PROFILES).
-
-------------------------------
-
-Now the main window passes in/removes the last edited profile #. From here, when starting
-up, we need to pull that number from the profile store and populate all our boxes.
-
--------------------------------
-
-Need to do AutoConnectProfiles from here, and detect any conflicts
-*/
ControllerTab::~ControllerTab()
if (deviceNumIndex == -1 || mapNumIndex == -1)
{
// We're doing the default, so set it up...
-// mapToList->setCurrentIndex(mapToList->findData(profile[0].preferredController));
-//printf("ControllerTab::SetupLastUsedProfile: [FAILED] profileNum=%i, controllerIndex=%i, preferredController=%i\n", profileNum, controllerIndex, profile[0].preferredController);
-// return;
deviceNumIndex = 0;
mapNumIndex = 0;
profileNum = 0;
deviceList->setCurrentIndex(deviceNumIndex);
mapNameList->setCurrentIndex(mapNumIndex);
-//no more: #warning "!!! bug in here where it doesn't save your preferred controller !!!"
- int controllerIndex = mapToList->findData(profile[profileNum].preferredController);
+ int controllerIndex = mapToList->findData(profile[profileNum].preferredSlot);
mapToList->setCurrentIndex(controllerIndex);
-//printf("ControllerTab::SetupLastUsedProfile: profileNum=%i, controllerIndex=%i, preferredController=%i\n", profileNum, controllerIndex, profile[profileNum].preferredController);
// We have to do this manually, since it's no longer done automagically...
ChangeDevice(deviceNumIndex);
void ControllerTab::UpdateProfileConnections(int selection)
{
-// profile[profileNum].preferredController = (controller1->isChecked() ? CONTROLLER1 : 0) | (controller2->isChecked() ? CONTROLLER2 : 0);
- profile[profileNum].preferredController = mapToList->itemData(selection).toInt();
-//printf("Setting profile #%i 'Maps To' to %i...\n", profileNum, mapToList->itemData(selection).toInt());
+ profile[profileNum].preferredSlot = mapToList->itemData(selection).toInt();
}
void ControllerTab::ChangeDevice(int selection)
{
-//printf("ControllerTab::ChangeDevice\n");
int deviceNum = deviceList->itemData(selection).toInt();
mapNameList->clear();
int numberOfMappings = FindMappingsForDevice(deviceNum, mapNameList);
+ // Make sure to disable the "-" button is there's only one mapping for this
+ // device...
deleteMapName->setDisabled(numberOfMappings == 1 ? true : false);
-//printf("Found %i mappings for device #%u...\n", numberOfMappings, deviceNum);
+ // Set up new profile #...
+ ChangeMapName(0);
}
void ControllerTab::ChangeMapName(int selection)
{
-//printf("ControllerTab::ChangeMapName\n");
profileNum = mapNameList->itemData(selection).toInt();
-//printf("You selected mapping: %s (profile #%u)\n", (mapNameList->itemText(selection)).toAscii().data(), profileNum);
for(int i=BUTTON_FIRST; i<=BUTTON_LAST; i++)
controllerWidget->keys[i] = profile[profileNum].map[i];
controllerWidget->update();
-// controller1->setChecked(profile[profileNum].preferredController & CONTROLLER1);
-// controller2->setChecked(profile[profileNum].preferredController & CONTROLLER2);
- mapToList->setCurrentIndex(mapToList->findData(profile[profileNum].preferredController));
+ mapToList->setCurrentIndex(mapToList->findData(profile[profileNum].preferredSlot));
}
if (freeProfile == -1)
{
// Oh crap, we're out of room! Alert the media!
- // (Really, tho, we should pop this up *before* asking for user input.
- // Which we now do!)
-#if 0
- QMessageBox msg;
- msg.setText(QString(tr("Can't create any more profiles!")));
- msg.setIcon(QMessageBox::Warning);
- msg.exec();
-#else
QMessageBox::warning(this, tr("Houston, we have a problem..."), tr("Can't create any more profiles!"));
-#endif
return;
}
profile[profileNum].device = deviceList->itemData(deviceList->currentIndex()).toInt();
strncpy(profile[profileNum].mapName, text.toAscii().data(), 31);
profile[profileNum].mapName[31] = 0;
- profile[profileNum].preferredController = CONTROLLER1;
+ profile[profileNum].preferredSlot = CONTROLLER1;
for(int i=BUTTON_FIRST; i<BUTTON_LAST; i++)
profile[profileNum].map[i] = '*';
void ControllerTab::DeleteMapName(void)
{
-//printf("Delete current mapping (TODO)...\n");
-
- // hmm, don't need to check this... Because presumably, it's already been checked for.
-// if (mapNameList->count() == 1) ;
-
QMessageBox::StandardButton retVal = QMessageBox::question(this, tr("Remove Mapping"), tr("Are you sure you want to remove this mapping?"), QMessageBox::No | QMessageBox::Yes, QMessageBox::No);
if (retVal == QMessageBox::No)
DeleteProfile(profileToRemove);
}
-
-/*
-The profiles need the following:
-
- - The name of the controller
- - A unique human readable ID
- - The key definitions for that controller (keyboard keys can be mixed in)
-
-So there can be more than one profile for each unique controller; the
-relationship is many-to-one. So basically, how it works it like this: SDL
-reports all connected controllers. If there are none connected, the default
-controller is the keyboard (which can have multiple profiles). The UI only
-presents those profiles which are usuable with the controllers that are plugged
-in, all else is ignored. The user can pick the profile for the controller and
-configure the keys for it; the UI automagically saves everything.
-
-How to handle the case of identical controllers being plugged in? How does the
-UI know which is which? Each controller will have a mapping to a default
-Jaguar controller (#1 or #2). Still doesn't prevent confusion though. Actually,
-it can: The profile can have a field that maps it to a preferred Jaguar
-controller, which can also be both (#1 AND #2--in this case we can set it to
-zero which means no preference). If the UI detects two of the same controller
-and each can be mapped to the same profile, it assigns them in order since it
-doesn't matter, the profiles are identical.
-
-The default profile is always available and is the keyboard (hey, we're PC
-centric here). The default profile is usually #0.
-
-Can there be more than one keyboard profile? Why not? You will need separate
-ones for controller #1 and controller #2.
-
-A profile might look like this:
-
-Field 1: Nostomo N45 Analog
-Field 2: Dad's #1
-Field 3: Jaguar controller #1
-Field 4: The button/stick mapping
-
-Profile # would be implicit in the order that they are stored in the internal
-data structure.
-
-When a new controller is plugged in with no profiles attached, it defaults to
-a set keyboard layout which the user can change. So every new controller will
-always have at least one profile.
-
-Data structures:
-The Gamepad class has the name of the controller (except for Keyboard)
-The profile list is just a list
-The controller name index + profile index makes a unique key
-Probably the best way to deal with it is to stuff the name/profile indices
-into the key definition structure.
-
-#define CONTROLLER1 0x01
-#define CONTROLLER2 0x02
-
-struct Profile
-{
- int device; // Host device number
- char mapName[32]; // Human readable map name
- int preferredController; // CONTROLLER1 and/or CONTROLLER2
- int map[21]; // Keys/buttons/axes
-};
-
-NOTE that device is an int, and the list is maintained elsewhere. It is
-*not* the same as what you see in GetJoystickName(); the device names have
-to be able to persist even when not available.
-
-Where to store the master profile list? It has to be accessible to this class.
-vjs.profile[x] would be good, but it's not really a concern for the Jaguar core.
-So it shouldn't go there. There should be a separate global setting place for
-GUI stuff...
-*/
-
#include "keygrabber.h"
-// These tables are used to convert Qt keycodes into human readable form. Note that
-// a lot of these are just filler.
+// These tables are used to convert Qt keycodes into human readable form. Note
+// that a lot of these are just filler.
char ControllerWidget::keyName1[96][16] = {
"Space",
"!", "\"", "#", "$", "%", "&", "'", "(", ")", "*", "+", ",", "-", ".", "/",
// JLH = James Hammons <jlhamm@acm.org>
//
// Who When What
-// --- ---------- -------------------------------------------------------------
+// --- ---------- ------------------------------------------------------------
// JLH 01/05/2013 Created this file
//
// Class member initialization
/*static*/ int Gamepad::numJoysticks = 0;
/*static*/ SDL_Joystick * Gamepad::pad[8];
-/*static*/ const char * Gamepad::padName[8];
+/*static*/ char Gamepad::padName[8][128];
/*static*/ int Gamepad::numButtons[8];
/*static*/ int Gamepad::numHats[8];
/*static*/ int Gamepad::numAxes[8];
for(int i=0; i<numJoysticks; i++)
{
pad[i] = SDL_JoystickOpen(i);
- padName[i] = SDL_JoystickName(i);
numButtons[i] = numHats[i] = numAxes[i] = 0;
+ // We need to copy the contents of this pointer, as SDL will change it
+ // willy nilly to suit itself
+// padName[i] = SDL_JoystickName(i);
+ strncpy(padName[i], SDL_JoystickName(i), 127);
+ padName[i][127] = 0; // Just in case name's length > 127
if (pad[i])
{
numButtons[i] = SDL_JoystickNumButtons(pad[i]);
numHats[i] = SDL_JoystickNumHats(pad[i]);
numAxes[i] = SDL_JoystickNumAxes(pad[i]);
+ WriteLog("Gamepad: Joystick #%i: %s\n", i, padName[i]);
}
}
WriteLog("Gamepad: Found %u joystick%s.\n", numJoysticks, (numJoysticks == 1 ? "" : "s"));
+#if 0
+for(int i=0; i<numJoysticks; i++)
+ printf("GAMEPAD::AllocateJoysticks: stick #%i = %s\n", i, padName[i]);
+#endif
}
if (joystickID >= 8)
return NULL;
+//printf("GAMEPAD: Getting name (%s) for joystick #%i...\n", padName[joystickID], joystickID);
return padName[joystickID];
}
}
+//UNUSED
int Gamepad::CheckButtonPressed(void)
{
// This translates the hat direction to a mask index.
}
+// UNUSED
int Gamepad::GetButtonID(void)
{
// Return single button ID being pressed (if any)
}
+// UNUSED
int Gamepad::GetJoystickID(void)
{
// Return joystick ID of button being pressed (if any)
}
+// However, SDL 2 *does* support hot-plugging! :-D
#if 0
// Need to test this. It may be that the only time joysticks are detected is
// when the program is first run. That would suck.
class Gamepad
{
// really should make all methods and members be static so that we can
-// call this stuff without instantiating one. :-)
+// call this stuff without instantiating one. :-) [DONE]
public:
Gamepad();
~Gamepad();
// Support up to 8 gamepads
static int numJoysticks;
static SDL_Joystick * pad[8];
- static const char * padName[8];
+ static char padName[8][128];
static int numButtons[8];
static int numAxes[8];
static int numHats[8];
#include <QtGui>
#include <QGLWidget>
+#include <stdint.h>
class GLWidget: public QGLWidget
{
// JLH = James Hammons <jlhamm@acm.org>
//
// Who When What
-// --- ---------- -------------------------------------------------------------
+// --- ---------- ------------------------------------------------------------
// JLH 12/23/2009 Created this file
// JLH 12/20/2010 Added settings, menus & toolbars
// JLH 07/05/2011 Added CD BIOS functionality to GUI
//
// - Add dbl click/enter to select in cart list, ESC to dimiss [DONE]
// - Autoscan/autoload all available BIOS from 'software' folder [DONE]
-// - Add 1 key jumping in cartridge list (press 'R', jumps to carts starting with 'R', etc) [DONE]
+// - Add 1 key jumping in cartridge list (press 'R', jumps to carts starting
+// with 'R', etc) [DONE]
// - Controller configuration [DONE]
//
// STILL TO BE DONE:
//
// - Fix bug in switching between PAL & NTSC in fullscreen mode.
// - Remove SDL dependencies (sound, mainly) from Jaguar core lib
-// - Fix inconsistency with trailing slashes in paths (eeproms needs one, software doesn't)
+// - Fix inconsistency with trailing slashes in paths (eeproms needs one,
+// software doesn't)
//
// SFDX CODE: S1E9T8H5M23YS
}
+//
+// N.B.: The profile system AutoConnect functionality sets the gamepad IDs here.
+//
void MainWin::HandleGamepads(void)
{
Gamepad::Update();
for(int i=BUTTON_FIRST; i<=BUTTON_LAST; i++)
{
if (vjs.p1KeyBindings[i] & (JOY_BUTTON | JOY_HAT | JOY_AXIS))
- joypad0Buttons[i] = (Gamepad::GetState(0, vjs.p1KeyBindings[i]) ? 0x01 : 0x00);
-/*{
-if (vjs.p1KeyBindings[i] & JOY_AXIS)
- printf("Axis state (HandleGamepads): %i\n", joypad0Buttons[i]);
-}*/
+ joypad0Buttons[i] = (Gamepad::GetState(gamepadIDSlot1, vjs.p1KeyBindings[i]) ? 0x01 : 0x00);
+
if (vjs.p2KeyBindings[i] & (JOY_BUTTON | JOY_HAT | JOY_AXIS))
- joypad1Buttons[i] = (Gamepad::GetState(1, vjs.p2KeyBindings[i]) ? 0x01 : 0x00);
+ joypad1Buttons[i] = (Gamepad::GetState(gamepadIDSlot2, vjs.p2KeyBindings[i]) ? 0x01 : 0x00);
}
}
dlg.generalTab->useUnknownSoftware->setChecked(allowUnknownSoftware);
dlg.controllerTab1->profileNum = lastEditedProfile;
dlg.controllerTab1->SetupLastUsedProfile();
+// maybe instead of this, we tell the controller tab to work on a copy that gets
+// written if the user hits 'OK'.
+ SaveProfiles(); // Just in case user cancels
if (dlg.exec() == false)
+ {
+ RestoreProfiles();
return;
+ }
QString before = vjs.ROMPath;
QString alpineBefore = vjs.alpineROMPath;
//ick.
allowUnknownSoftware = dlg.generalTab->useUnknownSoftware->isChecked();
lastEditedProfile = dlg.controllerTab1->profileNum;
+ AutoConnectProfiles();
// We rescan the "software" folder if the user either changed the path or
// checked/unchecked the "Allow unknown files" option in the config dialog.
// JLH = James Hammons <jlhamm@acm.org>
//
// Who When What
-// --- ---------- -------------------------------------------------------------
+// --- ---------- ------------------------------------------------------------
// JLH 05/01/2013 Created this file
+// JLH 10/02/2014 Finally fixed stuff so it works the way it should
+//
+// This is a profile database with two parts: One, a list of devices, and two,
+// a list of profiles each containing a pointer to the device list, and map
+// name, a preferred slot #, and a key/button map. All the heavy lifting (incl.
+// autoconnection of devices to profiles to slots) is done here.
+//
+// Basically, how this works is that we connect the device the user plugs into
+// the computer to a profile in the database to a slot in the virtual Jaguar.
+// Hopefully the configuration that the user gives us is sane enough for us to
+// figure out how to do the right thing! By default, there is always a keyboard
+// device plugged in; any other device that gets plugged in and wants to be in
+// slot #0 can override it. This is so there is always a sane configuration if
+// nothing is plugged in.
+//
+// Devices go into the database when the user plugs them in and runs VJ, and
+// subsequently does anything to alter any of the existing profiles. Once a
+// device has been seen, it can't be unseen!
//
-
#include "profile.h"
#include <QtGui>
#include "settings.h"
+//#define DEBUG_PROFILES
#define MAX_DEVICES 64
Profile profile[MAX_PROFILES];
+Profile profileBackup[MAX_PROFILES];
int controller1Profile;
int controller2Profile;
-int gamepad1Slot;
-int gamepad2Slot;
+int gamepadIDSlot1;
+int gamepadIDSlot2;
int numberOfProfiles;
int numberOfDevices;
char deviceNames[MAX_DEVICES][128];
'3', 'L', 'K', 'J', 'O', 'P'
};
+
// Function Prototypes
-int ConnectProfileToDevice(int deviceNum);
+int ConnectProfileToDevice(int deviceNum, int gamepadID = -1);
int FindProfileForDevice(int deviceNum, int preferred, int * found);
+//
+// These two functions are mainly to support the controller configuration GUI.
+// Could just as easily go there as well (and be better placed there).
+//
+void SaveProfiles(void)
+{
+ memcpy(&profileBackup, &profile, sizeof(Profile) * MAX_PROFILES);
+}
+
+
+void RestoreProfiles(void)
+{
+ memcpy(&profile, &profileBackup, sizeof(Profile) * MAX_PROFILES);
+}
+
+
void ReadProfiles(QSettings * set)
{
// Assume no profiles, until we read them
{
set->setArrayIndex(i - 1);
strcpy(deviceNames[i], set->value("deviceName").toString().toAscii().data());
-//printf("Read device name: %s\n", deviceNames[i]);
+#ifdef DEBUG_PROFILES
+printf("Read device name: %s\n", deviceNames[i]);
+#endif
}
set->endArray();
numberOfProfiles = set->beginReadArray("profiles");
-//printf("Number of profiles: %u\n", numberOfProfiles);
+#ifdef DEBUG_PROFILES
+printf("Number of profiles: %u\n", numberOfProfiles);
+#endif
for(int i=0; i<numberOfProfiles; i++)
{
set->setArrayIndex(i);
profile[i].device = set->value("deviceNum").toInt();
strcpy(profile[i].mapName, set->value("mapName").toString().toAscii().data());
- profile[i].preferredController = set->value("preferredController").toInt();
+ profile[i].preferredSlot = set->value("preferredSlot").toInt();
for(int j=0; j<21; j++)
{
QString string = QString("map%1").arg(j);
profile[i].map[j] = set->value(string).toInt();
}
-//printf("Profile #%u: device=%u (%s)\n", i, profile[i].device, deviceNames[profile[i].device]);
+#ifdef DEBUG_PROFILES
+printf("Profile #%u: device=%u (%s)\n", i, profile[i].device, deviceNames[profile[i].device]);
+#endif
}
set->endArray();
-//printf("Number of profiles found: %u\n", numberOfProfiles);
+#ifdef DEBUG_PROFILES
+printf("Number of profiles found: %u\n", numberOfProfiles);
+#endif
// Set up a reasonable default if no profiles were found
if (numberOfProfiles == 0)
{
-//printf("Setting up default profile...\n");
+#ifdef DEBUG_PROFILES
+printf("Setting up default profile...\n");
+#endif
numberOfProfiles++;
profile[0].device = 0; // Keyboard is always device #0
strcpy(profile[0].mapName, "Default");
- profile[0].preferredController = CONTROLLER1;
+ profile[0].preferredSlot = CONTROLLER1;
for(int i=0; i<21; i++)
profile[0].map[i] = defaultMap[i];
set->setArrayIndex(i);
set->setValue("deviceNum", profile[i].device);
set->setValue("mapName", profile[i].mapName);
- set->setValue("preferredController", profile[i].preferredController);
+ set->setValue("preferredSlot", profile[i].preferredSlot);
for(int j=0; j<21; j++)
{
for(int i=0; i<numberOfDevices; i++)
{
if (strcmp(deviceNames[i], name) == 0)
+#ifdef DEBUG_PROFILES
+{
+printf("PROFILE: Found device #%i for name (%s)...\n", i, name);
+#endif
return i;
+#ifdef DEBUG_PROFILES
+}
+#endif
}
if (numberOfDevices == MAX_DEVICES)
return -1;
+#ifdef DEBUG_PROFILES
+printf("Device '%s' not found, creating device...\n", name);
+#endif
// If the device wasn't found, it must be new; so add it to the list.
int deviceNum = numberOfDevices;
deviceNames[deviceNum][127] = 0;
{
profile[numberOfProfiles].device = deviceNum;
strcpy(profile[numberOfProfiles].mapName, "Default");
- profile[numberOfProfiles].preferredController = CONTROLLER1;
+ profile[numberOfProfiles].preferredSlot = CONTROLLER1;
for(int i=0; i<21; i++)
profile[numberOfProfiles].map[i] = defaultMap[i];
}
+// N.B.: Unused
int FindUsableProfiles(QComboBox * combo)
{
int found = 0;
for(int j=0; j<numberOfProfiles; j++)
{
// Check for device *and* usable configuration
- if ((profile[j].device == 0) && (profile[j].preferredController))
+ if ((profile[j].device == 0) && (profile[j].preferredSlot))
{
combo->addItem(QString("Keyboard::%1").arg(profile[j].mapName), j);
found++;
for(int j=0; j<numberOfProfiles; j++)
{
- if ((profile[j].device == deviceNum) && (profile[j].preferredController))
+ if ((profile[j].device == deviceNum) && (profile[j].preferredSlot))
{
combo->addItem(QString("%1::%2").arg(Gamepad::GetJoystickName(i)).arg(profile[j].mapName), j);
found++;
bool ConnectProfileToController(int profileNum, int controllerNum)
{
+ // Sanity checks...
+ if (profileNum < 0)
+ return false;
+
if (profile[profileNum].device == -1)
return false;
}
-//
-// This is a pretty crappy way of doing autodetection. What it does is scan for
-// keyboard profiles first, then look for plugged in gamepads next. If more
-// than one plugged in gamepad matches a preferred controller slot, the last
-// one found is chosen.
-//
-// There has to be a better way to do this, I just can't think of what it
-// should be ATM... :-P
-//
/*
-Here's the rules: If preferred Jaguar controller is not checked, the profile is
-skipped. If one or the other is checked, it's put into that slot. If *both* are
-checked, it will take over any slot that isn't claimed by another gamepad. If
-there are ties, present it to the user *once* and ask them which gamepad should
-be #1; don't ask again unless a), they change the profiles and b), the
-situation warrants it.
-
-Also, there is a problem with this approach and having multiple devices
-that are the same. Currently, if two of the same device are plugged in
-and the profile is set to both controllers, it will broadcast buttons
-pressed from either gamepad, no matter who is pressing them. This is
-BAD(tm). [Not true, but there's a different problem described under 'How to
-solve?', so GOOD(tm).]
-
-Also, the gamepad logic doesn't distinguish inputs by controller, it just
-grabs them all regardless. This is also BAD(tm). [Actually, it doesn't. It
-properly segregates the inputs. So this is GOOD(tm).]
-
-How to solve?
-
-Seems there's yet ANOTHER dimension to all this: The physical gamepads
-plugged into their ports. Now the device # can map these fine if they're
-different, but we still run into problems with the handling in the MainWin
-because it's hardwired to take pad 0 in slot 0 and pad 1 in slot 1. If you have
-them configured other than this, you won't get anything. So we need to also
-map the physical devices to their respective slots.
-
-
-Steps:
-
-1) Make a list of all devices attached to the system.
-
-2) Make a list of all profiles belonging to those devices, as long as they have
- one or more Jaguar controllers that are "mapped to".
-
-3) See if there are any conflicts. If there are, see if the user has already
- been asked to resolve and chosen a resolution; otherwise, ask the user to
- resolve.
-
- a) Loop through all found profiles. If they are set to a single controller,
- set it in the appropriate list (one list for controller 1, another for
- controller 2).
-
- b) Loop through all found profiles. If they are set to both controllers,
- ... (first stab at it:)
- Check for list #1. If nothing there, assign it to list #1.
- Else, check for List #2. If nothing there, assign to list #2.
- [But the wording of it implies that it will assign it to both.
- Does that mean we should make another combobox will all the possible
- combinations laid out? Probably. Not many people will understand that
- checking both means "assign to either one that's free".]
-
-4) Connect profiles to controllers, and set gamepad slots (for the MainWin
- handler).
-
+One more stab at this...
+
+ - Connect keyboard to slot #0.
+ - Loop thru all connected devices. For each device:
+ - Grab all profiles for the device. For each profile:
+ - Check to see what its preferred device is.
+ - If PD is slot #0, see if slot is already taken (gamepadIDSlot1 != -1).
+ If not taken, take it; otherwise put in list to tell user to solve the
+ conflict for us.
+ - If the slot is already taken and *it's the same device* as the one
+ we're looking at, set it in slot #1.
+ - If PD is slot #1, see if slot is already taken. If not, take it;
+ otherwise, put in list to tell user to solve conflict for us.
+ - If PD is slot #0 & #1, see if either is already taken. Try #0 first,
+ then try #1. If both are already taken, skip it. Do this *after* we've
+ connected devices with preferred slots.
*/
void AutoConnectProfiles(void)
{
int foundProfiles[MAX_PROFILES];
- int controller1Profile = -1;
- int controller2Profile = -1;
+ controller1Profile = -1;
+ controller2Profile = -1;
+ gamepadIDSlot1 = -1;
+ gamepadIDSlot2 = -1;
- // Check for Keyboard device profiles first, if anything else is plugged in
- // it will default to it instead.
-#if 0
- for(int i=0; i<numberOfProfiles; i++)
- {
- // Skip profile if it's not Keyboard device
- if (profile[i].device != 0)
- continue;
-
- if (profile[i].preferredController & CONTROLLER1)
- controller1Profile = i;
-
- if (profile[i].preferredController & CONTROLLER2)
- controller2Profile = i;
- }
-#else
- // Connect keyboard devices first...
+ // Connect keyboard devices first... (N.B.: this leaves gampadIDSlot1 at -1,
+ // so it can be overridden by plugged-in gamepads.)
ConnectProfileToDevice(0);
-#endif
- // Next, check for the "don't care" condition of both jaguar controllers
- // checked for connected host devices
+ // Connect the profiles that prefer a slot, if any.
+ // N.B.: Conflicts are detected, but ignored. 1st controller to grab a
+ // preferred slot gets it. :-P
for(int i=0; i<Gamepad::numJoysticks; i++)
{
int deviceNum = FindDeviceNumberForName(Gamepad::GetJoystickName(i));
- int numberProfilesFound = FindProfileForDevice(deviceNum, CONTROLLER1 | CONTROLLER2, foundProfiles);
+// bool p1Overwriteable =
+
+ for(int j=0; j<numberOfProfiles; j++)
+ {
+ if (deviceNum != profile[j].device)
+ continue;
+
+ int slot = profile[j].preferredSlot;
- // We need to grab pairs here, host device # paired up with profiles
- // so we can then determine if there are any conflicts that can't be
- // resolved...
+ if (slot == CONTROLLER1)
+ {
+ if (gamepadIDSlot1 == -1)
+ controller1Profile = j, gamepadIDSlot1 = i;
+ else
+ {
+ // Autoresolve simple conflict: two controllers sharing one
+ // profile mapped to slot #0.
+ if ((deviceNum == profile[controller1Profile].device) && (controller2Profile == -1))
+ controller2Profile = j, gamepadIDSlot2 = i;
+ else
+ ; // Alert user to conflict and ask to resolve
+ }
+ }
+ else if (slot == CONTROLLER2)
+ {
+ if (gamepadIDSlot2 == -1)
+ controller2Profile = j, gamepadIDSlot2 = i;
+ else
+ {
+ // Autoresolve simple conflict: two controllers sharing one
+ // profile mapped to slot #1.
+ if ((deviceNum == profile[controller2Profile].device) && (controller1Profile == -1))
+ controller1Profile = j, gamepadIDSlot1 = i;
+ else
+ ; // Alert user to conflict and ask to resolve
+ }
+ }
+ }
}
+ // Connect the "don't care" states, if any. We don't roll it into the above,
+ // because it can override the profiles that have a definite preference.
+ // These should be lowest priority.
for(int i=0; i<Gamepad::numJoysticks; i++)
{
int deviceNum = FindDeviceNumberForName(Gamepad::GetJoystickName(i));
-#if 0
for(int j=0; j<numberOfProfiles; j++)
{
- // Skip profile if it's not discovered device
- if (profile[j].device != deviceNum)
+ if (deviceNum != profile[j].device)
continue;
- if (profile[j].preferredController & CONTROLLER1)
- controller1Profile = j;
+ int slot = profile[j].preferredSlot;
- if (profile[j].preferredController & CONTROLLER2)
- controller2Profile = j;
+ if (slot == (CONTROLLER1 | CONTROLLER2))
+ {
+ if (gamepadIDSlot1 == -1)
+ controller1Profile = j, gamepadIDSlot1 = i;
+ else if (gamepadIDSlot2 == -1)
+ controller2Profile = j, gamepadIDSlot2 = i;
+ }
}
-#else
- ConnectProfileToDevice(deviceNum);
-#endif
}
- if (controller1Profile != -1)
- ConnectProfileToController(controller1Profile, 0);
-
- if (controller2Profile != -1)
- ConnectProfileToController(controller2Profile, 1);
+ // Finally, attempt to connect profiles to controllers
+ ConnectProfileToController(controller1Profile, 0);
+ ConnectProfileToController(controller2Profile, 1);
}
-int ConnectProfileToDevice(int deviceNum)
+int ConnectProfileToDevice(int deviceNum, int gamepadID/*= -1*/)
{
// bool found1 = false;
// bool found2 = false;
if (profile[i].device != deviceNum)
continue;
- if (profile[i].preferredController & CONTROLLER1)
+ if (profile[i].preferredSlot & CONTROLLER1)
{
controller1Profile = i;
+ gamepadIDSlot1 = gamepadID;
// found1 = true;
numberFoundForController1++;
}
- if (profile[i].preferredController & CONTROLLER2)
+ if (profile[i].preferredSlot & CONTROLLER2)
{
controller2Profile = i;
+ gamepadIDSlot2 = gamepadID;
// found2 = true;
numberFoundForController2++;
}
return numberFoundForController1 + numberFoundForController2;
}
-/*
-int FindProfileForDevice(int deviceNum)
-{
- for(int i=0; i<numberOfProfiles; i++)
- {
- // Skip profile if it's not our device
- if (profile[i].device != deviceNum)
- continue;
-
- return i;
- }
-
- return -1;
-}
-*/
+// N.B.: Unused
int FindProfileForDevice(int deviceNum, int preferred, int * found)
{
int numFound = 0;
for(int i=0; i<numberOfProfiles; i++)
{
// Return the profile only if it matches the passed in device and
- // matches the passed in prefence...
- if ((profile[i].device == deviceNum) && (profile[i].preferredController == preferred))
+ // matches the passed in preference...
+ if ((profile[i].device == deviceNum) && (profile[i].preferredSlot == preferred))
found[numFound++] = i;
}
return numFound;
}
+
+//
+// Also note that we have the intersection of three things here: One the one
+// hand, we have the detected joysticks with their IDs (typically in the range
+// of 0-7), we have our gamepad profiles and their IDs (typically can have up to
+// 64 of them), and we have our gamepad slots that the detected joysticks can be
+// connected to.
+//
+// So, when the user plugs in a gamepad, it gets a joystick ID, then the profile
+// manager checks to see if a profile (or profiles) for it exists. If so, then
+// it assigns that joystick ID to a gamepad slot, based upon what the user
+// requested for that profile.
+//
+// A problem (perhaps) arises when you have more than one profile for a certain
+// device, how do you know which one to use? Perhaps you have a field in the
+// profile saying that you use this profile 1st, that one 2nd, and so on...
+//
+// Some use cases, and how to resolve them:
+//
+// - User has two of the same device, and plugs them both in. There is only one
+// profile. In this case, the sane thing to do is ignore the "preferred slot"
+// of the dialog and use the same profile for both controllers, and plug them
+// both into slot #0 and #1.
+// - User has one device, and plugs it in. There are two profiles. In this case,
+// the profile chosen should be based upon the "preferred slot", with slot #0
+// being the winner. If both profiles are set for slot #0, ask the user which
+// profile to use, and set a flag in the profile to say that it is a preferred
+// profile for that device.
+// - In any case where there are conflicts, the user must be consulted and sane
+// defaults used.
+//
class QComboBox;
class QSettings;
-#define MAX_PROFILES 64
+#define MAX_PROFILES 64 // 64 profiles ought to be enough for everybody
#define CONTROLLER1 0x01
#define CONTROLLER2 0x02
{
int device; // Host device number (-1 == invalid profile)
char mapName[32]; // Human readable map name
- int preferredController; // CONTROLLER1 and/or CONTROLLER2
+ int preferredSlot; // CONTROLLER1 and/or CONTROLLER2
uint32_t map[21]; // Keys/buttons/axes
};
// Function prototypes
+void SaveProfiles(void);
+void RestoreProfiles(void);
void ReadProfiles(QSettings *);
void WriteProfiles(QSettings *);
int GetFreeProfile(void);
extern Profile profile[];
extern int controller1Profile;
extern int controller2Profile;
-extern int gamepad1Slot;
-extern int gamepad2Slot;
+extern int gamepadIDSlot1;
+extern int gamepadIDSlot2;
//extern int numberOfProfiles;
#endif // __PROFILE_H__
//#define JERRY_CONFIG 0x4002 // ??? What's this ???
+// JERRY Registers (write, offset from $F10000)
+#define JPIT1 0x00
+#define JPIT2 0x02
+#define JPIT3 0x04
+#define JPIT4 0x08
+#define CLK1 0x10
+#define CLK2 0x12
+#define CLK3 0x14
+#define JINTCTRL 0x20
+#define ASIDATA 0x30
+#define ASICTRL 0x32
+#define ASICLK 0x34
+#define SCLK 0xA150
+#define SMODE 0xA154
+
+
uint8_t analog_x, analog_y;
static uint32_t JERRYPIT1Prescaler;
void JERRYDone(void)
{
+ JERRYDumpIORegistersToLog();
WriteLog("JERRY: M68K Interrupt control ($F10020) = %04X\n", GET16(jerry_ram_8, 0x20));
JoystickDone();
DACDone();
jerryPendingInterrupt |= irq;
}
+//
+// Dump all JERRY register values to the log
+//
+void JERRYDumpIORegistersToLog(void)
+{
+ WriteLog("\n\n---------------------------------------------------------------------\n");
+ WriteLog("JERRY I/O Registers\n");
+ WriteLog("---------------------------------------------------------------------\n");
+ WriteLog("F1%04X (JPIT1): $%04X\n", JPIT1, GET16(jerry_ram_8, JPIT1));
+ WriteLog("F1%04X (JPIT2): $%04X\n", JPIT2, GET16(jerry_ram_8, JPIT2));
+ WriteLog("F1%04X (JPIT3): $%04X\n", JPIT3, GET16(jerry_ram_8, JPIT3));
+ WriteLog("F1%04X (JPIT4): $%04X\n", JPIT4, GET16(jerry_ram_8, JPIT4));
+ WriteLog("F1%04X (CLK1): $%04X\n", CLK1, GET16(jerry_ram_8, CLK1));
+ WriteLog("F1%04X (CLK2): $%04X\n", CLK2, GET16(jerry_ram_8, CLK2));
+ WriteLog("F1%04X (CLK3): $%04X\n", CLK3, GET16(jerry_ram_8, CLK3));
+ WriteLog("F1%04X (JINTCTRL): $%04X\n", JINTCTRL, GET16(jerry_ram_8, JINTCTRL));
+ WriteLog("F1%04X (ASIDATA): $%04X\n", ASIDATA, GET16(jerry_ram_8, ASIDATA));
+ WriteLog("F1%04X (ASICTRL): $%04X\n", ASICTRL, GET16(jerry_ram_8, ASICTRL));
+ WriteLog("F1%04X (ASICLK): $%04X\n", ASICLK, GET16(jerry_ram_8, ASICLK));
+ WriteLog("F1%04X (SCLK): $%04X\n", SCLK, GET16(jerry_ram_8, SCLK));
+ WriteLog("F1%04X (SMODE): $%04X\n", SMODE, GET16(jerry_ram_8, SMODE));
+ WriteLog("---------------------------------------------------------------------\n\n\n");
+}
+
//
// JERRY byte access (read)
//
void JERRYWriteByte(uint32_t offset, uint8_t data, uint32_t who/*=UNKNOWN*/)
{
+ // Moved here tentatively, so we can see everything written to JERRY.
+ jerry_ram_8[offset & 0xFFFF] = data;
+
#ifdef JERRY_DEBUG
WriteLog("jerry: writing byte %.2x at 0x%.6x\n",data,offset);
#endif
- if ((offset >= DSP_CONTROL_RAM_BASE) && (offset < DSP_CONTROL_RAM_BASE+0x20))
+ if ((offset >= DSP_CONTROL_RAM_BASE) && (offset < DSP_CONTROL_RAM_BASE + 0x20))
{
DSPWriteByte(offset, data, who);
return;
}
- else if ((offset >= DSP_WORK_RAM_BASE) && (offset < DSP_WORK_RAM_BASE+0x2000))
+ else if ((offset >= DSP_WORK_RAM_BASE) && (offset < DSP_WORK_RAM_BASE + 0x2000))
{
DSPWriteByte(offset, data, who);
return;
if (offset >= 0xF1D000 && offset <= 0xF1DFFF)
return;
- jerry_ram_8[offset & 0xFFFF] = data;
+// jerry_ram_8[offset & 0xFFFF] = data;
}
//
void JERRYWriteWord(uint32_t offset, uint16_t data, uint32_t who/*=UNKNOWN*/)
{
+ // Moved here tentatively, so we can see everything written to JERRY.
+ jerry_ram_8[(offset+0) & 0xFFFF] = (data >> 8) & 0xFF;
+ jerry_ram_8[(offset+1) & 0xFFFF] = data & 0xFF;
+
#ifdef JERRY_DEBUG
WriteLog( "JERRY: Writing word %04X at %06X\n", data, offset);
#endif
(data & 0x10 ? "ASI " : ""), (data & 0x20 ? "I2S " : ""));
#endif
- if ((offset >= DSP_CONTROL_RAM_BASE) && (offset < DSP_CONTROL_RAM_BASE+0x20))
+ if ((offset >= DSP_CONTROL_RAM_BASE) && (offset < DSP_CONTROL_RAM_BASE + 0x20))
{
DSPWriteWord(offset, data, who);
return;
}
- else if ((offset >= DSP_WORK_RAM_BASE) && (offset < DSP_WORK_RAM_BASE+0x2000))
+ else if ((offset >= DSP_WORK_RAM_BASE) && (offset < DSP_WORK_RAM_BASE + 0x2000))
{
DSPWriteWord(offset, data, who);
return;
return;
}
-/* else if (offset >= 0xF10010 && offset < 0xF10016)
- {
- clock_word_write(offset, data);
- return;
- }//*/
// JERRY -> 68K interrupt enables/latches (need to be handled!)
else if (offset >= 0xF10020 && offset <= 0xF10022)
{
//WriteLog("JERRY: (Previous is partially handled... IRQMask=$%04X)\n", jerryInterruptMask);
return;
}
-/* else if (offset >= 0xF17C00 && offset < 0xF17C02)
- {
-//I think this was removed from the Jaguar. If so, then we don't need this...!
- anajoy_word_write(offset, data);
- return;
- }*/
else if (offset >= 0xF14000 && offset < 0xF14003)
{
JoystickWriteWord(offset, data);
if (offset >= 0xF1D000 && offset <= 0xF1DFFF)
return;
- jerry_ram_8[(offset+0) & 0xFFFF] = (data >> 8) & 0xFF;
- jerry_ram_8[(offset+1) & 0xFFFF] = data & 0xFF;
+// jerry_ram_8[(offset+0) & 0xFFFF] = (data >> 8) & 0xFF;
+// jerry_ram_8[(offset+1) & 0xFFFF] = data & 0xFF;
}
void JERRYInit(void);
void JERRYReset(void);
void JERRYDone(void);
+void JERRYDumpIORegistersToLog(void);
uint8_t JERRYReadByte(uint32_t offset, uint32_t who = UNKNOWN);
uint16_t JERRYReadWord(uint32_t offset, uint32_t who = UNKNOWN);
Actually: writes would tuck in the value, but reads would have to be handled
correctly since some registers do not fall on the same address as far as reading
goes... Still completely doable though. :-)
+
+N.B.: Jaguar RAM is only 2 megs. ROM is 6 megs max, IO is 128K
*/
#include "memory.h"
MemDesc memoryMap[] = {
- { 0x000000, 0x3FFFFF, MM_RAM, jaguarMainRAM },
+ { 0x000000, 0x1FFFFF, MM_RAM, jaguarMainRAM },
+ { 0x200000, 0x3FFFFF, MM_RAM, jaguarMainRAM }, // Mirror of 1st 2 megs
+ { 0x400000, 0x5FFFFF, MM_RAM, jaguarMainRAM }, // " "
+ { 0x600000, 0x7FFFFF, MM_RAM, jaguarMainRAM }, // " "
{ 0x800000, 0xDFFEFF, MM_ROM, jaguarMainROM },
{ 0xDFFF00, 0xDFFF03, MM_IO, &butch }, // base of Butch == interrupt control register, R/W
// JLH = James Hammons <jlhamm@acm.org>
//
// Who When What
-// --- ---------- -------------------------------------------------------------
+// --- ---------- ------------------------------------------------------------
// JLH 01/16/2010 Created this log
// JLH 02/23/2013 Finally removed commented out stuff :-P
//
#include <limits.h>
#define MAX_PATH _POSIX_PATH_MAX
#else
-#include <stdlib.h> // for MAX_PATH on MinGW/Darwin
+#include <stdlib.h> // for MAX_PATH on MinGW/Darwin
+// Kludge for Win64
+#ifndef MAX_PATH
+#define MAX_PATH _MAX_PATH // Urgh.
+#endif
#endif
#include <stdint.h>
struct VJSettings
{
bool useJoystick;
- int32_t joyport; // Joystick port
- bool hardwareTypeNTSC; // Set to false for PAL
+ int32_t joyport; // Joystick port
+ bool hardwareTypeNTSC; // Set to false for PAL
bool useJaguarBIOS;
bool GPUEnabled;
bool DSPEnabled;
#define HEQ 0x54 // Horizontal equalization end
#define BG 0x58 // Background color
#define INT1 0xE0
+#define INT2 0xE2
//NOTE: These arbitrary cutoffs are NOT taken into account for PAL jaguar screens. !!! FIX !!! [DONE]
void TOMDone(void)
{
+ TOMDumpIORegistersToLog();
OPDone();
BlitterDone();
WriteLog("TOM: Resolution %i x %i %s\n", TOMGetVideoModeWidth(), TOMGetVideoModeHeight(),
// WriteLog("\ntom: object processor:\n");
// WriteLog("tom: pointer to object list: 0x%.8x\n",op_get_list_pointer());
// WriteLog("tom: INT1=0x%.2x%.2x\n",TOMReadByte(0xf000e0),TOMReadByte(0xf000e1));
-// gpu_done();
-// dsp_done();
-// memory_free(tomRam8);
-// memory_free(tom_cry_rgb_mix_lut);
}
if (vjs.hardwareTypeNTSC)
{
SET16(tomRam8, MEMCON1, 0x1861);
+// SET16(tomRam8, MEMCON1, 0x1865);//Bunch of BS
SET16(tomRam8, MEMCON2, 0x35CC);
SET16(tomRam8, HP, 844); // Horizontal Period (1-based; HP=845)
SET16(tomRam8, HBB, 1713); // Horizontal Blank Begin
}
+//
+// Dump all TOM register values to the log
+//
+void TOMDumpIORegistersToLog(void)
+{
+ WriteLog("\n\n---------------------------------------------------------------------\n");
+ WriteLog("TOM I/O Registers\n");
+ WriteLog("---------------------------------------------------------------------\n");
+ WriteLog("F000%02X (MEMCON1): $%04X\n", MEMCON1, GET16(tomRam8, MEMCON1));
+ WriteLog("F000%02X (MEMCON2): $%04X\n", MEMCON2, GET16(tomRam8, MEMCON2));
+ WriteLog("F000%02X (HC): $%04X\n", HC, GET16(tomRam8, HC));
+ WriteLog("F000%02X (VC): $%04X\n", VC, GET16(tomRam8, VC));
+ WriteLog("F000%02X (OLP): $%08X\n", OLP, GET32(tomRam8, OLP));
+ WriteLog("F000%02X (OBF): $%04X\n", OBF, GET16(tomRam8, OBF));
+ WriteLog("F000%02X (VMODE): $%04X\n", VMODE, GET16(tomRam8, VMODE));
+ WriteLog("F000%02X (BORD1): $%04X\n", BORD1, GET16(tomRam8, BORD1));
+ WriteLog("F000%02X (BORD2): $%04X\n", BORD2, GET16(tomRam8, BORD2));
+ WriteLog("F000%02X (HP): $%04X\n", HP, GET16(tomRam8, HP));
+ WriteLog("F000%02X (HBB): $%04X\n", HBB, GET16(tomRam8, HBB));
+ WriteLog("F000%02X (HBE): $%04X\n", HBE, GET16(tomRam8, HBE));
+ WriteLog("F000%02X (HS): $%04X\n", HS, GET16(tomRam8, HS));
+ WriteLog("F000%02X (HVS): $%04X\n", HVS, GET16(tomRam8, HVS));
+ WriteLog("F000%02X (HDB1): $%04X\n", HDB1, GET16(tomRam8, HDB1));
+ WriteLog("F000%02X (HDB2): $%04X\n", HDB2, GET16(tomRam8, HDB2));
+ WriteLog("F000%02X (HDE): $%04X\n", HDE, GET16(tomRam8, HDE));
+ WriteLog("F000%02X (VP): $%04X\n", VP, GET16(tomRam8, VP));
+ WriteLog("F000%02X (VBB): $%04X\n", VBB, GET16(tomRam8, VBB));
+ WriteLog("F000%02X (VBE): $%04X\n", VBE, GET16(tomRam8, VBE));
+ WriteLog("F000%02X (VS): $%04X\n", VS, GET16(tomRam8, VS));
+ WriteLog("F000%02X (VDB): $%04X\n", VDB, GET16(tomRam8, VDB));
+ WriteLog("F000%02X (VDE): $%04X\n", VDE, GET16(tomRam8, VDE));
+ WriteLog("F000%02X (VEB): $%04X\n", VEB, GET16(tomRam8, VEB));
+ WriteLog("F000%02X (VEE): $%04X\n", VEE, GET16(tomRam8, VEE));
+ WriteLog("F000%02X (VI): $%04X\n", VI, GET16(tomRam8, VI));
+ WriteLog("F000%02X (PIT0): $%04X\n", PIT0, GET16(tomRam8, PIT0));
+ WriteLog("F000%02X (PIT1): $%04X\n", PIT1, GET16(tomRam8, PIT1));
+ WriteLog("F000%02X (HEQ): $%04X\n", HEQ, GET16(tomRam8, HEQ));
+ WriteLog("F000%02X (BG): $%04X\n", BG, GET16(tomRam8, BG));
+ WriteLog("F000%02X (INT1): $%04X\n", INT1, GET16(tomRam8, INT1));
+ WriteLog("F000%02X (INT2): $%04X\n", INT2, GET16(tomRam8, INT2));
+ WriteLog("---------------------------------------------------------------------\n\n\n");
+}
+
+
//
// TOM byte access (read)
//
//
void TOMWriteByte(uint32_t offset, uint8_t data, uint32_t who/*=UNKNOWN*/)
{
+ // Moved here tentatively, so we can see everything written to TOM.
+ tomRam8[offset & 0x3FFF] = data;
+
#ifdef TOM_DEBUG
WriteLog("TOM: Writing byte %02X at %06X", data, offset);
#endif
tomRam8[offset] = data, tomRam8[offset + 0x200] = data;
}
- tomRam8[offset & 0x3FFF] = data;
+// tomRam8[offset & 0x3FFF] = data;
}
//
void TOMWriteWord(uint32_t offset, uint16_t data, uint32_t who/*=UNKNOWN*/)
{
+ // Moved here tentatively, so we can see everything written to TOM.
+ tomRam8[(offset + 0) & 0x3FFF] = data >> 8;
+ tomRam8[(offset + 1) & 0x3FFF] = data & 0xFF;
+
#ifdef TOM_DEBUG
WriteLog("TOM: Writing byte %04X at %06X", data, offset);
#endif
data &= 0x03FF; // These are all 10-bit registers
// Fix a lockup bug... :-P
- TOMWriteByte(0xF00000 | offset, data >> 8, who);
- TOMWriteByte(0xF00000 | (offset+1), data & 0xFF, who);
+// TOMWriteByte(0xF00000 | offset, data >> 8, who);
+// TOMWriteByte(0xF00000 | (offset+1), data & 0xFF, who);
if (offset == MEMCON1)
WriteLog("TOM: Memory Config 1 written by %s: $%04X\n", whoName[who], data);
// TOM Shouldn't be mucking around with this, it's up to the host system to properly
// handle this kind of crap.
// NOTE: This is needed somehow, need to get rid of the dependency on this crap.
+// N.B.: It's used in the rendering functions... So...
#warning "!!! Need to get rid of this dependency !!!"
#if 1
if ((offset >= 0x28) && (offset <= 0x4F))
uint8_t * TOMGetRamPointer(void);
uint16_t TOMGetHDB(void);
uint16_t TOMGetVDB(void);
+void TOMDumpIORegistersToLog(void);
+
int TOMIRQEnabled(int irq);
uint16_t TOMIRQControlReg(void);
#
# See the README and GPLv3 files for licensing and warranty information
#
-# NOTE: M68000 core is built and linked in as a library, so there should be no more
-# problems with using the qmake build system as-is. :-)
-# Other than on the Mac, where it stupidly defaults to making XCode binaries. >:-(
-# Well, we fixed it in the Makefile, by doing platfrom detection there. :-/
+# NOTE: M68000 core is built and linked in as a library, so there should be no
+# more problems with using the qmake build system as-is. :-)
+# Other than on the Mac, where it stupidly defaults to making XCode
+# binaries. >:-( Well, we fixed it in the Makefile, by doing platform
+# detection there. :-/
#
TARGET = virtualjaguar
CONFIG += qt warn_on release
# debug
RESOURCES += virtualjaguar.qrc
-LIBS += -Lobj -ljaguarcore -lz -lm68k
+LIBS += -Lobj -Lsrc/m68000/obj -ljaguarcore -lz -lm68k
QT += opengl
-# We stuff all the intermediate crap into obj/ so it won't confuse us mere mortals ;-)
+# We stuff all the intermediate crap into obj/ so it won't confuse us mere
+# mortals ;-)
OBJECTS_DIR = obj
MOC_DIR = obj
RCC_DIR = obj
else { LIBS += `$(CROSS)sdl-config --libs` }
# Icon on Win32, Mac
-win32 { LIBS += res/vj-ico.o }
+#win32 { LIBS += res/vj-ico.o }
+win32 { ICON = res/vj.ico }
macx { ICON = res/vj-icon.icns }
# C/C++ flags...
# NOTE: May have to put -Wall back in, but only on non-release cycles. It can
-# cause problems if you're not careful. (Can do this via command line in qmake)
+# cause problems if you're not careful. (Can do this via command line in
+# qmake)
QMAKE_CFLAGS += `$(CROSS)sdl-config --cflags`
QMAKE_CXXFLAGS += `$(CROSS)sdl-config --cflags`
# Need to add libcdio stuffola (checking/including)...
-# Translations. NB: Nobody has stepped up to do any :-P so these are dummy translations
-TRANSLATIONS = virtualjaguar_fr.ts \
+# Translations. NB: Nobody has stepped up to do any :-P so these are dummy
+# translations
+TRANSLATIONS = \
+ virtualjaguar_fr.ts \
virtualjaguar_gr.ts
INCLUDEPATH += \
src/gui/debug/m68kdasmbrowser.h \
src/gui/debug/memorybrowser.h \
src/gui/debug/opbrowser.h \
- src/gui/debug/riscdasmbrowser.h \
-# src/gui/sdljoystick.h
+ src/gui/debug/riscdasmbrowser.h
SOURCES = \
src/gui/about.cpp \
src/gui/debug/m68kdasmbrowser.cpp \
src/gui/debug/memorybrowser.cpp \
src/gui/debug/opbrowser.cpp \
- src/gui/debug/riscdasmbrowser.cpp \
-# src/gui/sdljoystick.cpp
+ src/gui/debug/riscdasmbrowser.cpp
+