mirror of
https://github.com/n64dev/cen64.git
synced 2024-06-23 14:33:13 -04:00
Prevent 64DD thread from crashing.
RTC adjustment works and communication between the 64DD is now present, but we don't actually save the RTC settings.
This commit is contained in:
parent
10fc81d7a3
commit
ce34ff04c4
|
@ -11,6 +11,10 @@ Iconoclast: Although we hardly ever see eye-to-eye with regards to
|
|||
ification of the RSP algorithms would have been even more
|
||||
testing than it already was.
|
||||
|
||||
OzOnE/LuigiBlood For your fantastic documentation and efforts on reversing
|
||||
the 64DD. Without your efforts, there's no way that CEN64
|
||||
would have 64DD support.
|
||||
|
||||
AIO: Thank you for your RSP/SSE optimizations. It's always nice
|
||||
to see someone else's approaches to vectorizing some of the
|
||||
RSP instructions!
|
||||
|
|
119
dd/controller.c
119
dd/controller.c
|
@ -8,10 +8,17 @@
|
|||
// 'LICENSE', which is part of this source code package.
|
||||
//
|
||||
|
||||
//
|
||||
// Thanks go out to OzOnE and Luigiblood (Seru-kun) for reverse
|
||||
// engineering, documenting, and assisting with the reversal of
|
||||
// this device!
|
||||
//
|
||||
|
||||
#include "common.h"
|
||||
#include "bus/address.h"
|
||||
#include "bus/controller.h"
|
||||
#include "dd/controller.h"
|
||||
#include "vr4300/interface.h"
|
||||
|
||||
#ifdef DEBUG_MMIO_REGISTER_ACCESS
|
||||
const char *dd_register_mnemonics[NUM_DD_REGISTERS] = {
|
||||
|
@ -21,6 +28,63 @@ const char *dd_register_mnemonics[NUM_DD_REGISTERS] = {
|
|||
};
|
||||
#endif
|
||||
|
||||
// ASIC_CMD_STATUS flags.
|
||||
#define DD_CMD_NOOP 0x00000000U
|
||||
#define DD_CMD_SEEK_READ 0x00010001U
|
||||
#define DD_CMD_SEEK_WRITE 0x00020001U
|
||||
#define DD_CMD_RECALIBRATE 0x00030001U // ???
|
||||
#define DD_CMD_SLEEP 0x00040000U
|
||||
#define DD_CMD_START 0x00050001U
|
||||
#define DD_CMD_SET_STANDBY 0x00060000U
|
||||
#define DD_CMD_SET_SLEEP 0x00040000U
|
||||
#define DD_CMD_CLR_DSK_CHNG 0x00080000U
|
||||
#define DD_CMD_CLR_RESET 0x00090000U
|
||||
#define DD_CMD_READ_VERSION 0x000A0000U
|
||||
#define DD_CMD_SET_DISK_TYPE 0x000B0001U
|
||||
#define DD_CMD_REQUEST_STATUS 0x000C0000U
|
||||
#define DD_CMD_STANDBY 0x000D0000U
|
||||
#define DD_CMD_IDX_LOCK_RETRY 0x000D0000U // ???
|
||||
#define DD_CMD_SET_YEAR_MONTH 0x000F0000U
|
||||
#define DD_CMD_SET_DAY_HOUR 0x00100000U
|
||||
#define DD_CMD_SET_MIN_SEC 0x00110000U
|
||||
#define DD_CMD_GET_YEAR_MONTH 0x00120000U
|
||||
#define DD_CMD_GET_DAY_HOUR 0x00130000U
|
||||
#define DD_CMD_GET_MIN_SEC 0x00140000U
|
||||
#define DD_CMD_FEATURE_INQ 0x001B0000U
|
||||
|
||||
#define DD_STATUS_DATA_RQ 0x40000000U
|
||||
#define DD_STATUS_C2_XFER 0x10000000U
|
||||
#define DD_STATUS_BM_ERR 0x08000000U
|
||||
#define DD_STATUS_BM_INT 0x04000000U
|
||||
#define DD_STATUS_MECHA_INT 0x02000000U
|
||||
#define DD_STATUS_DISK_PRES 0x01000000U
|
||||
#define DD_STATUS_BUSY_STATE 0x00800000U
|
||||
#define DD_STATUS_RST_STATE 0x00400000U
|
||||
#define DD_STATUS_MTR_N_SPIN 0x00100000U
|
||||
#define DD_STATUS_HEAD_RTRCT 0x00080000U
|
||||
#define DD_STATUS_WR_PR_ERR 0x00040000U
|
||||
#define DD_STATUS_MECHA_ERR 0x00020000U
|
||||
#define DD_STATUS_DISK_CHNG 0x00010000U
|
||||
|
||||
// ASIC_BM_STATUS_CTL flags.
|
||||
#define DD_BM_STATUS_RUNNING 0x00000000U
|
||||
#define DD_BM_STATUS_ERROR 0x04000000U
|
||||
#define DD_BM_STATUS_MICRO 0x02000000U // ???
|
||||
#define DD_BM_STATUS_BLOCK 0x01000000U
|
||||
#define DD_BM_STATUS_C1CRR 0x00800000U
|
||||
#define DD_BM_STATUS_C1DBL 0x00400000U
|
||||
#define DD_BM_STATUS_C1SNG 0x00200000U
|
||||
#define DD_BM_STATUS_C1ERR 0x00010000U // Typo ???
|
||||
|
||||
#define DD_BM_CTL_START 0x80000000U
|
||||
#define DD_BM_CTL_MNGRMODE 0x40000000U
|
||||
#define DD_BM_CTL_INTMASK 0x20000000U
|
||||
#define DD_BM_CTL_RESET 0x10000000U
|
||||
#define DD_BM_CTL_DIS_OR_CHK 0x08000000U // ???
|
||||
#define DD_BM_CTL_DIS_C1_CRR 0x04000000U
|
||||
#define DD_BM_CTL_BLK_TRANS 0x02000000U
|
||||
#define DD_BM_CTL_MECHA_RST 0x01000000U
|
||||
|
||||
// Initializes the DD.
|
||||
int dd_init(struct dd_controller *dd, struct bus_controller *bus,
|
||||
const uint8_t *rom) {
|
||||
|
@ -49,8 +113,57 @@ int write_dd_regs(void *opaque, uint32_t address, uint32_t word, uint32_t dqm) {
|
|||
|
||||
debug_mmio_write(dd, dd_register_mnemonics[reg], word, dqm);
|
||||
|
||||
dd->regs[reg] &= ~dqm;
|
||||
dd->regs[reg] |= word;
|
||||
// Command register written: do something.
|
||||
if (reg == DD_ASIC_CMD_STATUS) {
|
||||
|
||||
// Get time [minute/second]:
|
||||
if (word == DD_CMD_GET_MIN_SEC) {
|
||||
dd->regs[DD_ASIC_CMD_STATUS] |= DD_STATUS_MECHA_INT;
|
||||
signal_dd_interrupt(dd->bus->vr4300);
|
||||
}
|
||||
|
||||
else if (word == DD_CMD_GET_DAY_HOUR) {
|
||||
dd->regs[DD_ASIC_CMD_STATUS] |= DD_STATUS_MECHA_INT;
|
||||
signal_dd_interrupt(dd->bus->vr4300);
|
||||
}
|
||||
|
||||
else if (word == DD_CMD_GET_YEAR_MONTH) {
|
||||
dd->regs[DD_ASIC_CMD_STATUS] |= DD_STATUS_MECHA_INT;
|
||||
signal_dd_interrupt(dd->bus->vr4300);
|
||||
}
|
||||
}
|
||||
|
||||
// Buffer manager control request: handle it.
|
||||
else if (reg == DD_ASIC_BM_STATUS_CTL) {
|
||||
if (word == DD_BM_CTL_RESET) {
|
||||
dd->regs[DD_ASIC_BM_STATUS_CTL] &= ~DD_BM_CTL_INTMASK;
|
||||
clear_dd_interrupt(dd->bus->vr4300);
|
||||
}
|
||||
|
||||
else if (word == DD_BM_CTL_MECHA_RST) {
|
||||
dd->regs[DD_ASIC_CMD_STATUS] &= ~DD_STATUS_MECHA_INT;
|
||||
clear_dd_interrupt(dd->bus->vr4300);
|
||||
}
|
||||
|
||||
else if (word == 0) {
|
||||
clear_dd_interrupt(dd->bus->vr4300);
|
||||
}
|
||||
}
|
||||
|
||||
// This is done by the IPL and a lot of games. The only word
|
||||
// ever know to be written to this register is 0xAAAA0000.
|
||||
// Reverse engineering shows the drive always sets the C1
|
||||
// double correction flag in response.
|
||||
else if (reg == DD_ASIC_HARD_RESET) {
|
||||
assert(*word == 0xAAAA0000 && "dd: Hard reset without magic word?");
|
||||
|
||||
dd->regs[DD_ASIC_BM_STATUS_CTL] = DD_BM_STATUS_C1DBL;
|
||||
}
|
||||
|
||||
else {
|
||||
dd->regs[reg] &= ~dqm;
|
||||
dd->regs[reg] |= word;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -61,7 +174,7 @@ int read_dd_ipl_rom(void *opaque, uint32_t address, uint32_t *word) {
|
|||
struct dd_controller *dd = (struct dd_controller*) opaque;
|
||||
|
||||
if (!dd->rom)
|
||||
memset(word, 0, sizeof(word));
|
||||
memset(word, 0, sizeof(*word));
|
||||
|
||||
else {
|
||||
memcpy(word, dd->rom + offset, sizeof(*word));
|
||||
|
|
|
@ -12,9 +12,9 @@
|
|||
#define DD_REGISTER_LIST \
|
||||
X(DD_ASIC_DATA) \
|
||||
X(DD_ASIC_MISC_REG) \
|
||||
X(DD_ASIC_CMD) \
|
||||
X(DD_ASIC_CMD_STATUS) \
|
||||
X(DD_ASIC_CUR_TK) \
|
||||
X(DD_ASIC_BM_STATUS) \
|
||||
X(DD_ASIC_BM_STATUS_CTL) \
|
||||
X(DD_ASIC_ERR_SECTOR) \
|
||||
X(DD_ASIC_SEQ_STATUS) \
|
||||
X(DD_ASIC_CUR_SECTOR) \
|
||||
|
|
|
@ -44,6 +44,16 @@ static void raise_rcp_interrupt(struct vr4300 *vr4300) {
|
|||
vr4300->regs[VR4300_CP0_REGISTER_CAUSE] |= 0x400;
|
||||
}
|
||||
|
||||
// Deasserts the interrupt signal from the 64DD.
|
||||
void clear_dd_interrupt(struct vr4300 *vr4300) {
|
||||
vr4300->regs[VR4300_CP0_REGISTER_CAUSE] &= ~0x800;
|
||||
}
|
||||
|
||||
// Asserts the interrupt signal from the 64DD.
|
||||
void signal_dd_interrupt(struct vr4300 *vr4300) {
|
||||
vr4300->regs[VR4300_CP0_REGISTER_CAUSE] |= 0x800;
|
||||
}
|
||||
|
||||
// Callback: An RCP component is signaling an interrupt.
|
||||
void signal_rcp_interrupt(struct vr4300 *vr4300, enum rcp_interrupt_mask mask) {
|
||||
vr4300->mi_regs[MI_INTR_REG] |= mask;
|
||||
|
|
|
@ -28,5 +28,8 @@ int write_mi_regs(void *opaque, uint32_t address, uint32_t word, uint32_t dqm);
|
|||
void clear_rcp_interrupt(struct vr4300 *vr4300, enum rcp_interrupt_mask mask);
|
||||
void signal_rcp_interrupt(struct vr4300 *vr4300, enum rcp_interrupt_mask mask);
|
||||
|
||||
void clear_dd_interrupt(struct vr4300 *vr4300);
|
||||
void signal_dd_interrupt(struct vr4300 *vr4300);
|
||||
|
||||
#endif
|
||||
|
||||
|
|
Loading…
Reference in a new issue