gdrom: reduce dma buffer size. reios: schedule dma reads by chunks
Reduce gdrom dma buffer size to 16 sectors from 32. Limit serialization of dma and pio buffers to actual content. reios: schedule transfer of dma data in chunks. Fixes Soul Calibuf audio drop outs at boot with HLE BIOS (RA). Issue #1755
This commit is contained in:
parent
a085fd2f6d
commit
c860807fef
|
@ -25,9 +25,9 @@ int sns_key;
|
|||
static u32 set_mode_offset;
|
||||
static read_params_t read_params;
|
||||
static packet_cmd_t packet_cmd;
|
||||
static read_buff_t read_buff;
|
||||
static pio_buff_t pio_buff;
|
||||
static ata_cmd_t ata_cmd;
|
||||
static DmaBuffer dma_buff;
|
||||
static PioBuffer pio_buff;
|
||||
static u8 ata_command;
|
||||
cdda_t cdda;
|
||||
|
||||
static gd_states gd_state;
|
||||
|
@ -35,7 +35,7 @@ static DiscType gd_disk_type;
|
|||
/*
|
||||
GD rom reset -> GDS_WAITCMD
|
||||
|
||||
GDS_WAITCMD -> ATA/SPI command [Command code is on ata_cmd]
|
||||
GDS_WAITCMD -> ATA/SPI command [Command code is on ata_command]
|
||||
SPI Command -> GDS_WAITPACKET -> GDS_SPI_* , depending on input
|
||||
|
||||
GDS_SPI_READSECTOR -> Depending on features , it can do quite a few things
|
||||
|
@ -98,21 +98,69 @@ static void gd_spi_pio_end(const u8* buffer, u32 len, gd_states next_state = gds
|
|||
static void gd_process_spi_cmd();
|
||||
static void gd_process_ata_cmd();
|
||||
|
||||
static void FillReadBuffer()
|
||||
void DmaBuffer::fill(read_params_t& params)
|
||||
{
|
||||
read_buff.cache_index=0;
|
||||
u32 count = read_params.remaining_sectors;
|
||||
if (!isEmpty())
|
||||
return;
|
||||
index = 0;
|
||||
verify(params.remaining_sectors > 0);
|
||||
u32 count = std::min(params.remaining_sectors, NSECT);
|
||||
size = count * params.sector_type;
|
||||
|
||||
if (count > 32)
|
||||
count = 32;
|
||||
|
||||
read_buff.cache_size=count*read_params.sector_type;
|
||||
|
||||
libGDR_ReadSector(read_buff.cache,read_params.start_sector,count,read_params.sector_type);
|
||||
read_params.start_sector+=count;
|
||||
read_params.remaining_sectors-=count;
|
||||
libGDR_ReadSector(cache, params.start_sector, count, params.sector_type);
|
||||
params.start_sector += count;
|
||||
params.remaining_sectors -= count;
|
||||
}
|
||||
|
||||
const u8 *DmaBuffer::read(u32 len)
|
||||
{
|
||||
verify(len <= size);
|
||||
const u8 *p = &cache[index];
|
||||
index += len;
|
||||
size -= len;
|
||||
return p;
|
||||
}
|
||||
|
||||
void DmaBuffer::serialize(Serializer& ser) const
|
||||
{
|
||||
ser << size;
|
||||
ser.serialize(&cache[index], size);
|
||||
}
|
||||
|
||||
void DmaBuffer::deserialize(Deserializer& deser)
|
||||
{
|
||||
if (deser.version() < Deserializer::V54)
|
||||
{
|
||||
deser >> index;
|
||||
deser >> size;
|
||||
deser >> cache;
|
||||
}
|
||||
else
|
||||
{
|
||||
index = 0;
|
||||
deser >> size;
|
||||
deser.deserialize(&cache[0], size);
|
||||
}
|
||||
}
|
||||
|
||||
void PioBuffer::serialize(Serializer& ser) const
|
||||
{
|
||||
ser << next_state;
|
||||
ser << index;
|
||||
ser << size;
|
||||
ser.serialize(&_data[0], size);
|
||||
}
|
||||
|
||||
void PioBuffer::deserialize(Deserializer& deser)
|
||||
{
|
||||
deser >> next_state;
|
||||
deser >> index;
|
||||
deser >> size;
|
||||
if (deser.version() < Deserializer::V54)
|
||||
deser >> _data;
|
||||
else
|
||||
deser.deserialize(&_data[0], size);
|
||||
}
|
||||
|
||||
static void gd_set_state(gd_states state)
|
||||
{
|
||||
|
@ -163,7 +211,7 @@ static void gd_set_state(gd_states state)
|
|||
case gds_pio_send_data:
|
||||
// When preparations are complete, the following steps are carried out at the device.
|
||||
//(1) Number of bytes to be read is set in "Byte Count" register.
|
||||
ByteCount.full =(u16)(pio_buff.size<<1);
|
||||
ByteCount.full = (u16)pio_buff.getSize();
|
||||
//(2) IO bit is set and CoD bit is cleared.
|
||||
IntReason.IO=1;
|
||||
IntReason.CoD=0;
|
||||
|
@ -189,22 +237,24 @@ static void gd_set_state(gd_states state)
|
|||
u32 sector_count = read_params.remaining_sectors;
|
||||
gd_states next_state=gds_pio_end;
|
||||
|
||||
if (sector_count > 27)
|
||||
{
|
||||
sector_count = 27;
|
||||
const u32 maxSectors = (PioBuffer::Capacity - 1) / read_params.sector_type;
|
||||
if (sector_count > maxSectors) {
|
||||
sector_count = maxSectors;
|
||||
next_state = gds_readsector_pio;
|
||||
}
|
||||
|
||||
libGDR_ReadSector((u8*)&pio_buff.data[0],read_params.start_sector,sector_count, read_params.sector_type);
|
||||
read_params.start_sector+=sector_count;
|
||||
read_params.remaining_sectors-=sector_count;
|
||||
u16 *buffer = pio_buff.fill(sector_count * read_params.sector_type);
|
||||
libGDR_ReadSector((u8*)buffer, read_params.start_sector, sector_count, read_params.sector_type);
|
||||
read_params.start_sector += sector_count;
|
||||
read_params.remaining_sectors -= sector_count;
|
||||
|
||||
gd_spi_pio_end(0,sector_count*read_params.sector_type,next_state);
|
||||
gd_spi_pio_end(nullptr, 0, next_state);
|
||||
}
|
||||
break;
|
||||
|
||||
case gds_readsector_dma:
|
||||
FillReadBuffer();
|
||||
dma_buff.clear();
|
||||
dma_buff.fill(read_params);
|
||||
break;
|
||||
|
||||
case gds_pio_end:
|
||||
|
@ -236,7 +286,7 @@ static void gd_set_state(gd_states state)
|
|||
break;
|
||||
|
||||
case gds_process_set_mode:
|
||||
memcpy((u8 *)&GD_HardwareInfo + set_mode_offset, pio_buff.data, pio_buff.size << 1);
|
||||
memcpy((u8 *)&GD_HardwareInfo + set_mode_offset, pio_buff.data(), pio_buff.getSize());
|
||||
//end pio transfer ;)
|
||||
gd_set_state(gds_pio_end);
|
||||
break;
|
||||
|
@ -304,36 +354,32 @@ static void gd_disc_change()
|
|||
read_params = { 0 };
|
||||
set_mode_offset = 0;
|
||||
packet_cmd = { 0 };
|
||||
memset(&read_buff, 0, sizeof(read_buff));
|
||||
pio_buff = { gds_waitcmd, 0 };
|
||||
ata_cmd = { 0 };
|
||||
dma_buff.clear();
|
||||
pio_buff.clear();
|
||||
ata_command = 0;
|
||||
cdda = { cdda_t::NoInfo, 0 };
|
||||
}
|
||||
|
||||
//This handles the work of setting up the pio regs/state :)
|
||||
static void gd_spi_pio_end(const u8* buffer, u32 len, gd_states next_state)
|
||||
{
|
||||
verify(len<0xFFFF);
|
||||
pio_buff.index=0;
|
||||
pio_buff.size=len>>1;
|
||||
pio_buff.next_state=next_state;
|
||||
|
||||
if (buffer!=0)
|
||||
memcpy(pio_buff.data,buffer,len);
|
||||
|
||||
if (len==0)
|
||||
if (buffer != nullptr) {
|
||||
verify(len < 0xFFFF); // TODO shouldn't this be <= 0xFFFF ?
|
||||
memcpy(pio_buff.fill(len), buffer, len);
|
||||
}
|
||||
pio_buff.next_state = next_state;
|
||||
if (pio_buff.isEmpty())
|
||||
gd_set_state(next_state);
|
||||
else
|
||||
gd_set_state(gds_pio_send_data);
|
||||
}
|
||||
static void gd_spi_pio_read_end(u32 len, gd_states next_state)
|
||||
{
|
||||
verify(len<0xFFFF);
|
||||
pio_buff.index=0;
|
||||
pio_buff.size=len>>1;
|
||||
pio_buff.next_state=next_state;
|
||||
verify(len < 0xFFFF); // TODO see above
|
||||
pio_buff.resetSize(len);
|
||||
pio_buff.next_state = next_state;
|
||||
|
||||
if (len==0)
|
||||
if (len == 0)
|
||||
gd_set_state(next_state);
|
||||
else
|
||||
gd_set_state(gds_pio_get_data);
|
||||
|
@ -350,7 +396,7 @@ static void gd_process_ata_cmd()
|
|||
else
|
||||
GDStatus.CHECK=1;
|
||||
|
||||
switch(ata_cmd.command)
|
||||
switch (ata_command)
|
||||
{
|
||||
case ATA_NOP:
|
||||
printf_ata("ATA_NOP");
|
||||
|
@ -447,7 +493,7 @@ static void gd_process_ata_cmd()
|
|||
break;
|
||||
|
||||
default:
|
||||
WARN_LOG(GDROM, "Unknown ATA command %x", ata_cmd.command);
|
||||
WARN_LOG(GDROM, "Unknown ATA command %x", ata_command);
|
||||
Error.ABRT = 1;
|
||||
Error.Sense = 5; // illegal request
|
||||
GDStatus.BSY = 0;
|
||||
|
@ -706,12 +752,12 @@ static void gd_process_spi_cmd()
|
|||
read_params.sector_type = sector_type;//yeah i know , not really many types supported...
|
||||
|
||||
printf_spicmd("SPI_CD_READ - Sector=%d Size=%d/%d DMA=%d",read_params.start_sector,read_params.remaining_sectors,read_params.sector_type,Features.CDRead.DMA);
|
||||
if (Features.CDRead.DMA == 1)
|
||||
{
|
||||
if (Features.CDRead.DMA == 1) {
|
||||
pio_buff.clear();
|
||||
gd_set_state(gds_readsector_dma);
|
||||
}
|
||||
else
|
||||
{
|
||||
else {
|
||||
dma_buff.clear();
|
||||
gd_set_state(gds_readsector_pio);
|
||||
}
|
||||
}
|
||||
|
@ -1008,16 +1054,15 @@ u32 ReadMem_gdrom(u32 Addr, u32 sz)
|
|||
|
||||
//if (gd_state == gds_pio_send_data)
|
||||
//{
|
||||
if (pio_buff.index == pio_buff.size)
|
||||
if (pio_buff.atEnd())
|
||||
{
|
||||
INFO_LOG(GDROM, "GDROM: Illegal Read From DATA (underflow)");
|
||||
}
|
||||
else
|
||||
{
|
||||
u32 rv= pio_buff.data[pio_buff.index];
|
||||
pio_buff.index+=1;
|
||||
ByteCount.full-=2;
|
||||
if (pio_buff.index==pio_buff.size)
|
||||
u32 rv = pio_buff.read();
|
||||
ByteCount.full -= sizeof(u16);
|
||||
if (pio_buff.atEnd())
|
||||
{
|
||||
verify(pio_buff.next_state != gds_pio_send_data);
|
||||
//end of pio transfer !
|
||||
|
@ -1085,11 +1130,10 @@ void WriteMem_gdrom(u32 Addr, u32 data, u32 sz)
|
|||
}
|
||||
else if (gd_state == gds_pio_get_data)
|
||||
{
|
||||
pio_buff.data[pio_buff.index]=(u16)data;
|
||||
pio_buff.index+=1;
|
||||
if (pio_buff.size==pio_buff.index)
|
||||
pio_buff.write((u16)data);
|
||||
if (pio_buff.atEnd())
|
||||
{
|
||||
verify(pio_buff.next_state!=gds_pio_get_data);
|
||||
verify(pio_buff.next_state != gds_pio_get_data);
|
||||
gd_set_state(pio_buff.next_state);
|
||||
}
|
||||
}
|
||||
|
@ -1136,7 +1180,7 @@ void WriteMem_gdrom(u32 Addr, u32 data, u32 sz)
|
|||
{
|
||||
if (data != ATA_NOP && data != ATA_SOFT_RESET)
|
||||
verify(gd_state == gds_waitcmd);
|
||||
ata_cmd.command = (u8)data;
|
||||
ata_command = (u8)data;
|
||||
gd_set_state(gds_procata);
|
||||
}
|
||||
else
|
||||
|
@ -1178,7 +1222,7 @@ static int GDRomschd(int tag, int cycles, int jitter, void *arg)
|
|||
SecNumber.Status = GD_STANDBY;
|
||||
GDStatus.DSC = 1;
|
||||
}
|
||||
if(!(SB_GDST&1) || !(SB_GDEN &1) || (read_buff.cache_size==0 && read_params.remaining_sectors==0))
|
||||
if (!(SB_GDST & 1) || !(SB_GDEN & 1) || (dma_buff.isEmpty() && read_params.remaining_sectors == 0))
|
||||
return 0;
|
||||
|
||||
u32 src = SB_GDSTARD;
|
||||
|
@ -1193,7 +1237,7 @@ static int GDRomschd(int tag, int cycles, int jitter, void *arg)
|
|||
//if we don't have any more sectors to read
|
||||
if (read_params.remaining_sectors == 0)
|
||||
//make sure we don't underrun the cache :)
|
||||
len = std::min(len, read_buff.cache_size);
|
||||
len = std::min(len, dma_buff.getSize());
|
||||
|
||||
len = std::min(len, (u32)10240);
|
||||
// do we need to do this for GDROM DMA?
|
||||
|
@ -1211,25 +1255,15 @@ static int GDRomschd(int tag, int cycles, int jitter, void *arg)
|
|||
u32 len_backup = len;
|
||||
if(1 == SB_GDDIR)
|
||||
{
|
||||
while(len)
|
||||
while (len)
|
||||
{
|
||||
u32 buff_size =read_buff.cache_size;
|
||||
if (buff_size==0)
|
||||
{
|
||||
verify(read_params.remaining_sectors>0);
|
||||
//buffer is empty , fill it :)
|
||||
FillReadBuffer();
|
||||
continue;
|
||||
}
|
||||
dma_buff.fill(read_params);
|
||||
// transfer up to len bytes
|
||||
const u32 buff_size = std::min(dma_buff.getSize(), len);
|
||||
|
||||
//transfer up to len bytes
|
||||
if (buff_size>len)
|
||||
buff_size=len;
|
||||
WriteMemBlock_nommu_ptr(src,(u32*)&read_buff.cache[read_buff.cache_index], buff_size);
|
||||
read_buff.cache_index+=buff_size;
|
||||
read_buff.cache_size-=buff_size;
|
||||
src+=buff_size;
|
||||
len-=buff_size;
|
||||
WriteMemBlock_nommu_ptr(src, (const u32 *)dma_buff.read(buff_size), buff_size);
|
||||
src += buff_size;
|
||||
len -= buff_size;
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -1245,16 +1279,10 @@ static int GDRomschd(int tag, int cycles, int jitter, void *arg)
|
|||
SB_GDST = 0;
|
||||
asic_RaiseInterrupt(holly_GDROM_DMA);
|
||||
}
|
||||
//Read ALL sectors
|
||||
if (read_params.remaining_sectors==0)
|
||||
{
|
||||
//And all buffer :p
|
||||
if (read_buff.cache_size==0)
|
||||
{
|
||||
//verify(!SB_GDST&1) -> dc can do multi read dma
|
||||
gd_set_state(gds_procpacketdone);
|
||||
}
|
||||
}
|
||||
// Read ALL sectors and all buffer
|
||||
if (read_params.remaining_sectors == 0 && dma_buff.isEmpty())
|
||||
//verify(!SB_GDST&1) -> dc can do multi read dma
|
||||
gd_set_state(gds_procpacketdone);
|
||||
|
||||
return getGDROMTicks();
|
||||
}
|
||||
|
@ -1338,9 +1366,9 @@ void gdrom_reg_Reset(bool hard)
|
|||
set_mode_offset = 0;
|
||||
read_params = {};
|
||||
packet_cmd = {};
|
||||
read_buff = {};
|
||||
pio_buff = {};
|
||||
ata_cmd = {};
|
||||
dma_buff.clear();
|
||||
pio_buff.clear();
|
||||
ata_command = 0;
|
||||
cdda = {};
|
||||
gd_disk_type = NoDisk;
|
||||
|
||||
|
@ -1371,9 +1399,9 @@ void serialize(Serializer& ser)
|
|||
ser << packet_cmd;
|
||||
ser << set_mode_offset;
|
||||
ser << read_params;
|
||||
ser << read_buff;
|
||||
ser << pio_buff;
|
||||
ser << ata_cmd;
|
||||
dma_buff.serialize(ser);
|
||||
pio_buff.serialize(ser);
|
||||
ser << ata_command;
|
||||
ser << cdda;
|
||||
ser << gd_state;
|
||||
ser << gd_disk_type;
|
||||
|
@ -1400,16 +1428,16 @@ void deserialize(Deserializer& deser)
|
|||
deser >> packet_cmd;
|
||||
deser >> set_mode_offset;
|
||||
deser >> read_params;
|
||||
if (deser.version() >= Deserializer::V17)
|
||||
deser >> read_buff;
|
||||
else
|
||||
{
|
||||
deser >> packet_cmd;
|
||||
read_buff.cache_size = 0;
|
||||
if (deser.version() >= Deserializer::V17) {
|
||||
dma_buff.deserialize(deser);
|
||||
}
|
||||
deser >> pio_buff;
|
||||
else {
|
||||
deser >> packet_cmd;
|
||||
dma_buff.clear();
|
||||
}
|
||||
pio_buff.deserialize(deser);
|
||||
deser.skip<u32>(Deserializer::V44); // set_mode_offset (repeat)
|
||||
deser >> ata_cmd;
|
||||
deser >> ata_command;
|
||||
deser >> cdda;
|
||||
deser >> gd_state;
|
||||
deser >> gd_disk_type;
|
||||
|
|
|
@ -164,26 +164,89 @@ struct packet_cmd_t
|
|||
};
|
||||
};
|
||||
|
||||
//Buffer for sector reads [dma]
|
||||
struct read_buff_t
|
||||
class DmaBuffer
|
||||
{
|
||||
u32 cache_index;
|
||||
u32 cache_size;
|
||||
u8 cache[2352 * 32];
|
||||
};
|
||||
public:
|
||||
DmaBuffer() {
|
||||
clear();
|
||||
}
|
||||
bool isEmpty() const {
|
||||
return size == 0;
|
||||
}
|
||||
u32 getSize() const {
|
||||
return size;
|
||||
}
|
||||
void clear() {
|
||||
size = 0;
|
||||
index = 0;
|
||||
}
|
||||
|
||||
//pio buffer
|
||||
struct pio_buff_t
|
||||
{
|
||||
gd_states next_state;
|
||||
// Fill the cache with up to NSECT sectors if empty, using the passed read parameters
|
||||
void fill(read_params_t& params);
|
||||
// Return a pointer to the cache and advance the index by len bytes. len *must* be <= getSize()
|
||||
const u8 *read(u32 len);
|
||||
void serialize(Serializer& ser) const;
|
||||
void deserialize(Deserializer& deser);
|
||||
|
||||
private:
|
||||
static constexpr u32 NSECT = 16;
|
||||
u32 index;
|
||||
u32 size;
|
||||
u16 data[0x10000>>1]; //64 kb
|
||||
u8 cache[2352 * NSECT] {};
|
||||
};
|
||||
|
||||
struct ata_cmd_t
|
||||
class PioBuffer
|
||||
{
|
||||
u8 command;
|
||||
public:
|
||||
PioBuffer() {
|
||||
clear();
|
||||
}
|
||||
bool isEmpty() const {
|
||||
return size == 0;
|
||||
}
|
||||
// Returns true if the buffer has reached its capacity and can't be read from or written to
|
||||
bool atEnd() const {
|
||||
return index == size;
|
||||
}
|
||||
// in bytes
|
||||
u32 getSize() const {
|
||||
return size * sizeof(u16);
|
||||
}
|
||||
void clear()
|
||||
{
|
||||
next_state = gds_waitcmd;
|
||||
size = 0;
|
||||
index = 0;
|
||||
}
|
||||
u16 read() {
|
||||
return _data[index++];
|
||||
}
|
||||
const u16 *data() const {
|
||||
return _data;
|
||||
}
|
||||
void write(u16 v) {
|
||||
_data[index++] = v;
|
||||
}
|
||||
// Returns a pointer to fill the buffer and sets its size. Index is reset.
|
||||
u16 *fill(u32 size) {
|
||||
resetSize(size);
|
||||
return &_data[0];
|
||||
}
|
||||
// Sets the buffer capacity and resets the index.
|
||||
void resetSize(u32 size) {
|
||||
this->index = 0;
|
||||
this->size = size / sizeof(u16);
|
||||
}
|
||||
void serialize(Serializer& ser) const;
|
||||
void deserialize(Deserializer& deser);
|
||||
|
||||
gd_states next_state;
|
||||
static constexpr u32 Capacity = 64_KB;
|
||||
|
||||
private:
|
||||
u32 index;
|
||||
u32 size;
|
||||
u16 _data[Capacity / 2] {};
|
||||
};
|
||||
|
||||
struct cdda_t
|
||||
|
|
|
@ -22,8 +22,126 @@
|
|||
#define SWAP32(a) ((((a) & 0xff) << 24) | (((a) & 0xff00) << 8) | (((a) >> 8) & 0xff00) | (((a) >> 24) & 0xff))
|
||||
|
||||
#define debugf(...) DEBUG_LOG(REIOS, __VA_ARGS__)
|
||||
static void readSectors(u32 addr, u32 sector, u32 count, bool virtualAddr);
|
||||
|
||||
gdrom_hle_state_t gd_hle_state;
|
||||
struct gdrom_hle_state_t
|
||||
{
|
||||
gdrom_hle_state_t() : params{}, result{} {}
|
||||
|
||||
u32 last_request_id = 0xFFFFFFFF;
|
||||
u32 next_request_id = 2;
|
||||
gd_return_value status = GDC_OK;
|
||||
gd_command command = GDCC_NONE;
|
||||
u32 params[4];
|
||||
u32 result[4];
|
||||
u32 cur_sector = 0;
|
||||
u32 multi_read_sector = 0;
|
||||
u32 multi_read_offset = 0;
|
||||
u32 multi_read_count = 0;
|
||||
u32 multi_read_total = 0;
|
||||
u32 multi_callback = 0;
|
||||
u32 multi_callback_arg = 0;
|
||||
bool dma_trans_ended = false;
|
||||
u64 xfer_end_time = 0;
|
||||
|
||||
void Serialize(Serializer& ser)
|
||||
{
|
||||
ser << last_request_id;
|
||||
ser << next_request_id;
|
||||
ser << status;
|
||||
ser << command;
|
||||
ser << params;
|
||||
ser << result;
|
||||
ser << cur_sector;
|
||||
ser << multi_read_sector;
|
||||
ser << multi_read_offset;
|
||||
ser << multi_read_count;
|
||||
ser << multi_read_total;
|
||||
ser << multi_callback;
|
||||
ser << multi_callback_arg;
|
||||
ser << dma_trans_ended;
|
||||
ser << xfer_end_time;
|
||||
|
||||
}
|
||||
void Deserialize(Deserializer& deser)
|
||||
{
|
||||
deser >> last_request_id;
|
||||
deser >> next_request_id;
|
||||
deser >> status;
|
||||
deser >> command;
|
||||
deser >> params;
|
||||
deser >> result;
|
||||
deser >> cur_sector;
|
||||
deser >> multi_read_sector;
|
||||
deser >> multi_read_offset;
|
||||
deser >> multi_read_count;
|
||||
deser >> multi_read_total;
|
||||
deser >> multi_callback;
|
||||
deser >> multi_callback_arg;
|
||||
deser >> dma_trans_ended;
|
||||
deser >> xfer_end_time;
|
||||
}
|
||||
};
|
||||
static gdrom_hle_state_t gd_hle_state;
|
||||
|
||||
static int schedId = -1;
|
||||
|
||||
static int getGdromTicks()
|
||||
{
|
||||
u32 len = gd_hle_state.multi_read_count * 2048;
|
||||
if (len > 10240)
|
||||
return 1000000; // Large transfers: GD-ROM transfer rate 1.8 MB/s
|
||||
else
|
||||
return len * 2; // Small transfers: Max G1 bus rate: 50 MHz x 16 bits
|
||||
}
|
||||
|
||||
static int schedCallback(int tag, int cycles, int jitter, void *arg)
|
||||
{
|
||||
const u32 sect = std::min(gd_hle_state.multi_read_count, 5u);
|
||||
readSectors(gd_hle_state.multi_read_offset, gd_hle_state.multi_read_sector, sect, false);
|
||||
gd_hle_state.multi_read_count -= sect;
|
||||
gd_hle_state.multi_read_sector += sect;
|
||||
gd_hle_state.cur_sector = gd_hle_state.multi_read_sector;
|
||||
gd_hle_state.multi_read_offset += sect * 2048;
|
||||
|
||||
if (gd_hle_state.multi_read_count == 0)
|
||||
{
|
||||
gd_hle_state.result[3] = GDC_WAIT_INTERNAL;
|
||||
SecNumber.Status = GD_STANDBY;
|
||||
gd_hle_state.status = GDC_COMPLETE;
|
||||
}
|
||||
gd_hle_state.result[2] = (gd_hle_state.multi_read_total - gd_hle_state.multi_read_count) * 2048;
|
||||
|
||||
return getGdromTicks();
|
||||
}
|
||||
|
||||
void reios_init() {
|
||||
if (schedId == -1)
|
||||
schedId = sh4_sched_register(0, schedCallback);
|
||||
}
|
||||
|
||||
void reios_serialize(Serializer& ser) {
|
||||
gd_hle_state.Serialize(ser);
|
||||
sh4_sched_serialize(ser, schedId);
|
||||
}
|
||||
|
||||
void reios_deserialize(Deserializer& deser)
|
||||
{
|
||||
gd_hle_state.Deserialize(deser);
|
||||
if (deser.version() >= Deserializer::V54)
|
||||
sh4_sched_deserialize(deser, schedId);
|
||||
}
|
||||
|
||||
void gdrom_hle_reset() {
|
||||
gd_hle_state = {};
|
||||
}
|
||||
|
||||
void reios_term()
|
||||
{
|
||||
if (schedId != -1)
|
||||
sh4_sched_unregister(schedId);
|
||||
schedId = -1;
|
||||
}
|
||||
|
||||
static void GDROM_HLE_ReadSES()
|
||||
{
|
||||
|
@ -64,19 +182,10 @@ static void GDROM_HLE_ReadTOC()
|
|||
WriteMem32(dest, toc[i]);
|
||||
}
|
||||
|
||||
template<bool virtual_addr>
|
||||
static void read_sectors_to(u32 addr, u32 sector, u32 count)
|
||||
static void readSectors(u32 addr, u32 sector, u32 count, bool virtualAddr)
|
||||
{
|
||||
gd_hle_state.cur_sector = sector + count - 1;
|
||||
if (virtual_addr)
|
||||
gd_hle_state.xfer_end_time = 0;
|
||||
else if (count > 5 && !config::FastGDRomLoad)
|
||||
// Large Transfers: GD-ROM rate (approx. 1.8 MB/s)
|
||||
gd_hle_state.xfer_end_time = sh4_sched_now64() + (u64)count * 2048 * 1000000L / 10240;
|
||||
else
|
||||
// Small transfers: Max G1 bus rate: 50 MHz x 16 bits
|
||||
gd_hle_state.xfer_end_time = sh4_sched_now64() + 5 * 2048 * 2;
|
||||
if (!virtual_addr || !mmu_enabled())
|
||||
if (!virtualAddr || !mmu_enabled())
|
||||
{
|
||||
u8 * pDst = GetMemPtr(addr, 0);
|
||||
|
||||
|
@ -94,7 +203,7 @@ static void read_sectors_to(u32 addr, u32 sector, u32 count)
|
|||
|
||||
for (std::size_t i = 0; i < std::size(temp); i++)
|
||||
{
|
||||
if (virtual_addr)
|
||||
if (virtualAddr)
|
||||
WriteMem32(addr, temp[i]);
|
||||
else
|
||||
WriteMem32_nommu(addr, temp[i]);
|
||||
|
@ -106,6 +215,12 @@ static void read_sectors_to(u32 addr, u32 sector, u32 count)
|
|||
}
|
||||
}
|
||||
|
||||
static void read_pio_sectors(u32 addr, u32 sector, u32 count)
|
||||
{
|
||||
gd_hle_state.xfer_end_time = 0;
|
||||
readSectors(addr, sector, count, true);
|
||||
}
|
||||
|
||||
static void GDROM_HLE_ReadDMA()
|
||||
{
|
||||
u32 fad = gd_hle_state.params[0] & 0xffffff;
|
||||
|
@ -115,7 +230,13 @@ static void GDROM_HLE_ReadDMA()
|
|||
|
||||
debugf("GDROM: DMA READ Sector=%d, Num=%d, Buffer=%08x, zero=%x", fad, nsect, buffer, gd_hle_state.params[3]);
|
||||
|
||||
read_sectors_to<false>(buffer, fad, nsect);
|
||||
gd_hle_state.cur_sector = fad;
|
||||
gd_hle_state.multi_read_sector = fad;
|
||||
gd_hle_state.multi_read_offset = buffer;
|
||||
gd_hle_state.multi_read_count = nsect;
|
||||
gd_hle_state.multi_read_total = nsect;
|
||||
sh4_sched_request(schedId, getGdromTicks());
|
||||
|
||||
gd_hle_state.result[2] = 0;
|
||||
gd_hle_state.result[3] = 0;
|
||||
}
|
||||
|
@ -129,7 +250,7 @@ static void GDROM_HLE_ReadPIO()
|
|||
|
||||
debugf("GDROM: PIO READ Sector=%d, Num=%d, Buffer=%08x, SeekAhead=%x", fad, nsect, buffer, gd_hle_state.params[3]);
|
||||
|
||||
read_sectors_to<true>(buffer, fad, nsect);
|
||||
read_pio_sectors(buffer, fad, nsect);
|
||||
gd_hle_state.result[2] = nsect * 2048;
|
||||
gd_hle_state.result[3] = 0;
|
||||
}
|
||||
|
@ -292,19 +413,9 @@ static void GD_HLE_Command(gd_command cc)
|
|||
|
||||
case GDCC_DMAREAD:
|
||||
cdda.status = cdda_t::NoInfo;
|
||||
if (gd_hle_state.xfer_end_time == 0)
|
||||
if (gd_hle_state.multi_read_count == 0)
|
||||
GDROM_HLE_ReadDMA();
|
||||
if (gd_hle_state.xfer_end_time > 0)
|
||||
{
|
||||
if (gd_hle_state.xfer_end_time > sh4_sched_now64())
|
||||
return;
|
||||
gd_hle_state.xfer_end_time = 0;
|
||||
}
|
||||
gd_hle_state.result[2] = gd_hle_state.params[1] * 2048;
|
||||
gd_hle_state.result[3] = 0;
|
||||
SecNumber.Status = GD_PAUSE;
|
||||
break;
|
||||
|
||||
return;
|
||||
|
||||
case GDCC_PLAY2:
|
||||
{
|
||||
|
|
|
@ -70,9 +70,8 @@ enum misc_command {
|
|||
MISC_SETVECTOR
|
||||
};
|
||||
|
||||
void gdrom_hle_init();
|
||||
void gdrom_hle_term();
|
||||
void gdrom_hle_op();
|
||||
void gdrom_hle_reset();
|
||||
|
||||
typedef enum : int32_t {
|
||||
GDC_ERR = -1,
|
||||
|
@ -85,66 +84,6 @@ typedef enum : int32_t {
|
|||
GDC_RET2
|
||||
} gd_return_value;
|
||||
|
||||
struct gdrom_hle_state_t
|
||||
{
|
||||
gdrom_hle_state_t() : params{}, result{} {}
|
||||
|
||||
u32 last_request_id = 0xFFFFFFFF;
|
||||
u32 next_request_id = 2;
|
||||
gd_return_value status = GDC_OK;
|
||||
gd_command command = GDCC_NONE;
|
||||
u32 params[4];
|
||||
u32 result[4];
|
||||
u32 cur_sector = 0;
|
||||
u32 multi_read_sector = 0;
|
||||
u32 multi_read_offset = 0;
|
||||
u32 multi_read_count = 0;
|
||||
u32 multi_read_total = 0;
|
||||
u32 multi_callback = 0;
|
||||
u32 multi_callback_arg = 0;
|
||||
bool dma_trans_ended = false;
|
||||
u64 xfer_end_time = 0;
|
||||
|
||||
void Serialize(Serializer& ser)
|
||||
{
|
||||
ser << last_request_id;
|
||||
ser << next_request_id;
|
||||
ser << status;
|
||||
ser << command;
|
||||
ser << params;
|
||||
ser << result;
|
||||
ser << cur_sector;
|
||||
ser << multi_read_sector;
|
||||
ser << multi_read_offset;
|
||||
ser << multi_read_count;
|
||||
ser << multi_read_total;
|
||||
ser << multi_callback;
|
||||
ser << multi_callback_arg;
|
||||
ser << dma_trans_ended;
|
||||
ser << xfer_end_time;
|
||||
|
||||
}
|
||||
void Deserialize(Deserializer& deser)
|
||||
{
|
||||
deser >> last_request_id;
|
||||
deser >> next_request_id;
|
||||
deser >> status;
|
||||
deser >> command;
|
||||
deser >> params;
|
||||
deser >> result;
|
||||
deser >> cur_sector;
|
||||
deser >> multi_read_sector;
|
||||
deser >> multi_read_offset;
|
||||
deser >> multi_read_count;
|
||||
deser >> multi_read_total;
|
||||
deser >> multi_callback;
|
||||
deser >> multi_callback_arg;
|
||||
deser >> dma_trans_ended;
|
||||
deser >> xfer_end_time;
|
||||
}
|
||||
};
|
||||
extern gdrom_hle_state_t gd_hle_state;
|
||||
|
||||
// status for GDROM_GET_DRV_STAT
|
||||
enum gd_drv_stat {
|
||||
GD_STAT_BUSY,
|
||||
|
|
|
@ -727,13 +727,7 @@ void DYNACALL reios_trap(Sh4Context *ctx, u32 op)
|
|||
ctx->pc = ctx->pr;
|
||||
}
|
||||
|
||||
bool reios_init()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void reios_set_flash(MemChip* flash)
|
||||
{
|
||||
void reios_set_flash(MemChip* flash) {
|
||||
flashrom = flash;
|
||||
}
|
||||
|
||||
|
@ -763,8 +757,5 @@ void reios_reset(u8* rom)
|
|||
std::unique_ptr<u8[]> fontData = resource::load("fonts/biosfont.bin", size);
|
||||
memcpy(pFont, fontData.get(), size);
|
||||
|
||||
gd_hle_state = {};
|
||||
}
|
||||
|
||||
void reios_term() {
|
||||
gdrom_hle_reset();
|
||||
}
|
||||
|
|
|
@ -3,10 +3,11 @@
|
|||
#include "types.h"
|
||||
#include "hw/flashrom/flashrom.h"
|
||||
|
||||
bool reios_init();
|
||||
void reios_init();
|
||||
void reios_set_flash(MemChip* flash);
|
||||
void reios_reset(u8* rom);
|
||||
|
||||
void reios_serialize(Serializer& ser);
|
||||
void reios_deserialize(Deserializer& deser);
|
||||
void reios_term();
|
||||
|
||||
struct Sh4Context;
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
#include "hw/pvr/pvr.h"
|
||||
#include "hw/sh4/sh4_sched.h"
|
||||
#include "hw/sh4/sh4_mmr.h"
|
||||
#include "reios/gdrom_hle.h"
|
||||
#include "reios/reios.h"
|
||||
#include "hw/naomi/naomi.h"
|
||||
#include "hw/naomi/naomi_cart.h"
|
||||
#include "hw/bba/bba.h"
|
||||
|
@ -50,7 +50,7 @@ void dc_serialize(Serializer& ser)
|
|||
ser << config::Region.get();
|
||||
|
||||
naomi_cart_serialize(ser);
|
||||
gd_hle_state.Serialize(ser);
|
||||
reios_serialize(ser);
|
||||
achievements::serialize(ser);
|
||||
|
||||
DEBUG_LOG(SAVESTATE, "Saved %d bytes", (u32)ser.size());
|
||||
|
@ -93,7 +93,7 @@ void dc_deserialize(Deserializer& deser)
|
|||
verify(config::Region >= 0 && config::Region <= 3);
|
||||
|
||||
naomi_cart_deserialize(deser);
|
||||
gd_hle_state.Deserialize(deser);
|
||||
reios_deserialize(deser);
|
||||
achievements::deserialize(deser);
|
||||
sh4_sched_ffts();
|
||||
|
||||
|
|
|
@ -64,7 +64,8 @@ public:
|
|||
V51,
|
||||
V52,
|
||||
V53,
|
||||
Current = V53,
|
||||
V54,
|
||||
Current = V54,
|
||||
|
||||
Next = Current + 1,
|
||||
};
|
||||
|
|
|
@ -32,8 +32,5 @@ TEST_F(SerializeTest, SizeTest)
|
|||
std::vector<char> data(30000000);
|
||||
Serializer ser(data.data(), data.size());
|
||||
dc_serialize(ser);
|
||||
ASSERT_EQ(28191434u, ser.size());
|
||||
ASSERT_EQ(28050642u, ser.size());
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue