mirror of
https://github.com/PCSX2/pcsx2.git
synced 2026-01-31 01:15:24 +01:00
Around half of the debug and console output from the DEV9 tree already had this prefix. Adding it everywhere for consistency. Also fixed misspelling of "Unknown" whilst there.
1158 lines
25 KiB
C++
1158 lines
25 KiB
C++
/* PCSX2 - PS2 Emulator for PCs
|
|
* Copyright (C) 2002-2020 PCSX2 Dev Team
|
|
*
|
|
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
|
* of the GNU Lesser General Public License as published by the Free Software Found-
|
|
* ation, either version 3 of the License, or (at your option) any later version.
|
|
*
|
|
* PCSX2 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 PCSX2.
|
|
* If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include "PrecompiledHeader.h"
|
|
#define WINVER 0x0600
|
|
#define _WIN32_WINNT 0x0600
|
|
|
|
#ifdef _WIN32
|
|
//#include <winsock2.h>
|
|
#include <Winioctl.h>
|
|
#include <windows.h>
|
|
#elif defined(__linux__) || defined(__APPLE__)
|
|
#include <sys/types.h>
|
|
#include <sys/mman.h>
|
|
#include <err.h>
|
|
#endif
|
|
|
|
#include "ghc/filesystem.h"
|
|
|
|
#include <fcntl.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <errno.h>
|
|
#include <stdarg.h>
|
|
#define EXTERN
|
|
#include "DEV9.h"
|
|
#undef EXTERN
|
|
#include "Config.h"
|
|
#include "AppConfig.h"
|
|
#include "smap.h"
|
|
|
|
|
|
#ifdef _WIN32
|
|
#pragma warning(disable : 4244)
|
|
|
|
HINSTANCE hInst = NULL;
|
|
#endif
|
|
|
|
//#define HDD_48BIT
|
|
|
|
#if defined(__i386__) && !defined(_WIN32)
|
|
|
|
static __inline__ unsigned long long GetTickCount(void)
|
|
{
|
|
unsigned long long int x;
|
|
__asm__ volatile("rdtsc"
|
|
: "=A"(x));
|
|
return x;
|
|
}
|
|
|
|
#elif defined(__x86_64__) && !defined(_WIN32)
|
|
|
|
static __inline__ unsigned long long GetTickCount(void)
|
|
{
|
|
unsigned hi, lo;
|
|
__asm__ __volatile__("rdtsc"
|
|
: "=a"(lo), "=d"(hi));
|
|
return ((unsigned long long)lo) | (((unsigned long long)hi) << 32);
|
|
}
|
|
|
|
#endif
|
|
|
|
// clang-format off
|
|
u8 eeprom[] = {
|
|
//0x6D, 0x76, 0x63, 0x61, 0x31, 0x30, 0x08, 0x01,
|
|
0x76, 0x6D, 0x61, 0x63, 0x30, 0x31, 0x07, 0x02,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
};
|
|
// clang-format on
|
|
|
|
#ifdef _WIN32
|
|
HANDLE hEeprom;
|
|
HANDLE mapping;
|
|
#else
|
|
int hEeprom;
|
|
int mapping;
|
|
#endif
|
|
|
|
std::string s_strIniPath = "inis";
|
|
std::string s_strLogPath = "logs";
|
|
|
|
bool isRunning = false;
|
|
|
|
s32 DEV9init()
|
|
{
|
|
DevCon.WriteLn("DEV9: DEV9init");
|
|
|
|
memset(&dev9, 0, sizeof(dev9));
|
|
dev9.ata = new ATA();
|
|
DevCon.WriteLn("DEV9: DEV9init2");
|
|
|
|
DevCon.WriteLn("DEV9: DEV9init3");
|
|
|
|
FLASHinit();
|
|
|
|
#ifdef _WIN32
|
|
hEeprom = CreateFile(
|
|
L"eeprom.dat",
|
|
GENERIC_READ | GENERIC_WRITE,
|
|
0,
|
|
NULL,
|
|
OPEN_EXISTING,
|
|
FILE_FLAG_WRITE_THROUGH,
|
|
NULL);
|
|
|
|
if (hEeprom == INVALID_HANDLE_VALUE)
|
|
{
|
|
dev9.eeprom = (u16*)eeprom;
|
|
}
|
|
else
|
|
{
|
|
mapping = CreateFileMapping(hEeprom, NULL, PAGE_READWRITE, 0, 0, NULL);
|
|
if (mapping == INVALID_HANDLE_VALUE)
|
|
{
|
|
CloseHandle(hEeprom);
|
|
dev9.eeprom = (u16*)eeprom;
|
|
}
|
|
else
|
|
{
|
|
dev9.eeprom = (u16*)MapViewOfFile(mapping, FILE_MAP_WRITE, 0, 0, 0);
|
|
|
|
if (dev9.eeprom == NULL)
|
|
{
|
|
CloseHandle(mapping);
|
|
CloseHandle(hEeprom);
|
|
dev9.eeprom = (u16*)eeprom;
|
|
}
|
|
}
|
|
}
|
|
#else
|
|
hEeprom = open("eeprom.dat", O_RDWR, 0);
|
|
|
|
if (-1 == hEeprom)
|
|
{
|
|
dev9.eeprom = (u16*)eeprom;
|
|
}
|
|
else
|
|
{
|
|
dev9.eeprom = (u16*)mmap(NULL, 64, PROT_READ | PROT_WRITE, MAP_FILE | MAP_SHARED, hEeprom, 0);
|
|
|
|
if (dev9.eeprom == NULL)
|
|
{
|
|
close(hEeprom);
|
|
dev9.eeprom = (u16*)eeprom;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
int rxbi;
|
|
|
|
for (rxbi = 0; rxbi < (SMAP_BD_SIZE / 8); rxbi++)
|
|
{
|
|
smap_bd_t* pbd = (smap_bd_t*)&dev9.dev9R[SMAP_BD_RX_BASE & 0xffff];
|
|
pbd = &pbd[rxbi];
|
|
|
|
pbd->ctrl_stat = SMAP_BD_RX_EMPTY;
|
|
pbd->length = 0;
|
|
}
|
|
|
|
DevCon.WriteLn("DEV9: DEV9init ok");
|
|
|
|
return 0;
|
|
}
|
|
|
|
void DEV9shutdown()
|
|
{
|
|
DevCon.WriteLn("DEV9: DEV9shutdown");
|
|
delete dev9.ata;
|
|
}
|
|
|
|
s32 DEV9open(void* pDsp)
|
|
{
|
|
DevCon.WriteLn("DEV9: DEV9open");
|
|
LoadConf();
|
|
#ifdef _WIN32
|
|
//Convert to utf8
|
|
char mbHdd[sizeof(config.Hdd)] = {0};
|
|
WideCharToMultiByte(CP_UTF8, 0, config.Hdd, -1, mbHdd, sizeof(mbHdd) - 1, nullptr, nullptr);
|
|
DevCon.WriteLn("DEV9: open r+: %s", mbHdd);
|
|
#else
|
|
DevCon.WriteLn("DEV9: open r+: %s", config.Hdd);
|
|
#endif
|
|
|
|
#ifdef _WIN32
|
|
ghc::filesystem::path hddPath(std::wstring(config.Hdd));
|
|
#else
|
|
ghc::filesystem::path hddPath(config.Hdd);
|
|
#endif
|
|
|
|
if (hddPath.empty())
|
|
config.hddEnable = false;
|
|
|
|
if (hddPath.is_relative())
|
|
{
|
|
//GHC uses UTF8 on all platforms
|
|
ghc::filesystem::path path(GetSettingsFolder().ToUTF8().data());
|
|
hddPath = path / hddPath;
|
|
}
|
|
|
|
if (config.hddEnable)
|
|
{
|
|
if (dev9.ata->Open(hddPath) != 0)
|
|
config.hddEnable = false;
|
|
}
|
|
|
|
if (config.ethEnable)
|
|
InitNet();
|
|
|
|
isRunning = true;
|
|
return 0;
|
|
}
|
|
|
|
void DEV9close()
|
|
{
|
|
DevCon.WriteLn("DEV9: DEV9close");
|
|
|
|
dev9.ata->Close();
|
|
TermNet();
|
|
isRunning = false;
|
|
}
|
|
|
|
int DEV9irqHandler(void)
|
|
{
|
|
//dev9Ru16(SPD_R_INTR_STAT)|= dev9.irqcause;
|
|
DevCon.WriteLn("DEV9: DEV9irqHandler %x, %x", dev9.irqcause, dev9.irqmask);
|
|
if (dev9.irqcause & dev9.irqmask)
|
|
return 1;
|
|
return 0;
|
|
}
|
|
|
|
void _DEV9irq(int cause, int cycles)
|
|
{
|
|
DevCon.WriteLn("DEV9: _DEV9irq %x, %x", cause, dev9.irqmask);
|
|
|
|
dev9.irqcause |= cause;
|
|
|
|
if (cycles < 1)
|
|
dev9Irq(1);
|
|
else
|
|
dev9Irq(cycles);
|
|
}
|
|
|
|
//Fakes SPEED FIFO
|
|
void HDDWriteFIFO()
|
|
{
|
|
if (dev9.ata->dmaReady && (dev9.if_ctrl & SPD_IF_ATA_DMAEN))
|
|
{
|
|
const int unread = (dev9.fifo_bytes_write - dev9.fifo_bytes_read);
|
|
const int spaceSectors = (SPD_DBUF_AVAIL_MAX * 512 - unread) / 512;
|
|
if (spaceSectors < 0)
|
|
{
|
|
Console.Error("DEV9: No Space on SPEED FIFO");
|
|
pxAssert(false);
|
|
abort();
|
|
}
|
|
|
|
const int readSectors = dev9.ata->nsectorLeft < spaceSectors ? dev9.ata->nsectorLeft : spaceSectors;
|
|
dev9.fifo_bytes_write += readSectors * 512;
|
|
dev9.ata->nsectorLeft -= readSectors;
|
|
}
|
|
//FIFOIntr();
|
|
}
|
|
void HDDReadFIFO()
|
|
{
|
|
if (dev9.ata->dmaReady && (dev9.if_ctrl & SPD_IF_ATA_DMAEN))
|
|
{
|
|
const int writeSectors = (dev9.fifo_bytes_write - dev9.fifo_bytes_read) / 512;
|
|
dev9.fifo_bytes_read += writeSectors * 512;
|
|
dev9.ata->nsectorLeft -= writeSectors;
|
|
}
|
|
//FIFOIntr();
|
|
}
|
|
void IOPReadFIFO(int bytes)
|
|
{
|
|
dev9.fifo_bytes_read += bytes;
|
|
if (dev9.fifo_bytes_read > dev9.fifo_bytes_write)
|
|
Console.Error("DEV9: UNDERFLOW BY IOP");
|
|
//FIFOIntr();
|
|
}
|
|
void IOPWriteFIFO(int bytes)
|
|
{
|
|
dev9.fifo_bytes_write += bytes;
|
|
if (dev9.fifo_bytes_write - SPD_DBUF_AVAIL_MAX * 512 > dev9.fifo_bytes_read)
|
|
Console.Error("DEV9: OVERFLOW BY IOP");
|
|
//FIFOIntr();
|
|
}
|
|
void FIFOIntr()
|
|
{
|
|
//FIFO Buffer Full/Empty
|
|
const int unread = (dev9.fifo_bytes_write - dev9.fifo_bytes_read);
|
|
|
|
if (unread == 0)
|
|
{
|
|
if ((dev9.irqcause & SPD_INTR_ATA_FIFO_EMPTY) == 0)
|
|
_DEV9irq(SPD_INTR_ATA_FIFO_EMPTY, 1);
|
|
}
|
|
if (unread == SPD_DBUF_AVAIL_MAX * 512)
|
|
{
|
|
//Log_Error("FIFO Full");
|
|
//INTR Full?
|
|
}
|
|
}
|
|
|
|
u8 DEV9read8(u32 addr)
|
|
{
|
|
if (!config.ethEnable & !config.hddEnable)
|
|
return 0;
|
|
|
|
u8 hard;
|
|
if (addr >= ATA_DEV9_HDD_BASE && addr < ATA_DEV9_HDD_END)
|
|
{
|
|
Console.Error("DEV9: ATA does not support 8bit reads %lx", addr);
|
|
return 0;
|
|
}
|
|
if (addr >= SMAP_REGBASE && addr < FLASH_REGBASE)
|
|
{
|
|
//smap
|
|
return smap_read8(addr);
|
|
}
|
|
if ((addr >= FLASH_REGBASE) && (addr < (FLASH_REGBASE + FLASH_REGSIZE)))
|
|
{
|
|
return (u8)FLASHread32(addr, 1);
|
|
}
|
|
|
|
switch (addr)
|
|
{
|
|
case SPD_R_PIO_DATA:
|
|
|
|
/*if(dev9.eeprom_dir!=1)
|
|
{
|
|
hard=0;
|
|
break;
|
|
}*/
|
|
|
|
if (dev9.eeprom_state == EEPROM_TDATA)
|
|
{
|
|
if (dev9.eeprom_command == 2) //read
|
|
{
|
|
if (dev9.eeprom_bit == 0xFF)
|
|
hard = 0;
|
|
else
|
|
hard = ((dev9.eeprom[dev9.eeprom_address] << dev9.eeprom_bit) & 0x8000) >> 11;
|
|
dev9.eeprom_bit++;
|
|
if (dev9.eeprom_bit == 16)
|
|
{
|
|
dev9.eeprom_address++;
|
|
dev9.eeprom_bit = 0;
|
|
}
|
|
}
|
|
else
|
|
hard = 0;
|
|
}
|
|
else
|
|
hard = 0;
|
|
DevCon.WriteLn("DEV9: SPD_R_PIO_DATA 8bit read %x", hard);
|
|
return hard;
|
|
|
|
case DEV9_R_REV:
|
|
hard = 0x32; // expansion bay
|
|
DevCon.WriteLn("DEV9: DEV9_R_REV 8bit read %x", hard);
|
|
return hard;
|
|
|
|
default:
|
|
hard = dev9Ru8(addr);
|
|
Console.Error("DEV9: Unknown 8bit read at address %lx value %x", addr, hard);
|
|
return hard;
|
|
}
|
|
}
|
|
|
|
u16 DEV9read16(u32 addr)
|
|
{
|
|
if (!config.ethEnable & !config.hddEnable)
|
|
return 0;
|
|
|
|
u16 hard;
|
|
if (addr >= ATA_DEV9_HDD_BASE && addr < ATA_DEV9_HDD_END)
|
|
{
|
|
return dev9.ata->Read16(addr);
|
|
}
|
|
if (addr >= SMAP_REGBASE && addr < FLASH_REGBASE)
|
|
{
|
|
//smap
|
|
return smap_read16(addr);
|
|
}
|
|
if ((addr >= FLASH_REGBASE) && (addr < (FLASH_REGBASE + FLASH_REGSIZE)))
|
|
{
|
|
return (u16)FLASHread32(addr, 2);
|
|
}
|
|
|
|
switch (addr)
|
|
{
|
|
case SPD_R_INTR_STAT:
|
|
DevCon.WriteLn("DEV9: SPD_R_INTR_STAT 16bit read %x", dev9.irqcause);
|
|
return dev9.irqcause;
|
|
|
|
case SPD_R_INTR_MASK:
|
|
DevCon.WriteLn("DEV9: SPD_R_INTR_MASK 16bit read %x", dev9.irqmask);
|
|
return dev9.irqmask;
|
|
|
|
case SPD_R_PIO_DATA:
|
|
|
|
/*if(dev9.eeprom_dir!=1)
|
|
{
|
|
hard=0;
|
|
break;
|
|
}*/
|
|
|
|
if (dev9.eeprom_state == EEPROM_TDATA)
|
|
{
|
|
if (dev9.eeprom_command == 2) //read
|
|
{
|
|
if (dev9.eeprom_bit == 0xFF)
|
|
hard = 0;
|
|
else
|
|
hard = ((dev9.eeprom[dev9.eeprom_address] << dev9.eeprom_bit) & 0x8000) >> 11;
|
|
dev9.eeprom_bit++;
|
|
if (dev9.eeprom_bit == 16)
|
|
{
|
|
dev9.eeprom_address++;
|
|
dev9.eeprom_bit = 0;
|
|
}
|
|
}
|
|
else
|
|
hard = 0;
|
|
}
|
|
else
|
|
hard = 0;
|
|
DevCon.WriteLn("DEV9: SPD_R_PIO_DATA 16bit read %x", hard);
|
|
return hard;
|
|
|
|
case DEV9_R_REV:
|
|
//hard = 0x0030; // expansion bay
|
|
DevCon.WriteLn("DEV9: DEV9_R_REV 16bit read %x", dev9.irqmask);
|
|
hard = 0x0032;
|
|
return hard;
|
|
|
|
case SPD_R_REV_1:
|
|
DevCon.WriteLn("DEV9: SPD_R_REV_1 16bit read %x", 0);
|
|
return 0;
|
|
|
|
case SPD_R_REV_2:
|
|
hard = 0x0011;
|
|
DevCon.WriteLn("DEV9: STD_R_REV_1 16bit read %x", hard);
|
|
return hard;
|
|
|
|
case SPD_R_REV_3:
|
|
hard = 0;
|
|
if (config.hddEnable)
|
|
hard |= SPD_CAPS_ATA;
|
|
if (config.ethEnable)
|
|
hard |= SPD_CAPS_SMAP;
|
|
hard |= SPD_CAPS_FLASH;
|
|
DevCon.WriteLn("DEV9: SPD_R_REV_3 16bit read %x", hard);
|
|
return hard;
|
|
|
|
case SPD_R_0e:
|
|
hard = 0x0002; //Have HDD inserted
|
|
DevCon.WriteLn("DEV9: SPD_R_0e 16bit read %x", hard);
|
|
return hard;
|
|
case SPD_R_XFR_CTRL:
|
|
DevCon.WriteLn("DEV9: SPD_R_XFR_CTRL 16bit read %x", dev9.xfr_ctrl);
|
|
return dev9.xfr_ctrl;
|
|
case SPD_R_DBUF_STAT:
|
|
{
|
|
hard = 0;
|
|
if (dev9.if_ctrl & SPD_IF_READ) //Semi async
|
|
{
|
|
HDDWriteFIFO(); //Yes this is not a typo
|
|
}
|
|
else
|
|
{
|
|
HDDReadFIFO();
|
|
}
|
|
FIFOIntr();
|
|
|
|
const u8 count = (u8)((dev9.fifo_bytes_write - dev9.fifo_bytes_read) / 512);
|
|
if (dev9.xfr_ctrl & SPD_XFR_WRITE) //or ifRead?
|
|
{
|
|
hard = (u8)(SPD_DBUF_AVAIL_MAX - count);
|
|
hard |= (count == 0) ? SPD_DBUF_STAT_1 : (u16)0;
|
|
hard |= (count > 0) ? SPD_DBUF_STAT_2 : (u16)0;
|
|
}
|
|
else
|
|
{
|
|
hard = count;
|
|
hard |= (count < SPD_DBUF_AVAIL_MAX) ? SPD_DBUF_STAT_1 : (u16)0;
|
|
hard |= (count == 0) ? SPD_DBUF_STAT_2 : (u16)0;
|
|
//If overflow (HDD->SPEED), set both SPD_DBUF_STAT_2 & SPD_DBUF_STAT_FULL
|
|
//and overflow INTR set
|
|
}
|
|
|
|
if (count == SPD_DBUF_AVAIL_MAX)
|
|
{
|
|
hard |= SPD_DBUF_STAT_FULL;
|
|
}
|
|
|
|
DevCon.WriteLn("DEV9: SPD_R_DBUF_STAT 16bit read %x", hard);
|
|
return hard;
|
|
}
|
|
case SPD_R_IF_CTRL:
|
|
DevCon.WriteLn("DEV9: SPD_R_IF_CTRL 16bit read %x", dev9.if_ctrl);
|
|
return dev9.if_ctrl;
|
|
default:
|
|
hard = dev9Ru16(addr);
|
|
Console.Error("DEV9: Unknown 16bit read at address %lx value %x", addr, hard);
|
|
return hard;
|
|
}
|
|
}
|
|
|
|
u32 DEV9read32(u32 addr)
|
|
{
|
|
if (!config.ethEnable & !config.hddEnable)
|
|
return 0;
|
|
|
|
u32 hard;
|
|
if (addr >= ATA_DEV9_HDD_BASE && addr < ATA_DEV9_HDD_END)
|
|
{
|
|
Console.Error("DEV9: ATA does not support 32bit reads %lx", addr);
|
|
return 0;
|
|
}
|
|
if (addr >= SMAP_REGBASE && addr < FLASH_REGBASE)
|
|
{
|
|
//smap
|
|
return smap_read32(addr);
|
|
}
|
|
if ((addr >= FLASH_REGBASE) && (addr < (FLASH_REGBASE + FLASH_REGSIZE)))
|
|
{
|
|
return (u32)FLASHread32(addr, 4);
|
|
}
|
|
|
|
hard = dev9Ru32(addr);
|
|
Console.Error("DEV9: Unknown 32bit read at address %lx value %x", addr, hard);
|
|
return hard;
|
|
}
|
|
|
|
void DEV9write8(u32 addr, u8 value)
|
|
{
|
|
if (!config.ethEnable & !config.hddEnable)
|
|
return;
|
|
|
|
if (addr >= ATA_DEV9_HDD_BASE && addr < ATA_DEV9_HDD_END)
|
|
{
|
|
#ifdef ENABLE_ATA
|
|
ata_write<1>(addr, value);
|
|
#endif
|
|
return;
|
|
}
|
|
if (addr >= SMAP_REGBASE && addr < FLASH_REGBASE)
|
|
{
|
|
//smap
|
|
smap_write8(addr, value);
|
|
return;
|
|
}
|
|
if ((addr >= FLASH_REGBASE) && (addr < (FLASH_REGBASE + FLASH_REGSIZE)))
|
|
{
|
|
FLASHwrite32(addr, (u32)value, 1);
|
|
return;
|
|
}
|
|
|
|
switch (addr)
|
|
{
|
|
case 0x10000020:
|
|
Console.Error("DEV9: SPD_R_INTR_CAUSE, WTFH ?");
|
|
dev9.irqcause = 0xff;
|
|
break;
|
|
case SPD_R_INTR_STAT:
|
|
Console.Error("DEV9: SPD_R_INTR_STAT, WTFH ?");
|
|
dev9.irqcause = value;
|
|
return;
|
|
case SPD_R_INTR_MASK:
|
|
Console.Error("DEV9: SPD_R_INTR_MASK8, WTFH ?");
|
|
break;
|
|
|
|
case SPD_R_PIO_DIR:
|
|
DevCon.WriteLn("DEV9: SPD_R_PIO_DIR 8bit write %x", value);
|
|
|
|
if ((value & 0xc0) != 0xc0)
|
|
return;
|
|
|
|
if ((value & 0x30) == 0x20)
|
|
{
|
|
dev9.eeprom_state = 0;
|
|
}
|
|
dev9.eeprom_dir = (value >> 4) & 3;
|
|
|
|
return;
|
|
|
|
case SPD_R_PIO_DATA:
|
|
DevCon.WriteLn("DEV9: SPD_R_PIO_DATA 8bit write %x", value);
|
|
|
|
if ((value & 0xc0) != 0xc0)
|
|
return;
|
|
|
|
switch (dev9.eeprom_state)
|
|
{
|
|
case EEPROM_READY:
|
|
dev9.eeprom_command = 0;
|
|
dev9.eeprom_state++;
|
|
break;
|
|
case EEPROM_OPCD0:
|
|
dev9.eeprom_command = (value >> 4) & 2;
|
|
dev9.eeprom_state++;
|
|
dev9.eeprom_bit = 0xFF;
|
|
break;
|
|
case EEPROM_OPCD1:
|
|
dev9.eeprom_command |= (value >> 5) & 1;
|
|
dev9.eeprom_state++;
|
|
break;
|
|
case EEPROM_ADDR0:
|
|
case EEPROM_ADDR1:
|
|
case EEPROM_ADDR2:
|
|
case EEPROM_ADDR3:
|
|
case EEPROM_ADDR4:
|
|
case EEPROM_ADDR5:
|
|
dev9.eeprom_address =
|
|
(dev9.eeprom_address & (63 ^ (1 << (dev9.eeprom_state - EEPROM_ADDR0)))) |
|
|
((value >> (dev9.eeprom_state - EEPROM_ADDR0)) & (0x20 >> (dev9.eeprom_state - EEPROM_ADDR0)));
|
|
dev9.eeprom_state++;
|
|
break;
|
|
case EEPROM_TDATA:
|
|
{
|
|
if (dev9.eeprom_command == 1) //write
|
|
{
|
|
dev9.eeprom[dev9.eeprom_address] =
|
|
(dev9.eeprom[dev9.eeprom_address] & (63 ^ (1 << dev9.eeprom_bit))) |
|
|
((value >> dev9.eeprom_bit) & (0x8000 >> dev9.eeprom_bit));
|
|
dev9.eeprom_bit++;
|
|
if (dev9.eeprom_bit == 16)
|
|
{
|
|
dev9.eeprom_address++;
|
|
dev9.eeprom_bit = 0;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
Console.Error("DEV9: Unknown EEPROM COMMAND");
|
|
break;
|
|
}
|
|
return;
|
|
default:
|
|
dev9Ru8(addr) = value;
|
|
Console.Error("DEV9: Unknown 8bit write at address %lx value %x", addr, value);
|
|
return;
|
|
}
|
|
}
|
|
|
|
void DEV9write16(u32 addr, u16 value)
|
|
{
|
|
if (!config.ethEnable & !config.hddEnable)
|
|
return;
|
|
|
|
if (addr >= ATA_DEV9_HDD_BASE && addr < ATA_DEV9_HDD_END)
|
|
{
|
|
dev9.ata->Write16(addr, value);
|
|
return;
|
|
}
|
|
if (addr >= SMAP_REGBASE && addr < FLASH_REGBASE)
|
|
{
|
|
//smap
|
|
smap_write16(addr, value);
|
|
return;
|
|
}
|
|
if ((addr >= FLASH_REGBASE) && (addr < (FLASH_REGBASE + FLASH_REGSIZE)))
|
|
{
|
|
FLASHwrite32(addr, (u32)value, 2);
|
|
return;
|
|
}
|
|
|
|
switch (addr)
|
|
{
|
|
case SPD_R_INTR_MASK:
|
|
DevCon.WriteLn("DEV9: SPD_R_INTR_MASK 16bit write %x , checking for masked/unmasked interrupts", value);
|
|
if ((dev9.irqmask != value) && ((dev9.irqmask | value) & dev9.irqcause))
|
|
{
|
|
DevCon.WriteLn("DEV9: SPD_R_INTR_MASK16 firing unmasked interrupts");
|
|
dev9Irq(1);
|
|
}
|
|
dev9.irqmask = value;
|
|
break;
|
|
|
|
case SPD_R_PIO_DIR:
|
|
DevCon.WriteLn("DEV9: SPD_R_PIO_DIR 16bit write %x", value);
|
|
|
|
if ((value & 0xc0) != 0xc0)
|
|
return;
|
|
|
|
if ((value & 0x30) == 0x20)
|
|
{
|
|
dev9.eeprom_state = 0;
|
|
}
|
|
dev9.eeprom_dir = (value >> 4) & 3;
|
|
|
|
return;
|
|
|
|
case SPD_R_PIO_DATA:
|
|
DevCon.WriteLn("DEV9: SPD_R_PIO_DATA 16bit write %x", value);
|
|
|
|
if ((value & 0xc0) != 0xc0)
|
|
return;
|
|
|
|
switch (dev9.eeprom_state)
|
|
{
|
|
case EEPROM_READY:
|
|
dev9.eeprom_command = 0;
|
|
dev9.eeprom_state++;
|
|
break;
|
|
case EEPROM_OPCD0:
|
|
dev9.eeprom_command = (value >> 4) & 2;
|
|
dev9.eeprom_state++;
|
|
dev9.eeprom_bit = 0xFF;
|
|
break;
|
|
case EEPROM_OPCD1:
|
|
dev9.eeprom_command |= (value >> 5) & 1;
|
|
dev9.eeprom_state++;
|
|
break;
|
|
case EEPROM_ADDR0:
|
|
case EEPROM_ADDR1:
|
|
case EEPROM_ADDR2:
|
|
case EEPROM_ADDR3:
|
|
case EEPROM_ADDR4:
|
|
case EEPROM_ADDR5:
|
|
dev9.eeprom_address =
|
|
(dev9.eeprom_address & (63 ^ (1 << (dev9.eeprom_state - EEPROM_ADDR0)))) |
|
|
((value >> (dev9.eeprom_state - EEPROM_ADDR0)) & (0x20 >> (dev9.eeprom_state - EEPROM_ADDR0)));
|
|
dev9.eeprom_state++;
|
|
break;
|
|
case EEPROM_TDATA:
|
|
{
|
|
if (dev9.eeprom_command == 1) //write
|
|
{
|
|
dev9.eeprom[dev9.eeprom_address] =
|
|
(dev9.eeprom[dev9.eeprom_address] & (63 ^ (1 << dev9.eeprom_bit))) |
|
|
((value >> dev9.eeprom_bit) & (0x8000 >> dev9.eeprom_bit));
|
|
dev9.eeprom_bit++;
|
|
if (dev9.eeprom_bit == 16)
|
|
{
|
|
dev9.eeprom_address++;
|
|
dev9.eeprom_bit = 0;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
Console.Error("DEV9: Unknown EEPROM COMMAND");
|
|
break;
|
|
}
|
|
return;
|
|
|
|
case SPD_R_DMA_CTRL:
|
|
DevCon.WriteLn("DEV9: SPD_R_IF_CTRL 16bit write %x", value);
|
|
dev9.dma_ctrl = value;
|
|
|
|
if (value & SPD_DMA_TO_SMAP)
|
|
DevCon.WriteLn("DEV9: SPD_R_DMA_CTRL DMA For SMAP");
|
|
else
|
|
DevCon.WriteLn("DEV9: SPD_R_DMA_CTRL DMA For ATA");
|
|
|
|
if ((value & SPD_DMA_FASTEST) != 0)
|
|
DevCon.WriteLn("DEV9: SPD_R_DMA_CTRL Fastest DMA Mode");
|
|
else
|
|
DevCon.WriteLn("DEV9: SPD_R_DMA_CTRL Slower DMA Mode");
|
|
|
|
if ((value & SPD_DMA_WIDE) != 0)
|
|
DevCon.WriteLn("DEV9: SPD_R_DMA_CTRL Wide(32bit) DMA Mode Set");
|
|
else
|
|
DevCon.WriteLn("DEV9: SPD_R_DMA_CTRL 16bit DMA Mode");
|
|
|
|
if ((value & SPD_DMA_PAUSE) != 0)
|
|
Console.Error("DEV9: SPD_R_DMA_CTRL Pause DMA Not Implemented");
|
|
|
|
if ((value & 0b1111111111101000) != 0)
|
|
Console.Error("DEV9: SPD_R_DMA_CTRL Unknown value written %x", value);
|
|
|
|
break;
|
|
case SPD_R_XFR_CTRL:
|
|
DevCon.WriteLn("DEV9: SPD_R_IF_CTRL 16bit write %x", value);
|
|
dev9.xfr_ctrl = value;
|
|
|
|
if (value & SPD_XFR_WRITE)
|
|
DevCon.WriteLn("DEV9: SPD_R_XFR_CTRL Set Write");
|
|
else
|
|
DevCon.WriteLn("DEV9: SPD_R_XFR_CTRL Set Read");
|
|
|
|
if ((value & (1 << 1)) != 0)
|
|
DevCon.WriteLn("DEV9: SPD_R_XFR_CTRL Unknown Bit 1");
|
|
|
|
if ((value & (1 << 2)) != 0)
|
|
DevCon.WriteLn("DEV9: SPD_R_XFR_CTRL Unknown Bit 2");
|
|
|
|
if (value & SPD_XFR_DMAEN)
|
|
DevCon.WriteLn("DEV9: SPD_R_XFR_CTRL For DMA Enabled");
|
|
else
|
|
DevCon.WriteLn("DEV9: SPD_R_XFR_CTRL For DMA Disabled");
|
|
|
|
if ((value & 0b1111111101111000) != 0)
|
|
{
|
|
Console.Error("DEV9: SPD_R_XFR_CTRL Unknown value written %x", value);
|
|
}
|
|
|
|
break;
|
|
case SPD_R_DBUF_STAT:
|
|
DevCon.WriteLn("DEV9: SPD_R_DBUF_STAT 16bit write %x", value);
|
|
|
|
if ((value & SPD_DBUF_RESET_FIFO) != 0)
|
|
{
|
|
DevCon.WriteLn("DEV9: SPD_R_XFR_CTRL Reset FIFO");
|
|
dev9.fifo_bytes_write = 0;
|
|
dev9.fifo_bytes_read = 0;
|
|
dev9.xfr_ctrl &= ~SPD_XFR_WRITE; //?
|
|
dev9.if_ctrl |= SPD_IF_READ; //?
|
|
|
|
FIFOIntr();
|
|
}
|
|
|
|
if (value != 3)
|
|
Console.Error("DEV9: SPD_R_38 16bit write %x Which != 3!!!", value);
|
|
break;
|
|
|
|
case SPD_R_IF_CTRL:
|
|
DevCon.WriteLn("DEV9: SPD_R_IF_CTRL 16bit write %x", value);
|
|
dev9.if_ctrl = value;
|
|
|
|
if (value & SPD_IF_UDMA)
|
|
DevCon.WriteLn("DEV9: IF_CTRL UDMA Enabled");
|
|
else
|
|
DevCon.WriteLn("DEV9: IF_CTRL UDMA Disabled");
|
|
if (value & SPD_IF_READ)
|
|
DevCon.WriteLn("DEV9: IF_CTRL DMA Is ATA Read");
|
|
else
|
|
DevCon.WriteLn("DEV9: IF_CTRL DMA Is ATA Write");
|
|
|
|
if (value & SPD_IF_ATA_DMAEN)
|
|
{
|
|
DevCon.WriteLn("DEV9: IF_CTRL ATA DMA Enabled");
|
|
if (value & SPD_IF_READ) //Semi async
|
|
{
|
|
HDDWriteFIFO(); //Yes this is not a typo
|
|
}
|
|
else
|
|
{
|
|
HDDReadFIFO();
|
|
}
|
|
FIFOIntr();
|
|
}
|
|
else
|
|
DevCon.WriteLn("DEV9: IF_CTRL ATA DMA Disabled");
|
|
|
|
if (value & (1 << 3))
|
|
DevCon.WriteLn("DEV9: IF_CTRL Unknown Bit 3 Set");
|
|
|
|
if (value & (1 << 4))
|
|
Console.Error("DEV9: IF_CTRL Unknown Bit 4 Set");
|
|
if (value & (1 << 5))
|
|
Console.Error("DEV9: IF_CTRL Unknown Bit 5 Set");
|
|
|
|
if ((value & SPD_IF_HDD_RESET) == 0) //Maybe?
|
|
{
|
|
DevCon.WriteLn("DEV9: IF_CTRL HDD Hard Reset");
|
|
dev9.ata->ATA_HardReset();
|
|
}
|
|
if ((value & SPD_IF_ATA_RESET) != 0)
|
|
{
|
|
DevCon.WriteLn("DEV9: IF_CTRL ATA Reset");
|
|
//0x62 0x0020
|
|
dev9.if_ctrl = 0x001A;
|
|
//0x66 0x0001
|
|
dev9.pio_mode = 0x24;
|
|
dev9.mdma_mode = 0x45;
|
|
dev9.udma_mode = 0x83;
|
|
//0x76 0x4ABA (And consequently 0x78 = 0x4ABA.)
|
|
}
|
|
|
|
if ((value & 0xFF00) > 0)
|
|
Console.Error("DEV9: IF_CTRL Unknown Bit(s) %x", (value & 0xFF00));
|
|
|
|
break;
|
|
case SPD_R_PIO_MODE: //ATA only? or includes EEPROM?
|
|
DevCon.WriteLn("DEV9: SPD_R_PIO_MODE 16bit write %x", value);
|
|
dev9.pio_mode = value;
|
|
|
|
switch (value)
|
|
{
|
|
case 0x92:
|
|
DevCon.WriteLn("DEV9: SPD_R_PIO_MODE 0");
|
|
break;
|
|
case 0x72:
|
|
DevCon.WriteLn("DEV9: SPD_R_PIO_MODE 1");
|
|
break;
|
|
case 0x32:
|
|
DevCon.WriteLn("DEV9: SPD_R_PIO_MODE 2");
|
|
break;
|
|
case 0x24:
|
|
DevCon.WriteLn("DEV9: SPD_R_PIO_MODE 3");
|
|
break;
|
|
case 0x23:
|
|
DevCon.WriteLn("DEV9: SPD_R_PIO_MODE 4");
|
|
break;
|
|
|
|
default:
|
|
Console.Error("DEV9: SPD_R_PIO_MODE UNKNOWN MODE %x", value);
|
|
break;
|
|
}
|
|
break;
|
|
case SPD_R_MDMA_MODE: //ATA only? or includes EEPROM?
|
|
DevCon.WriteLn("DEV9: SPD_R_MDMA_MODE 16bit write %x", value);
|
|
dev9.mdma_mode = value;
|
|
|
|
switch (value)
|
|
{
|
|
case 0xFF:
|
|
DevCon.WriteLn("DEV9: SPD_R_MDMA_MODE 0");
|
|
break;
|
|
case 0x45:
|
|
DevCon.WriteLn("DEV9: SPD_R_MDMA_MODE 1");
|
|
break;
|
|
case 0x24:
|
|
DevCon.WriteLn("DEV9: SPD_R_MDMA_MODE 2");
|
|
break;
|
|
default:
|
|
Console.Error("DEV9: SPD_R_MDMA_MODE UNKNOWN MODE %x", value);
|
|
break;
|
|
}
|
|
|
|
break;
|
|
case SPD_R_UDMA_MODE: //ATA only?
|
|
DevCon.WriteLn("DEV9: SPD_R_UDMA_MODE 16bit write %x", value);
|
|
dev9.udma_mode = value;
|
|
|
|
switch (value)
|
|
{
|
|
case 0xa7:
|
|
DevCon.WriteLn("DEV9: SPD_R_UDMA_MODE 0");
|
|
break;
|
|
case 0x85:
|
|
DevCon.WriteLn("DEV9: SPD_R_UDMA_MODE 1");
|
|
break;
|
|
case 0x63:
|
|
DevCon.WriteLn("DEV9: SPD_R_UDMA_MODE 2");
|
|
break;
|
|
case 0x62:
|
|
DevCon.WriteLn("DEV9: SPD_R_UDMA_MODE 3");
|
|
break;
|
|
case 0x61:
|
|
DevCon.WriteLn("DEV9: SPD_R_UDMA_MODE 4");
|
|
break;
|
|
default:
|
|
Console.Error("DEV9: SPD_R_UDMA_MODE UNKNOWN MODE %x", value);
|
|
break;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
dev9Ru16(addr) = value;
|
|
Console.Error("DEV9: *Unknown 16bit write at address %lx value %x", addr, value);
|
|
return;
|
|
}
|
|
}
|
|
|
|
void DEV9write32(u32 addr, u32 value)
|
|
{
|
|
if (!config.ethEnable & !config.hddEnable)
|
|
return;
|
|
|
|
if (addr >= ATA_DEV9_HDD_BASE && addr < ATA_DEV9_HDD_END)
|
|
{
|
|
#ifdef ENABLE_ATA
|
|
ata_write<4>(addr, value);
|
|
#endif
|
|
return;
|
|
}
|
|
if (addr >= SMAP_REGBASE && addr < FLASH_REGBASE)
|
|
{
|
|
//smap
|
|
smap_write32(addr, value);
|
|
return;
|
|
}
|
|
if ((addr >= FLASH_REGBASE) && (addr < (FLASH_REGBASE + FLASH_REGSIZE)))
|
|
{
|
|
FLASHwrite32(addr, (u32)value, 4);
|
|
return;
|
|
}
|
|
|
|
switch (addr)
|
|
{
|
|
case SPD_R_INTR_MASK:
|
|
Console.Error("DEV9: SPD_R_INTR_MASK, WTFH ?");
|
|
break;
|
|
default:
|
|
dev9Ru32(addr) = value;
|
|
Console.Error("DEV9: Unknown 32bit write at address %lx write %x", addr, value);
|
|
return;
|
|
}
|
|
}
|
|
|
|
void DEV9readDMA8Mem(u32* pMem, int size)
|
|
{
|
|
if (!config.ethEnable & !config.hddEnable)
|
|
return;
|
|
|
|
size >>= 1;
|
|
|
|
DevCon.WriteLn("DEV9: *DEV9readDMA8Mem: size %x", size);
|
|
|
|
if (dev9.dma_ctrl & SPD_DMA_TO_SMAP)
|
|
smap_readDMA8Mem(pMem, size);
|
|
else
|
|
{
|
|
if (dev9.xfr_ctrl & SPD_XFR_DMAEN &&
|
|
!(dev9.xfr_ctrl & SPD_XFR_WRITE))
|
|
{
|
|
HDDWriteFIFO();
|
|
IOPReadFIFO(size);
|
|
dev9.ata->ATAreadDMA8Mem((u8*)pMem, size);
|
|
FIFOIntr();
|
|
}
|
|
}
|
|
|
|
//TODO, track if read was successful
|
|
}
|
|
|
|
void DEV9writeDMA8Mem(u32* pMem, int size)
|
|
{
|
|
if (!config.ethEnable & !config.hddEnable)
|
|
return;
|
|
|
|
size >>= 1;
|
|
|
|
DevCon.WriteLn("DEV9: *DEV9writeDMA8Mem: size %x", size);
|
|
|
|
if (dev9.dma_ctrl & SPD_DMA_TO_SMAP)
|
|
smap_writeDMA8Mem(pMem, size);
|
|
else
|
|
{
|
|
if (dev9.xfr_ctrl & SPD_XFR_DMAEN &&
|
|
dev9.xfr_ctrl & SPD_XFR_WRITE)
|
|
{
|
|
IOPWriteFIFO(size);
|
|
HDDReadFIFO();
|
|
dev9.ata->ATAwriteDMA8Mem((u8*)pMem, size);
|
|
FIFOIntr();
|
|
}
|
|
}
|
|
|
|
//TODO, track if write was successful
|
|
}
|
|
|
|
void DEV9async(u32 cycles)
|
|
{
|
|
smap_async(cycles);
|
|
dev9.ata->Async(cycles);
|
|
}
|
|
|
|
// extended funcs
|
|
|
|
void DEV9setSettingsDir(const char* dir)
|
|
{
|
|
// Grab the ini directory.
|
|
// TODO: Use
|
|
s_strIniPath = (dir == NULL) ? "inis" : dir;
|
|
}
|
|
|
|
void DEV9setLogDir(const char* dir)
|
|
{
|
|
// Get the path to the log directory.
|
|
s_strLogPath = (dir == NULL) ? "logs" : dir;
|
|
}
|
|
|
|
void ApplyConfigIfRunning(Config oldConfig)
|
|
{
|
|
if (!isRunning)
|
|
return;
|
|
|
|
//Eth
|
|
if (config.ethEnable)
|
|
{
|
|
if (oldConfig.ethEnable)
|
|
{
|
|
//Reload Net if adapter changed
|
|
if (strcmp(oldConfig.Eth, config.Eth) != 0 ||
|
|
oldConfig.EthApi != config.EthApi)
|
|
{
|
|
TermNet();
|
|
InitNet();
|
|
}
|
|
}
|
|
else
|
|
InitNet();
|
|
}
|
|
else if (oldConfig.ethEnable)
|
|
TermNet();
|
|
|
|
//Hdd
|
|
//Hdd Validate Path
|
|
#ifdef _WIN32
|
|
ghc::filesystem::path hddPath(std::wstring(config.Hdd));
|
|
#else
|
|
ghc::filesystem::path hddPath(config.Hdd);
|
|
#endif
|
|
|
|
if (hddPath.empty())
|
|
config.hddEnable = false;
|
|
|
|
if (hddPath.is_relative())
|
|
{
|
|
//GHC uses UTF8 on all platforms
|
|
ghc::filesystem::path path(GetSettingsFolder().ToUTF8().data());
|
|
hddPath = path / hddPath;
|
|
}
|
|
|
|
//Hdd Compare with old config
|
|
if (config.hddEnable)
|
|
{
|
|
if (oldConfig.hddEnable)
|
|
{
|
|
//ATA::Open/Close dosn't set any regs
|
|
//So we can close/open to apply settings
|
|
#ifdef _WIN32
|
|
if (wcscmp(config.Hdd, oldConfig.Hdd))
|
|
#else
|
|
if (strcmp(config.Hdd, oldConfig.Hdd))
|
|
#endif
|
|
{
|
|
dev9.ata->Close();
|
|
if (dev9.ata->Open(hddPath) != 0)
|
|
config.hddEnable = false;
|
|
}
|
|
|
|
if (config.HddSize != oldConfig.HddSize)
|
|
{
|
|
dev9.ata->Close();
|
|
if (dev9.ata->Open(hddPath) != 0)
|
|
config.hddEnable = false;
|
|
}
|
|
}
|
|
}
|
|
else if (oldConfig.hddEnable)
|
|
dev9.ata->Close();
|
|
}
|