-Stuff to add/fix for the next release of Virtual Jaguar
--------------------------------------------------------
-
-- Fix VC behavior to match what a real Jaguar does. Still not sure just what
- the heck is going on there. [Shamus]
-- Create an EEPROMs directory (or whatever is in EEPROMPath[]) if it doesn't
- already exist. [Shamus]
-- It would be nice to have the emulator pick up where you last left off, or at
- least give you the option of continuing from your last session. This would
- require save states, 'natch. ;-) [Shamus]
-- It would be nice to have "save states" for instant save/load capability.
- [Shamus]
-- Cycle accuracy for GPU/DSP/OP/Blitter. [Shamus]
-- Need to propagate blitter fixes in the A1 <- A2 direction to the A1 -> A2
- direction and the GPU fixes to various instructions to the DSP. [Shamus]
-- Blitter needs fixing. [Shamus]
-- In emulator screenshots. [Shamus]
-- Audio/video dumping. [Shamus]
-- Need to emulate bus contention. [Shamus]
-- Need to fix timing in the OP. As it is now, it gives a false impression of
- how much it's capable of. [Shamus]
-- Fix coming out of fullscreen on Win32. As of now, it doesn't restore the
- window position correctly [CJ]
-- Fix the Tripper Getem ROM so that it works. It has some tight coupling
- between the M68K and the DSP that causes the DSP to starve itself; fixing
- this will probably fix a bunch of other timing related issues as well.
- [Shamus]
-
-
-Stuff that was added/fixed
---------------------------
-
-- Controller handling. [Shamus] [DONE--Shamus]
-- Full screen option. [Shamus] [DONE--Shamus]
-- Command line switches for frontends. [Shamus] [DONE-Shamus]
-- Fix DSP code so that it doesn't hang in a spinlock waiting for the sound
- buffer to empty. Probably a CS lock contention issue. [Shamus] [DONE-Shamus]
-- Need to fix PAL mode to work with the virtual screen code. [DONE--Shamus]
-- There are a few ROMs that use some "quasi-illegal" 68K instructions. Need
- to patch the 68K core to deal with these in a better way than they are
- now. [DONE--Shamus]
- NOTE: This behavior was verified on Rayman, the problem was due to attempting
- to press both left & right at the same time!
-- We need a comprehensive way of determining what gets written where and
- by whom (i.e., blitter wrote to range $F03000-$F03230) in order to figure
- out the remaining problems with various ROMs. [DONE--Shamus]
-- Would also be nice to be able to dynamically change the keybindings for
- the various keys on the emulated Jaguar controller while inside the emulator.
- [DONE--Shamus]
-- Make sure that VJ doesn't crash if the useJaguarBIOS key is set to 1 and the
- BIOS file isn't available. [DONE--Shamus]
-- There is a bug either with the GPU or the blitter (most likely the latter)
- which causes the spinning "A"s in the BIOS startup code to be corrupted
- when they are showing their backsides. [Shamus] [DONE--Shamus]
- NOTE: This behavior has been verified on a real Jaguar and as such is not
- an emulator bug. A Jaguar boot ROM bug, yes, but not ours. ;-)
-- Make it possible to completely disable the GUI (using a switch like -nogui
- or the like) for people running VJ in a cabinet. [Shamus] [DONE--Shamus]
-- Code to stretch the display in a generic way would be nice. [Shamus]
- [DONE for OpenGL--nwagenaar]
-- Would be nice to have a GUI for things that are set on the command line or
- in the config file. [Shamus] [DONE--Shamus]
-- DSP code needs to be rewritten. [Shamus] [DONE but still work to be done--Shamus]
-- We need to have an external configuration file for remembering a user's
- preferences, such as key bindings, etc. [Shamus] [DONE--Shamus]
-- We need to come up with a way to fix the aspect ratio for pixel modes that
- aren't square (PWIDTH != 4). [Shamus] [DONE for OpenGL--Shamus]
-- GUI for ROM selection [Shamus] [DONE--Shamus]
-- Need to rewrite the main Jaguar execution loop to increment the VC by one
- instead of by two, which is how the real Jaguar works. [Shamus] [DONE--Shamus]
-- Sound needs a rewrite. With SDL, this shouldn't be much of a problem.
- Of course, whoever does this should realize that the PCM outs are probably
- not being used for a majority of the ROMs out there--according to the JTRM,
- you're supposed to use the I2S interface to output sound since the PCM outs
- aren't even physically hooked up in the console! [Shamus] [DONE--Shamus]
+Stuff to add/fix for the next release of Virtual Jaguar\r
+-------------------------------------------------------\r
+\r
+- Fix VC behavior to match what a real Jaguar does. Still not sure just what\r
+ the heck is going on there. [Shamus]\r
+- It would be nice to have the emulator pick up where you last left off, or at\r
+ least give you the option of continuing from your last session. This would\r
+ require save states, 'natch. ;-) [Shamus]\r
+- It would be nice to have "save states" for instant save/load capability.\r
+ [Shamus]\r
+- Cycle accuracy for GPU/DSP/OP/Blitter. [Shamus]\r
+- Need to propagate blitter fixes in the A1 <- A2 direction to the A1 -> A2\r
+ direction and the GPU fixes to various instructions to the DSP. [Shamus]\r
+- Blitter needs fixing. [Shamus]\r
+- In emulator screenshots. [Shamus]\r
+- Audio/video dumping. [Shamus]\r
+- Need to emulate bus contention. [Shamus]\r
+- Need to fix timing in the OP. As it is now, it gives a false impression of\r
+ how much it's capable of. [Shamus]\r
+- Fix coming out of fullscreen on Win32. As of now, it doesn't restore the\r
+ window position correctly [CJ]\r
+- Fix the Tripper Getem ROM so that it works. It has some tight coupling\r
+ between the M68K and the DSP that causes the DSP to starve itself; fixing\r
+ this will probably fix a bunch of other timing related issues as well.\r
+ [Shamus]\r
+\r
+\r
+Stuff that was added/fixed\r
+--------------------------\r
+\r
+- Create an EEPROMs directory (or whatever is in EEPROMPath[]) if it doesn't\r
+ already exist. [Shamus] [DONE--Flynn]\r
+- Controller handling. [Shamus] [DONE--Shamus]\r
+- Full screen option. [Shamus] [DONE--Shamus]\r
+- Command line switches for frontends. [Shamus] [DONE-Shamus]\r
+- Fix DSP code so that it doesn't hang in a spinlock waiting for the sound\r
+ buffer to empty. Probably a CS lock contention issue. [Shamus] [DONE-Shamus]\r
+- Need to fix PAL mode to work with the virtual screen code. [DONE--Shamus]\r
+- There are a few ROMs that use some "quasi-illegal" 68K instructions. Need\r
+ to patch the 68K core to deal with these in a better way than they are\r
+ now. [DONE--Shamus]\r
+ NOTE: This behavior was verified on Rayman, the problem was due to attempting\r
+ to press both left & right at the same time!\r
+- We need a comprehensive way of determining what gets written where and\r
+ by whom (i.e., blitter wrote to range $F03000-$F03230) in order to figure\r
+ out the remaining problems with various ROMs. [DONE--Shamus]\r
+- Would also be nice to be able to dynamically change the keybindings for\r
+ the various keys on the emulated Jaguar controller while inside the emulator.\r
+ [DONE--Shamus]\r
+- Make sure that VJ doesn't crash if the useJaguarBIOS key is set to 1 and the\r
+ BIOS file isn't available. [DONE--Shamus]\r
+- There is a bug either with the GPU or the blitter (most likely the latter)\r
+ which causes the spinning "A"s in the BIOS startup code to be corrupted\r
+ when they are showing their backsides. [Shamus] [DONE--Shamus]\r
+ NOTE: This behavior has been verified on a real Jaguar and as such is not\r
+ an emulator bug. A Jaguar boot ROM bug, yes, but not ours. ;-)\r
+- Make it possible to completely disable the GUI (using a switch like -nogui\r
+ or the like) for people running VJ in a cabinet. [Shamus] [DONE--Shamus]\r
+- Code to stretch the display in a generic way would be nice. [Shamus]\r
+ [DONE for OpenGL--nwagenaar]\r
+- Would be nice to have a GUI for things that are set on the command line or\r
+ in the config file. [Shamus] [DONE--Shamus]\r
+- DSP code needs to be rewritten. [Shamus] [DONE but still work to be done--Shamus]\r
+- We need to have an external configuration file for remembering a user's\r
+ preferences, such as key bindings, etc. [Shamus] [DONE--Shamus]\r
+- We need to come up with a way to fix the aspect ratio for pixel modes that\r
+ aren't square (PWIDTH != 4). [Shamus] [DONE for OpenGL--Shamus]\r
+- GUI for ROM selection [Shamus] [DONE--Shamus]\r
+- Need to rewrite the main Jaguar execution loop to increment the VC by one\r
+ instead of by two, which is how the real Jaguar works. [Shamus] [DONE--Shamus]\r
+- Sound needs a rewrite. With SDL, this shouldn't be much of a problem.\r
+ Of course, whoever does this should realize that the PCM outs are probably\r
+ not being used for a majority of the ROMs out there--according to the JTRM,\r
+ you're supposed to use the I2S interface to output sound since the PCM outs\r
+ aren't even physically hooked up in the console! [Shamus] [DONE--Shamus]\r
-//
-// Jaguar EEPROM handler
-//
-// by Cal2
-// GCC/SDL port by Niels Wagenaar (Linux/WIN32) and Caz (BeOS)
-// Cleanups/enhancements by James Hammons
-// (C) 2010 Underground Software
-//
-// JLH = James Hammons <jlhamm@acm.org>
-//
-// Who When What
-// --- ---------- ------------------------------------------------------------
-// JLH 01/16/2010 Created this log ;-)
-//
-
-#include "eeprom.h"
-
-#include <stdlib.h>
-#include <string.h> // For memset
-#include "jaguar.h"
-#include "log.h"
-#include "settings.h"
-
-//#define eeprom_LOG
-
-static uint16_t eeprom_ram[64];
-static uint16_t cdromEEPROM[64];
-
-//
-// Private function prototypes
-//
-
-static void EEPROMSave(void);
-static void eeprom_set_di(uint32_t state);
-static void eeprom_set_cs(uint32_t state);
-static uint32_t eeprom_get_do(void);
-void ReadEEPROMFromFile(FILE * file, uint16_t * ram);
-void WriteEEPROMToFile(FILE * file, uint16_t * ram);
-
-
-enum { EE_STATE_START = 1, EE_STATE_OP_A, EE_STATE_OP_B, EE_STATE_0, EE_STATE_1,
- EE_STATE_2, EE_STATE_3, EE_STATE_0_0, EE_READ_ADDRESS, EE_STATE_0_0_0,
- EE_STATE_0_0_1, EE_STATE_0_0_2, EE_STATE_0_0_3, EE_STATE_0_0_1_0, EE_READ_DATA,
- EE_STATE_BUSY, EE_STATE_1_0, EE_STATE_1_1, EE_STATE_2_0, EE_STATE_3_0 };
-
-// Local global variables
-
-static uint16_t jerry_ee_state = EE_STATE_START;
-static uint16_t jerry_ee_op = 0;
-static uint16_t jerry_ee_rstate = 0;
-static uint16_t jerry_ee_address_data = 0;
-static uint16_t jerry_ee_address_cnt = 6;
-static uint16_t jerry_ee_data = 0;
-static uint16_t jerry_ee_data_cnt = 16;
-static uint16_t jerry_writes_enabled = 0;
-static uint16_t jerry_ee_direct_jump = 0;
-
-static char eeprom_filename[MAX_PATH];
-static char cdromEEPROMFilename[MAX_PATH];
-static bool haveEEPROM = false;
-static bool haveCDROMEEPROM = false;
-
-
-void EepromInit(void)
-{
- // No need for EEPROM for the Memory Track device :-P
- if (jaguarMainROMCRC32 == 0xFDF37F47)
- {
- WriteLog("EEPROM: Memory Track device detected...\n");
- return;
- }
-
- // Handle regular cartridge EEPROM
- sprintf(eeprom_filename, "%s%08X.eeprom", vjs.EEPROMPath, (unsigned int)jaguarMainROMCRC32);
- sprintf(cdromEEPROMFilename, "%scdrom.eeprom", vjs.EEPROMPath);
- FILE * fp = fopen(eeprom_filename, "rb");
-
- if (fp)
- {
- ReadEEPROMFromFile(fp, eeprom_ram);
- fclose(fp);
- WriteLog("EEPROM: Loaded from %s\n", eeprom_filename);
- haveEEPROM = true;
- }
- else
- WriteLog("EEPROM: Could not open file \"%s\"!\n", eeprom_filename);
-
- // Handle JagCD EEPROM
- fp = fopen(cdromEEPROMFilename, "rb");
-
- if (fp)
- {
- ReadEEPROMFromFile(fp, cdromEEPROM);
- fclose(fp);
- WriteLog("EEPROM: Loaded from cdrom.eeprom\n");
- haveCDROMEEPROM = true;
- }
- else
- WriteLog("EEPROM: Could not open file \"%s\"!\n", cdromEEPROMFilename);
-}
-
-
-void EepromReset(void)
-{
- if (!haveEEPROM)
- memset(eeprom_ram, 0xFF, 64 * sizeof(uint16_t));
-
- if (!haveCDROMEEPROM)
- memset(cdromEEPROM, 0xFF, 64 * sizeof(uint16_t));
-}
-
-
-void EepromDone(void)
-{
- WriteLog("EEPROM: Done.\n");
-}
-
-
-static void EEPROMSave(void)
-{
- // Write out regular cartridge EEPROM data
- FILE * fp = fopen(eeprom_filename, "wb");
-
- if (fp)
- {
- WriteEEPROMToFile(fp, eeprom_ram);
- fclose(fp);
- }
- else
- WriteLog("EEPROM: Could not create file \"%s!\"\n", eeprom_filename);
-
- // Write out JagCD EEPROM data
- fp = fopen(cdromEEPROMFilename, "wb");
-
- if (fp)
- {
- WriteEEPROMToFile(fp, cdromEEPROM);
- fclose(fp);
- }
- else
- WriteLog("EEPROM: Could not create file \"%s!\"\n", cdromEEPROMFilename);
-}
-
-
-//
-// Read/write EEPROM files to disk in an endian safe manner
-//
-void ReadEEPROMFromFile(FILE * file, uint16_t * ram)
-{
- uint8_t buffer[128];
- size_t ignored = fread(buffer, 1, 128, file);
-
- for(int i=0; i<64; i++)
- ram[i] = (buffer[(i * 2) + 0] << 8) | buffer[(i * 2) + 1];
-}
-
-
-void WriteEEPROMToFile(FILE * file, uint16_t * ram)
-{
- uint8_t buffer[128];
-
- for(int i=0; i<64; i++)
- {
- buffer[(i * 2) + 0] = ram[i] >> 8;
- buffer[(i * 2) + 1] = ram[i] & 0xFF;
- }
-
- fwrite(buffer, 1, 128, file);
-}
-
-
-uint8_t EepromReadByte(uint32_t offset)
-{
- switch (offset)
- {
- case 0xF14001:
- return eeprom_get_do();
- case 0xF14801:
- break;
- case 0xF15001:
- eeprom_set_cs(1);
- break;
-// default: WriteLog("EEPROM: unmapped 0x%.8x\n", offset); break;
- }
-
- return 0x00;
-}
-
-
-uint16_t EepromReadWord(uint32_t offset)
-{
- return ((uint16_t)EepromReadByte(offset + 0) << 8) | EepromReadByte(offset + 1);
-}
-
-
-void EepromWriteByte(uint32_t offset, uint8_t data)
-{
- switch (offset)
- {
- case 0xF14001:
- break;
- case 0xF14801:
- eeprom_set_di(data & 0x01);
- break;
- case 0xF15001:
- eeprom_set_cs(1);
- break;
-// default: WriteLog("eeprom: unmapped 0x%.8x\n",offset); break;
- }
-}
-
-
-void EepromWriteWord(uint32_t offset, uint16_t data)
-{
- EepromWriteByte(offset + 0, (data >> 8) & 0xFF);
- EepromWriteByte(offset + 1, data & 0xFF);
-}
-
-
-/*
-;
-; Commands specific to the National Semiconductor NM93C14
-;
-;
-; 9-bit commands..
-; 876543210
-eEWDS equ %100000000 ;Erase/Write disable (default)
-eWRAL equ %100010000 ;Writes all registers
-eERAL equ %100100000 ;Erase all registers
-eEWEN equ %100110000 ;Erase/write Enable
-eWRITE equ %101000000 ;Write selected register
-eREAD equ %110000000 ;read from EEPROM
-eERASE equ %111000000 ;Erase selected register
-*/
-
-
-static void eeprom_set_di(uint32_t data)
-{
-// WriteLog("eeprom: di=%i\n",data);
-// WriteLog("eeprom: state %i\n",jerry_ee_state);
- switch (jerry_ee_state)
- {
- case EE_STATE_START:
- jerry_ee_state = EE_STATE_OP_A;
- break;
- case EE_STATE_OP_A:
- jerry_ee_op = (data << 1);
- jerry_ee_state = EE_STATE_OP_B;
- break;
- case EE_STATE_OP_B:
- jerry_ee_op |= data;
- jerry_ee_direct_jump = 0;
-// WriteLog("eeprom: opcode %i\n",jerry_ee_op);
-
- switch (jerry_ee_op)
- {
- // Opcode 00: eEWEN, eERAL, eWRAL, eEWNDS
- case 0: jerry_ee_state = EE_STATE_0; break;
- // Opcode 01: eWRITE (Write selected register)
- case 1: jerry_ee_state = EE_STATE_1; break;
- // Opcode 10: eREAD (Read from EEPROM)
- case 2: jerry_ee_state = EE_STATE_2; break;
- // Opcode 11: eERASE (Erase selected register)
- case 3: jerry_ee_state = EE_STATE_3; break;
- }
-
- eeprom_set_di(data);
- break;
- case EE_STATE_0:
- jerry_ee_rstate = EE_STATE_0_0;
- jerry_ee_state = EE_READ_ADDRESS;
- jerry_ee_direct_jump = 1;
- jerry_ee_address_cnt = 6;
- jerry_ee_address_data = 0;
- break;
- case EE_STATE_0_0:
- switch ((jerry_ee_address_data >> 4) & 0x03)
- {
- // Opcode 00 00: eEWDS (Erase/Write disable)
- case 0: jerry_ee_state=EE_STATE_0_0_0; break;
- // Opcode 00 01: eWRAL (Write all registers)
- case 1: jerry_ee_state=EE_STATE_0_0_1; break;
- // Opcode 00 10: eERAL (Erase all registers)
- case 2: jerry_ee_state=EE_STATE_0_0_2; break;
- // Opcode 00 11: eEWEN (Erase/Write enable)
- case 3: jerry_ee_state=EE_STATE_0_0_3; break;
- }
-
- eeprom_set_di(data);
- break;
- case EE_STATE_0_0_0:
- // writes disable
- // WriteLog("eeprom: read only\n");
- jerry_writes_enabled = 0;
- jerry_ee_state = EE_STATE_START;
- break;
- case EE_STATE_0_0_1:
- // writes all
- jerry_ee_rstate = EE_STATE_0_0_1_0;
- jerry_ee_state = EE_READ_DATA;
- jerry_ee_data_cnt = 16;
- jerry_ee_data = 0;
- jerry_ee_direct_jump = 1;
- break;
- case EE_STATE_0_0_1_0:
- // WriteLog("eeprom: filling eeprom with 0x%.4x\n",data);
- if (jerry_writes_enabled)
- {
- for(int i=0; i<64; i++)
- eeprom_ram[i] = jerry_ee_data;
-
- EEPROMSave(); // Save it NOW!
- }
-
- //else
- // WriteLog("eeprom: not writing because read only\n");
- jerry_ee_state = EE_STATE_BUSY;
- break;
- case EE_STATE_0_0_2:
- // erase all
- //WriteLog("eeprom: erasing eeprom\n");
- if (jerry_writes_enabled)
- for(int i=0; i<64; i++)
- eeprom_ram[i] = 0xFFFF;
-
- jerry_ee_state = EE_STATE_BUSY;
- break;
- case EE_STATE_0_0_3:
- // writes enable
- //WriteLog("eeprom: read/write\n");
- jerry_writes_enabled = 1;
- jerry_ee_state = EE_STATE_START;
- break;
- case EE_STATE_1:
- jerry_ee_rstate = EE_STATE_1_0;
- jerry_ee_state = EE_READ_ADDRESS;
- jerry_ee_address_cnt = 6;
- jerry_ee_address_data = 0;
- jerry_ee_direct_jump = 1;
- break;
- case EE_STATE_1_0:
- jerry_ee_rstate = EE_STATE_1_1;
- jerry_ee_state = EE_READ_DATA;
- jerry_ee_data_cnt = 16;
- jerry_ee_data = 0;
- jerry_ee_direct_jump = 1;
- break;
- case EE_STATE_1_1:
- //WriteLog("eeprom: writing 0x%.4x at 0x%.2x\n",jerry_ee_data,jerry_ee_address_data);
- if (jerry_writes_enabled)
- {
- eeprom_ram[jerry_ee_address_data] = jerry_ee_data;
- EEPROMSave(); // Save it NOW!
- }
-
- jerry_ee_state = EE_STATE_BUSY;
- break;
- case EE_STATE_2:
- jerry_ee_rstate = EE_STATE_2_0;
- jerry_ee_state = EE_READ_ADDRESS;
- jerry_ee_address_cnt = 6;
- jerry_ee_address_data = 0;
- jerry_ee_data_cnt = 16;
- jerry_ee_data = 0;
- break;
- case EE_STATE_3:
- jerry_ee_rstate = EE_STATE_3_0;
- jerry_ee_state = EE_READ_ADDRESS;
- jerry_ee_address_cnt = 6;
- jerry_ee_address_data = 0;
- jerry_ee_direct_jump = 1;
- break;
- case EE_STATE_3_0:
- //WriteLog("eeprom: erasing 0x%.2x\n",jerry_ee_address_data);
- if (jerry_writes_enabled)
- eeprom_ram[jerry_ee_address_data] = 0xFFFF;
-
- jerry_ee_state = EE_STATE_BUSY;
- break;
- case EE_READ_DATA:
- //WriteLog("eeprom:\t\t\t%i bit %i\n",data,jerry_ee_data_cnt-1);
- jerry_ee_data <<= 1;
- jerry_ee_data |= data;
- jerry_ee_data_cnt--;
-
- if (!jerry_ee_data_cnt)
- {
- jerry_ee_state = jerry_ee_rstate;
-
- if (jerry_ee_direct_jump)
- eeprom_set_di(data);
- }
-
- break;
- case EE_READ_ADDRESS:
- jerry_ee_address_data <<= 1;
- jerry_ee_address_data |= data;
- jerry_ee_address_cnt--;
-// WriteLog("eeprom:\t%i bits remaining\n",jerry_ee_address_cnt);
-
- if (!jerry_ee_address_cnt)
- {
- jerry_ee_state = jerry_ee_rstate;
- //WriteLog("eeprom:\t\tread address 0x%.2x\n",jerry_ee_address_data);
-
- if (jerry_ee_direct_jump)
- eeprom_set_di(data);
- }
-
- break;
- default:
- jerry_ee_state = EE_STATE_OP_A;
- }
-}
-
-
-static void eeprom_set_cs(uint32_t /*state*/)
-{
-// WriteLog("eeprom: cs=%i\n",state);
- jerry_ee_state = EE_STATE_START;
- jerry_ee_op = 0;
- jerry_ee_rstate = 0;
- jerry_ee_address_data = 0;
- jerry_ee_address_cnt = 6;
- jerry_ee_data = 0;
- jerry_ee_data_cnt = 16;
- jerry_writes_enabled = 1;
-}
-
-
-static uint32_t eeprom_get_do(void)
-{
- uint16_t data = 1;
-
- switch (jerry_ee_state)
- {
- case EE_STATE_START:
- data = 1;
- break;
- case EE_STATE_BUSY:
- jerry_ee_state = EE_STATE_START;
- data = 0;
- break;
- case EE_STATE_2_0:
- jerry_ee_data_cnt--;
- data = (eeprom_ram[jerry_ee_address_data] >> jerry_ee_data_cnt) & 0x01;
-
- if (!jerry_ee_data_cnt)
- {
- //WriteLog("eeprom: read 0x%.4x at 0x%.2x cpu %i pc=0x%.8x\n",eeprom_ram[jerry_ee_address_data],jerry_ee_address_data,jaguar_cpu_in_exec,s68000readPC());
- jerry_ee_state = EE_STATE_START;
- }
- break;
- }
-
-// WriteLog("eeprom: do=%i\n",data);
- return data;
-}
-
+//\r
+// Jaguar EEPROM handler\r
+//\r
+// by Cal2\r
+// GCC/SDL port by Niels Wagenaar (Linux/WIN32) and Caz (BeOS)\r
+// Cleanups/enhancements by James Hammons\r
+// (C) 2010 Underground Software\r
+//\r
+// JLH = James Hammons <jlhamm@acm.org>\r
+// JPM = Jean-Paul Mari <djipi.mari@gmail.com>\r
+//\r
+// Who When What\r
+// --- ---------- ------------------------------------------------------------\r
+// JLH 01/16/2010 Created this log ;-)\r
+// JPM 10/11/2017 Directory detection and creation if missing\r
+//\r
+\r
+#include "eeprom.h"\r
+#include <direct.h>\r
+#include <stdlib.h>\r
+#include <string.h> // For memset\r
+#include "jaguar.h"\r
+#include "log.h"\r
+#include "settings.h"\r
+\r
+#define eeprom_LOG\r
+\r
+static uint16_t eeprom_ram[64];\r
+static uint16_t cdromEEPROM[64];\r
+\r
+//\r
+// Private function prototypes\r
+//\r
+\r
+static void EEPROMSave(void);\r
+static void eeprom_set_di(uint32_t state);\r
+static void eeprom_set_cs(uint32_t state);\r
+static uint32_t eeprom_get_do(void);\r
+void ReadEEPROMFromFile(FILE * file, uint16_t * ram);\r
+void WriteEEPROMToFile(FILE * file, uint16_t * ram);\r
+\r
+\r
+enum { EE_STATE_START = 1, EE_STATE_OP_A, EE_STATE_OP_B, EE_STATE_0, EE_STATE_1,\r
+ EE_STATE_2, EE_STATE_3, EE_STATE_0_0, EE_READ_ADDRESS, EE_STATE_0_0_0,\r
+ EE_STATE_0_0_1, EE_STATE_0_0_2, EE_STATE_0_0_3, EE_STATE_0_0_1_0, EE_READ_DATA,\r
+ EE_STATE_BUSY, EE_STATE_1_0, EE_STATE_1_1, EE_STATE_2_0, EE_STATE_3_0 };\r
+\r
+// Local global variables\r
+\r
+static uint16_t jerry_ee_state = EE_STATE_START;\r
+static uint16_t jerry_ee_op = 0;\r
+static uint16_t jerry_ee_rstate = 0;\r
+static uint16_t jerry_ee_address_data = 0;\r
+static uint16_t jerry_ee_address_cnt = 6;\r
+static uint16_t jerry_ee_data = 0;\r
+static uint16_t jerry_ee_data_cnt = 16;\r
+static uint16_t jerry_writes_enabled = 0;\r
+static uint16_t jerry_ee_direct_jump = 0;\r
+\r
+static char eeprom_filename[MAX_PATH];\r
+static char cdromEEPROMFilename[MAX_PATH];\r
+static bool haveEEPROM = false;\r
+static bool haveCDROMEEPROM = false;\r
+\r
+\r
+// EEPROM initialisations\r
+void EepromInit(void)\r
+{\r
+ FILE * fp;\r
+\r
+ // No need for EEPROM for the Memory Track device :-P\r
+ if (jaguarMainROMCRC32 == 0xFDF37F47)\r
+ {\r
+ WriteLog("EEPROM: Memory Track device detected...\n");\r
+ }\r
+ else\r
+ {\r
+ // Handle regular cartridge EEPROM\r
+ sprintf(eeprom_filename, "%s%08X.eeprom", vjs.EEPROMPath, (unsigned int)jaguarMainROMCRC32);\r
+ fp = fopen(eeprom_filename, "rb");\r
+\r
+ if (fp)\r
+ {\r
+ ReadEEPROMFromFile(fp, eeprom_ram);\r
+ fclose(fp);\r
+ WriteLog("EEPROM: Loaded from %s\n", eeprom_filename);\r
+ haveEEPROM = true;\r
+ }\r
+ else\r
+ {\r
+ WriteLog("EEPROM: Could not open file \"%s\"!\n", eeprom_filename);\r
+ }\r
+\r
+ // Handle JagCD EEPROM\r
+ sprintf(cdromEEPROMFilename, "%scdrom.eeprom", vjs.EEPROMPath);\r
+ fp = fopen(cdromEEPROMFilename, "rb");\r
+\r
+ if (fp)\r
+ {\r
+ ReadEEPROMFromFile(fp, cdromEEPROM);\r
+ fclose(fp);\r
+ WriteLog("EEPROM: Loaded from cdrom.eeprom\n");\r
+ haveCDROMEEPROM = true;\r
+ }\r
+ else\r
+ {\r
+ WriteLog("EEPROM: Could not open file \"%s\"!\n", cdromEEPROMFilename);\r
+ }\r
+ }\r
+}\r
+\r
+\r
+// EEPROM reset\r
+void EepromReset(void)\r
+{\r
+ if (!haveEEPROM)\r
+ memset(eeprom_ram, 0xFF, 64 * sizeof(uint16_t));\r
+\r
+ if (!haveCDROMEEPROM)\r
+ memset(cdromEEPROM, 0xFF, 64 * sizeof(uint16_t));\r
+}\r
+\r
+\r
+//\r
+void EepromDone(void)\r
+{\r
+ WriteLog("EEPROM: Done.\n");\r
+}\r
+\r
+\r
+// EEPROM save\r
+static void EEPROMSave(void)\r
+{\r
+ FILE * fp;\r
+\r
+ // Check if EEPROM directory exists and try to create it if not\r
+ if (_mkdir(vjs.EEPROMPath))\r
+ {\r
+ WriteLog("EEPROM: Could not create directory \"%s!\"\n", vjs.EEPROMPath);\r
+ }\r
+\r
+ // Write out regular cartridge EEPROM data\r
+ fp = fopen(eeprom_filename, "wb");\r
+ if (fp)\r
+ {\r
+ WriteEEPROMToFile(fp, eeprom_ram);\r
+ fclose(fp);\r
+ }\r
+ else\r
+ {\r
+ WriteLog("EEPROM: Could not create file \"%s!\"\n", eeprom_filename);\r
+ }\r
+\r
+ // Write out JagCD EEPROM data\r
+ fp = fopen(cdromEEPROMFilename, "wb");\r
+ if (fp)\r
+ {\r
+ WriteEEPROMToFile(fp, cdromEEPROM);\r
+ fclose(fp);\r
+ }\r
+ else\r
+ {\r
+ WriteLog("EEPROM: Could not create file \"%s!\"\n", cdromEEPROMFilename);\r
+ }\r
+}\r
+\r
+\r
+//\r
+// Read/write EEPROM files to disk in an endian safe manner\r
+//\r
+void ReadEEPROMFromFile(FILE * file, uint16_t * ram)\r
+{\r
+ uint8_t buffer[128];\r
+ size_t ignored = fread(buffer, 1, 128, file);\r
+\r
+ for(int i=0; i<64; i++)\r
+ ram[i] = (buffer[(i * 2) + 0] << 8) | buffer[(i * 2) + 1];\r
+}\r
+\r
+\r
+void WriteEEPROMToFile(FILE * file, uint16_t * ram)\r
+{\r
+ uint8_t buffer[128];\r
+\r
+ for(int i=0; i<64; i++)\r
+ {\r
+ buffer[(i * 2) + 0] = ram[i] >> 8;\r
+ buffer[(i * 2) + 1] = ram[i] & 0xFF;\r
+ }\r
+\r
+ fwrite(buffer, 1, 128, file);\r
+}\r
+\r
+\r
+uint8_t EepromReadByte(uint32_t offset)\r
+{\r
+ switch (offset)\r
+ {\r
+ case 0xF14001:\r
+ return eeprom_get_do();\r
+ case 0xF14801:\r
+ break;\r
+ case 0xF15001:\r
+ eeprom_set_cs(1);\r
+ break;\r
+ default:\r
+#ifdef eeprom_LOG\r
+ WriteLog("EEPROM: unmapped 0x%.8x\n", offset);\r
+#endif\r
+ break;\r
+ }\r
+\r
+ return 0x00;\r
+}\r
+\r
+\r
+uint16_t EepromReadWord(uint32_t offset)\r
+{\r
+ return ((uint16_t)EepromReadByte(offset + 0) << 8) | EepromReadByte(offset + 1);\r
+}\r
+\r
+\r
+void EepromWriteByte(uint32_t offset, uint8_t data)\r
+{\r
+ switch (offset)\r
+ {\r
+ case 0xF14001:\r
+ break;\r
+ case 0xF14801:\r
+ eeprom_set_di(data & 0x01);\r
+ break;\r
+ case 0xF15001:\r
+ eeprom_set_cs(1);\r
+ break;\r
+ default:\r
+#ifdef eeprom_LOG\r
+ WriteLog("eeprom: unmapped 0x%.8x\n",offset);\r
+#endif\r
+ break;\r
+ }\r
+}\r
+\r
+\r
+void EepromWriteWord(uint32_t offset, uint16_t data)\r
+{\r
+ EepromWriteByte(offset + 0, (data >> 8) & 0xFF);\r
+ EepromWriteByte(offset + 1, data & 0xFF);\r
+}\r
+\r
+\r
+/*\r
+;\r
+; Commands specific to the National Semiconductor NM93C14\r
+;\r
+;\r
+; 9-bit commands..\r
+; 876543210\r
+eEWDS equ %100000000 ;Erase/Write disable (default)\r
+eWRAL equ %100010000 ;Writes all registers\r
+eERAL equ %100100000 ;Erase all registers\r
+eEWEN equ %100110000 ;Erase/write Enable\r
+eWRITE equ %101000000 ;Write selected register\r
+eREAD equ %110000000 ;read from EEPROM\r
+eERASE equ %111000000 ;Erase selected register\r
+*/\r
+\r
+\r
+static void eeprom_set_di(uint32_t data)\r
+{\r
+#ifdef eeprom_LOG\r
+ WriteLog("eeprom: di=%i\n",data);\r
+ WriteLog("eeprom: state %i\n",jerry_ee_state);\r
+#endif\r
+\r
+ switch (jerry_ee_state)\r
+ {\r
+ case EE_STATE_START:\r
+ jerry_ee_state = EE_STATE_OP_A;\r
+ break;\r
+ case EE_STATE_OP_A:\r
+ jerry_ee_op = (data << 1);\r
+ jerry_ee_state = EE_STATE_OP_B;\r
+ break;\r
+ case EE_STATE_OP_B:\r
+ jerry_ee_op |= data;\r
+ jerry_ee_direct_jump = 0;\r
+#ifdef eeprom_LOG\r
+ WriteLog("eeprom: opcode %i\n",jerry_ee_op);\r
+#endif\r
+\r
+ switch (jerry_ee_op)\r
+ {\r
+ // Opcode 00: eEWEN, eERAL, eWRAL, eEWNDS\r
+ case 0: jerry_ee_state = EE_STATE_0; break;\r
+ // Opcode 01: eWRITE (Write selected register)\r
+ case 1: jerry_ee_state = EE_STATE_1; break;\r
+ // Opcode 10: eREAD (Read from EEPROM)\r
+ case 2: jerry_ee_state = EE_STATE_2; break;\r
+ // Opcode 11: eERASE (Erase selected register)\r
+ case 3: jerry_ee_state = EE_STATE_3; break;\r
+ }\r
+\r
+ eeprom_set_di(data);\r
+ break;\r
+ case EE_STATE_0:\r
+ jerry_ee_rstate = EE_STATE_0_0;\r
+ jerry_ee_state = EE_READ_ADDRESS;\r
+ jerry_ee_direct_jump = 1;\r
+ jerry_ee_address_cnt = 6;\r
+ jerry_ee_address_data = 0;\r
+ break;\r
+ case EE_STATE_0_0:\r
+ switch ((jerry_ee_address_data >> 4) & 0x03)\r
+ {\r
+ // Opcode 00 00: eEWDS (Erase/Write disable)\r
+ case 0: jerry_ee_state=EE_STATE_0_0_0; break;\r
+ // Opcode 00 01: eWRAL (Write all registers)\r
+ case 1: jerry_ee_state=EE_STATE_0_0_1; break;\r
+ // Opcode 00 10: eERAL (Erase all registers)\r
+ case 2: jerry_ee_state=EE_STATE_0_0_2; break;\r
+ // Opcode 00 11: eEWEN (Erase/Write enable)\r
+ case 3: jerry_ee_state=EE_STATE_0_0_3; break;\r
+ }\r
+\r
+ eeprom_set_di(data);\r
+ break;\r
+ case EE_STATE_0_0_0:\r
+ // writes disable\r
+#ifdef eeprom_LOG\r
+ WriteLog("eeprom: read only\n");\r
+#endif\r
+ jerry_writes_enabled = 0;\r
+ jerry_ee_state = EE_STATE_START;\r
+ break;\r
+ case EE_STATE_0_0_1:\r
+ // writes all\r
+ jerry_ee_rstate = EE_STATE_0_0_1_0;\r
+ jerry_ee_state = EE_READ_DATA;\r
+ jerry_ee_data_cnt = 16;\r
+ jerry_ee_data = 0;\r
+ jerry_ee_direct_jump = 1;\r
+ break;\r
+ case EE_STATE_0_0_1_0:\r
+#ifdef eeprom_LOG\r
+ WriteLog("eeprom: filling eeprom with 0x%.4x\n",data);\r
+#endif\r
+ if (jerry_writes_enabled)\r
+ {\r
+ for(int i=0; i<64; i++)\r
+ eeprom_ram[i] = jerry_ee_data;\r
+\r
+ EEPROMSave(); // Save it NOW!\r
+ }\r
+\r
+ //else\r
+#ifdef eeprom_LOG\r
+ WriteLog("eeprom: not writing because read only\n");\r
+#endif\r
+ jerry_ee_state = EE_STATE_BUSY;\r
+ break;\r
+ case EE_STATE_0_0_2:\r
+ // erase all\r
+#ifdef eeprom_LOG\r
+ WriteLog("eeprom: erasing eeprom\n");\r
+#endif\r
+ if (jerry_writes_enabled)\r
+ for(int i=0; i<64; i++)\r
+ eeprom_ram[i] = 0xFFFF;\r
+\r
+ jerry_ee_state = EE_STATE_BUSY;\r
+ break;\r
+ case EE_STATE_0_0_3:\r
+ // writes enable\r
+#ifdef eeprom_LOG\r
+ WriteLog("eeprom: read/write\n");\r
+#endif\r
+ jerry_writes_enabled = 1;\r
+ jerry_ee_state = EE_STATE_START;\r
+ break;\r
+ case EE_STATE_1:\r
+ jerry_ee_rstate = EE_STATE_1_0;\r
+ jerry_ee_state = EE_READ_ADDRESS;\r
+ jerry_ee_address_cnt = 6;\r
+ jerry_ee_address_data = 0;\r
+ jerry_ee_direct_jump = 1;\r
+ break;\r
+ case EE_STATE_1_0:\r
+ jerry_ee_rstate = EE_STATE_1_1;\r
+ jerry_ee_state = EE_READ_DATA;\r
+ jerry_ee_data_cnt = 16;\r
+ jerry_ee_data = 0;\r
+ jerry_ee_direct_jump = 1;\r
+ break;\r
+ case EE_STATE_1_1:\r
+#ifdef eeprom_LOG\r
+ WriteLog("eeprom: writing 0x%.4x at 0x%.2x\n",jerry_ee_data,jerry_ee_address_data);\r
+#endif\r
+ if (jerry_writes_enabled)\r
+ {\r
+ eeprom_ram[jerry_ee_address_data] = jerry_ee_data;\r
+ EEPROMSave(); // Save it NOW!\r
+ }\r
+\r
+ jerry_ee_state = EE_STATE_BUSY;\r
+ break;\r
+ case EE_STATE_2:\r
+ jerry_ee_rstate = EE_STATE_2_0;\r
+ jerry_ee_state = EE_READ_ADDRESS;\r
+ jerry_ee_address_cnt = 6;\r
+ jerry_ee_address_data = 0;\r
+ jerry_ee_data_cnt = 16;\r
+ jerry_ee_data = 0;\r
+ break;\r
+ case EE_STATE_3:\r
+ jerry_ee_rstate = EE_STATE_3_0;\r
+ jerry_ee_state = EE_READ_ADDRESS;\r
+ jerry_ee_address_cnt = 6;\r
+ jerry_ee_address_data = 0;\r
+ jerry_ee_direct_jump = 1;\r
+ break;\r
+ case EE_STATE_3_0:\r
+#ifdef eeprom_LOG\r
+ WriteLog("eeprom: erasing 0x%.2x\n",jerry_ee_address_data);\r
+#endif\r
+ if (jerry_writes_enabled)\r
+ eeprom_ram[jerry_ee_address_data] = 0xFFFF;\r
+\r
+ jerry_ee_state = EE_STATE_BUSY;\r
+ break;\r
+ case EE_READ_DATA:\r
+#ifdef eeprom_LOG\r
+ WriteLog("eeprom:\t\t\t%i bit %i\n",data,jerry_ee_data_cnt-1);\r
+#endif\r
+ jerry_ee_data <<= 1;\r
+ jerry_ee_data |= data;\r
+ jerry_ee_data_cnt--;\r
+\r
+ if (!jerry_ee_data_cnt)\r
+ {\r
+ jerry_ee_state = jerry_ee_rstate;\r
+\r
+ if (jerry_ee_direct_jump)\r
+ eeprom_set_di(data);\r
+ }\r
+\r
+ break;\r
+ case EE_READ_ADDRESS:\r
+ jerry_ee_address_data <<= 1;\r
+ jerry_ee_address_data |= data;\r
+ jerry_ee_address_cnt--;\r
+#ifdef eeprom_LOG\r
+ WriteLog("eeprom:\t%i bits remaining\n",jerry_ee_address_cnt);\r
+#endif\r
+\r
+ if (!jerry_ee_address_cnt)\r
+ {\r
+ jerry_ee_state = jerry_ee_rstate;\r
+#ifdef eeprom_LOG\r
+ WriteLog("eeprom:\t\tread address 0x%.2x\n",jerry_ee_address_data);\r
+#endif\r
+\r
+ if (jerry_ee_direct_jump)\r
+ eeprom_set_di(data);\r
+ }\r
+\r
+ break;\r
+ default:\r
+ jerry_ee_state = EE_STATE_OP_A;\r
+ }\r
+}\r
+\r
+\r
+static void eeprom_set_cs(uint32_t state)\r
+{\r
+#ifdef eeprom_LOG\r
+ WriteLog("eeprom: cs=%i\n",state);\r
+#endif\r
+ jerry_ee_state = EE_STATE_START;\r
+ jerry_ee_op = 0;\r
+ jerry_ee_rstate = 0;\r
+ jerry_ee_address_data = 0;\r
+ jerry_ee_address_cnt = 6;\r
+ jerry_ee_data = 0;\r
+ jerry_ee_data_cnt = 16;\r
+ jerry_writes_enabled = 1;\r
+}\r
+\r
+\r
+static uint32_t eeprom_get_do(void)\r
+{\r
+ uint16_t data = 1;\r
+\r
+ switch (jerry_ee_state)\r
+ {\r
+ case EE_STATE_START:\r
+ data = 1;\r
+ break;\r
+ case EE_STATE_BUSY:\r
+ jerry_ee_state = EE_STATE_START;\r
+ data = 0;\r
+ break;\r
+ case EE_STATE_2_0:\r
+ jerry_ee_data_cnt--;\r
+ data = (eeprom_ram[jerry_ee_address_data] >> jerry_ee_data_cnt) & 0x01;\r
+\r
+ if (!jerry_ee_data_cnt)\r
+ {\r
+#ifdef eeprom_LOG\r
+ //WriteLog("eeprom: read 0x%.4x at 0x%.2x cpu %i pc=0x%.8x\n",eeprom_ram[jerry_ee_address_data],jerry_ee_address_data,jaguar_cpu_in_exec,s68000readPC());\r
+#endif\r
+ jerry_ee_state = EE_STATE_START;\r
+ }\r
+ break;\r
+ }\r
+\r
+#ifdef eeprom_LOG\r
+ WriteLog("eeprom: do=%i\n",data);\r
+#endif\r
+ return data;\r
+}\r
+\r