--- hatari/src/falcon/dsp.c 2019/04/09 08:47:21 1.1.1.3 +++ hatari/src/falcon/dsp.c 2019/04/09 08:59:31 1.1.1.14 @@ -16,18 +16,25 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + along with this program; if not, write to the Free Software Foundation, + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */ +#include + #include "main.h" #include "sysdeps.h" #include "newcpu.h" #include "memorySnapShot.h" #include "ioMem.h" #include "dsp.h" +#include "crossbar.h" +#include "configuration.h" +#include "cycInt.h" +#include "m68000.h" + #if ENABLE_DSP_EMU -#include "debugui.h" +#include "debugdsp.h" #include "dsp_cpu.h" #include "dsp_disasm.h" #endif @@ -39,38 +46,124 @@ #define Dprintf(a) #endif -#define BITMASK(x) ((1<<(x))-1) - #define DSP_HW_OFFSET 0xFFA200 + #if ENABLE_DSP_EMU -static dsp_core_t dsp_core; +static const char* x_ext_memory_addr_name[] = { + "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", + "PBC", "PCC", "PBDDR", "PCDDR", "PBD", "PCD", "", "", + "HCR", "HSR", "", "HRX/HTX", "CRA", "CRB", "SSISR/TSR", "RX/TX", + "SCR", "SSR", "SCCR", "STXA", "SRX/STX", "SRX/STX", "SRX/STX", "", + "", "", "", "", "", "", "BCR", "IPR" +}; + +static Sint32 save_cycles; #endif + static bool bDspDebugging; bool bDspEnabled = false; +bool bDspHostInterruptPending = false; + +Uint64 DSP_CyclesGlobalClockCounter = 0; /* Value of CyclesGlobalClockCounter when DSP_Run was last called */ /** - * Initialize the DSP emulation + * Trigger HREQ interrupt at the host CPU. + */ +#if ENABLE_DSP_EMU +static void DSP_TriggerHostInterrupt(int hreq) +{ +//fprintf ( stderr, "DSP_TriggerHostInterrupt %d %x %x\n" , hreq , regs.sr , regs.intmask ); + if ( hreq ) + { + M68000_SetSpecial(SPCFLAG_DSP); // TODO for old cpu core, remove, use level 6 instead and M68000_Update_intlev() + bDspHostInterruptPending = true; + M68000_Update_intlev (); + } + else + { + M68000_UnsetSpecial(SPCFLAG_DSP); // TODO for old cpu core, remove, use level 6 instead and M68000_Update_intlev() + bDspHostInterruptPending = false; + M68000_Update_intlev (); + } +} +#endif + + +/** + * Return the state of HREQ + */ +Uint8 DSP_GetHREQ ( void ) +{ + if ( bDspHostInterruptPending ) + return 1; + else + return 0; +} + + +/** + * Return the vector number associated to the HREQ interrupt. + * If this function is called when HREQ=0, then we return -1 to indicate + * a spurious interrupt. + */ +int DSP_ProcessIACK ( void ) +{ + int VecNr; + + if ( bDspHostInterruptPending ) + VecNr = IoMem_ReadByte ( 0xffa203 ); + else + VecNr = -1; + + return VecNr; +} + + +/** + * This function is called from the CPU emulation part when SPCFLAG_DSP is set. + * If the DSP's IRQ signal is set, we check that SR allows a level 6 interrupt, + * and if so, we call M68000_Exception. + */ +#if ENABLE_DSP_EMU +bool DSP_ProcessIRQ(void) +{ + if (bDspHostInterruptPending && regs.intmask < 6) + { + M68000_Exception(IoMem_ReadByte(0xffa203), M68000_EXC_SRC_INT_DSP); + bDspHostInterruptPending = false; // [NP] TODO : remove this line, should be cleared by DSP_TriggerHostInterrupt ? + M68000_UnsetSpecial(SPCFLAG_DSP); // [NP] TODO : remove this line, should be cleared by DSP_TriggerHostInterrupt ? + return true; + } + + return false; +} +#endif + + +/** + * Initialize the DSP emulation (should be called only once at start) */ void DSP_Init(void) { #if ENABLE_DSP_EMU - dsp_core_init(&dsp_core); - dsp56k_init_cpu(&dsp_core); - bDspEnabled = true; + dsp_core_init(DSP_TriggerHostInterrupt); + dsp56k_init_cpu(); + save_cycles = 0; #endif } /** - * Shut down the DSP emulation + * Shut down the DSP emulation (should be called only once at exit) */ void DSP_UnInit(void) { #if ENABLE_DSP_EMU - dsp_core_shutdown(&dsp_core); + dsp_core_shutdown(); bDspEnabled = false; #endif } @@ -82,7 +175,32 @@ void DSP_UnInit(void) void DSP_Reset(void) { #if ENABLE_DSP_EMU - dsp_core_reset(&dsp_core); + dsp_core_reset(); + DSP_TriggerHostInterrupt ( 0 ); /* Clear HREQ */ + save_cycles = 0; +#endif +} + + +/** + * Enable the DSP emulation + */ +void DSP_Enable(void) +{ +#if ENABLE_DSP_EMU + bDspEnabled = true; + DSP_CyclesGlobalClockCounter = CyclesGlobalClockCounter; +#endif +} + + +/** + * Disable the DSP emulation + */ +void DSP_Disable(void) +{ +#if ENABLE_DSP_EMU + bDspEnabled = false; #endif } @@ -93,36 +211,57 @@ void DSP_Reset(void) void DSP_MemorySnapShot_Capture(bool bSave) { #if ENABLE_DSP_EMU - if (!bSave) - DSP_Reset(); - MemorySnapShot_Store(&bDspEnabled, sizeof(bDspEnabled)); MemorySnapShot_Store(&dsp_core, sizeof(dsp_core)); + MemorySnapShot_Store(&save_cycles, sizeof(save_cycles)); + + if ( bDspEnabled ) + DSP_Enable(); + else + DSP_Disable(); #endif } - /** * Run DSP for certain cycles */ void DSP_Run(int nHostCycles) { #if ENABLE_DSP_EMU - /* Cycles emulation is just a rough approximation by now. - * (to be tuned ...) */ - int i = nHostCycles * 2 + 2; - int dsp_cycle = 0; + if ( nHostCycles == 0 ) + return; - while (dsp_core.running == 1 && i >= dsp_cycle) - { - if (unlikely(bDspDebugging)) - DebugUI_DspCheck(); + DSP_CyclesGlobalClockCounter = CyclesGlobalClockCounter; + + save_cycles += nHostCycles * 2; - dsp56k_execute_instruction(); - dsp_cycle += dsp_core.instr_cycle; + if (dsp_core.running == 0) + return; + + if (save_cycles <= 0) + return; + + if (unlikely(bDspDebugging)) + { + while (save_cycles > 0) + { + dsp56k_execute_instruction(); + save_cycles -= dsp_core.instr_cycle; + DebugDsp_Check(); + } + } + else + { + // fprintf(stderr, "--> %d\n", save_cycles); + while (save_cycles > 0) + { + dsp56k_execute_instruction(); + save_cycles -= dsp_core.instr_cycle; + } } + #endif -} +} /** * Enable/disable DSP debugging mode @@ -133,7 +272,7 @@ void DSP_SetDebugging(bool enabled) } /** - * Get DSP program counter (for disassembler) + * Get DSP program counter (for debugging) */ Uint16 DSP_GetPC(void) { @@ -145,22 +284,63 @@ Uint16 DSP_GetPC(void) return 0; } +/** + * Get next DSP PC without output (for debugging) + */ +Uint16 DSP_GetNextPC(Uint16 pc) +{ +#if ENABLE_DSP_EMU + /* code is reduced copy from dsp56k_execute_one_disasm_instruction() */ + dsp_core_t dsp_core_save; + Uint16 instruction_length; + + if (!bDspEnabled) + return 0; + + /* Save DSP context */ + memcpy(&dsp_core_save, &dsp_core, sizeof(dsp_core)); + + /* Disasm instruction */ + dsp_core.pc = pc; + /* why dsp56k_execute_one_disasm_instruction() does "-1" + * for this value, that doesn't seem right??? + */ + instruction_length = dsp56k_disasm(DSP_DISASM_MODE, stderr); + + /* Restore DSP context */ + memcpy(&dsp_core, &dsp_core_save, sizeof(dsp_core)); + + return pc + instruction_length; +#else + return 0; +#endif +} + +/** + * Get current DSP instruction cycles (for profiling) + */ +Uint16 DSP_GetInstrCycles(void) +{ +#if ENABLE_DSP_EMU + if (bDspEnabled) + return dsp_core.instr_cycle; + else +#endif + return 0; +} + /** - * Disassemble DSP code between given addresses + * Disassemble DSP code between given addresses, return next PC address */ -Uint32 DSP_DisasmAddress(Uint16 lowerAdr, Uint16 UpperAdr) +Uint16 DSP_DisasmAddress(FILE *out, Uint16 lowerAdr, Uint16 UpperAdr) { #if ENABLE_DSP_EMU - Uint32 dsp_pc, save_curPC; - - save_curPC = dsp_core.pc; + Uint16 dsp_pc; for (dsp_pc=lowerAdr; dsp_pc<=UpperAdr; dsp_pc++) { - dsp_core.pc = dsp_pc; - dsp_pc += dsp56k_disasm() - 1; + dsp_pc += dsp56k_execute_one_disasm_instruction(out, dsp_pc); } - dsp_core.pc = save_curPC; return dsp_pc; #else return 0; @@ -256,8 +436,9 @@ Uint32 DSP_ReadMemory(Uint16 address, ch /** * Output memory values between given addresses in given DSP address space. + * Return next DSP address value. */ -void DSP_DisasmMemory(Uint16 dsp_memdump_addr, Uint16 dsp_memdump_upper, char space) +Uint16 DSP_DisasmMemory(FILE *fp, Uint16 dsp_memdump_addr, Uint16 dsp_memdump_upper, char space) { #if ENABLE_DSP_EMU Uint32 mem, mem2, value; @@ -265,15 +446,19 @@ void DSP_DisasmMemory(Uint16 dsp_memdump for (mem = dsp_memdump_addr; mem <= dsp_memdump_upper; mem++) { /* special printing of host communication/transmit registers */ - if (space == 'X' && (mem == 0xffeb || mem == 0xffef)) { + if (space == 'X' && mem >= 0xffc0) { if (mem == 0xffeb) { - fprintf(stderr,"X periph:%04x HTX : %06x RTX:%06x\n", + fprintf(fp, "X periph:%04x HTX : %06x RTX:%06x\n", mem, dsp_core.dsp_host_htx, dsp_core.dsp_host_rtx); } else if (mem == 0xffef) { - fprintf(stderr,"X periph:%04x SSI TX : %06x SSI RX:%06x\n", + fprintf(fp, "X periph:%04x SSI TX : %06x SSI RX:%06x\n", mem, dsp_core.ssi.transmit_value, dsp_core.ssi.received_value); } + else { + value = DSP_ReadMemory(mem, space, &mem_str); + fprintf(fp, "%s:%04x %06x\t%s\n", mem_str, mem, value, x_ext_memory_addr_name[mem-0xffc0]); + } continue; } /* special printing of X & Y external RAM values */ @@ -283,40 +468,83 @@ void DSP_DisasmMemory(Uint16 dsp_memdump if (space == 'X') { mem2 += (DSP_RAMSIZE>>1); } - fprintf(stderr,"%c:%04x (P:%04x): %06x\n", space, + fprintf(fp, "%c:%04x (P:%04x): %06x\n", space, mem, mem2, dsp_core.ramext[mem2 & (DSP_RAMSIZE-1)]); continue; } value = DSP_ReadMemory(mem, space, &mem_str); - fprintf(stderr,"%s:%04x %06x\n", mem_str, mem, value); + fprintf(fp, "%s:%04x %06x\n", mem_str, mem, value); } #endif + return dsp_memdump_upper+1; } +/** + * Show information on DSP core state which isn't + * shown by any of the other commands (dd, dm, dr). + */ +void DSP_Info(FILE *fp, Uint32 dummy) +{ +#if ENABLE_DSP_EMU + int i, j; + const char *stackname[] = { "SSH", "SSL" }; + + fputs("DSP core information:\n", fp); + + for (i = 0; i < ARRAY_SIZE(stackname); i++) { + fprintf(fp, "- %s stack:", stackname[i]); + for (j = 0; j < ARRAY_SIZE(dsp_core.stack[0]); j++) { + fprintf(fp, " %04hx", dsp_core.stack[i][j]); + } + fputs("\n", fp); + } + + fprintf(fp, "- Interrupt IPL:"); + for (i = 0; i < ARRAY_SIZE(dsp_core.interrupt_ipl); i++) { + fprintf(fp, " %04hx", dsp_core.interrupt_ipl[i]); + } + fputs("\n", fp); + + fprintf(fp, "- Pending ints: "); + for (i = 0; i < ARRAY_SIZE(dsp_core.interrupt_isPending); i++) { + fprintf(fp, " %04hx", dsp_core.interrupt_isPending[i]); + } + fputs("\n", fp); + + fprintf(fp, "- Hostport:"); + for (i = 0; i < ARRAY_SIZE(dsp_core.hostport); i++) { + fprintf(fp, " %02x", dsp_core.hostport[i]); + } + fputs("\n", fp); +#endif +} -void DSP_DisasmRegisters(void) +/** + * Show DSP register contents + */ +void DSP_DisasmRegisters(FILE *fp) { #if ENABLE_DSP_EMU Uint32 i; - fprintf(stderr,"A: A2: %02x A1: %06x A0: %06x\n", + fprintf(fp, "A: A2: %02x A1: %06x A0: %06x\n", dsp_core.registers[DSP_REG_A2], dsp_core.registers[DSP_REG_A1], dsp_core.registers[DSP_REG_A0]); - fprintf(stderr,"B: B2: %02x B1: %06x B0: %06x\n", + fprintf(fp, "B: B2: %02x B1: %06x B0: %06x\n", dsp_core.registers[DSP_REG_B2], dsp_core.registers[DSP_REG_B1], dsp_core.registers[DSP_REG_B0]); - fprintf(stderr,"X: X1: %06x X0: %06x\n", dsp_core.registers[DSP_REG_X1], dsp_core.registers[DSP_REG_X0]); - fprintf(stderr,"Y: Y1: %06x Y0: %06x\n", dsp_core.registers[DSP_REG_Y1], dsp_core.registers[DSP_REG_Y0]); + fprintf(fp, "X: X1: %06x X0: %06x\n", dsp_core.registers[DSP_REG_X1], dsp_core.registers[DSP_REG_X0]); + fprintf(fp, "Y: Y1: %06x Y0: %06x\n", dsp_core.registers[DSP_REG_Y1], dsp_core.registers[DSP_REG_Y0]); for (i=0; i<8; i++) { - fprintf(stderr,"R%01x: %04x N%01x: %04x M%01x: %04x\n", + fprintf(fp, "R%01x: %04x N%01x: %04x M%01x: %04x\n", i, dsp_core.registers[DSP_REG_R0+i], i, dsp_core.registers[DSP_REG_N0+i], i, dsp_core.registers[DSP_REG_M0+i]); } - fprintf(stderr,"LA: %04x LC: %04x PC: %04x\n", dsp_core.registers[DSP_REG_LA], dsp_core.registers[DSP_REG_LC], dsp_core.pc); - fprintf(stderr,"SR: %04x OMR: %02x\n", dsp_core.registers[DSP_REG_SR], dsp_core.registers[DSP_REG_OMR]); - fprintf(stderr,"SP: %02x SSH: %04x SSL: %04x\n", + fprintf(fp, "LA: %04x LC: %04x PC: %04x\n", dsp_core.registers[DSP_REG_LA], dsp_core.registers[DSP_REG_LC], dsp_core.pc); + fprintf(fp, "SR: %04x OMR: %02x\n", dsp_core.registers[DSP_REG_SR], dsp_core.registers[DSP_REG_OMR]); + fprintf(fp, "SP: %02x SSH: %04x SSL: %04x\n", dsp_core.registers[DSP_REG_SP], dsp_core.registers[DSP_REG_SSH], dsp_core.registers[DSP_REG_SSL]); #endif } @@ -408,24 +636,29 @@ int DSP_GetRegisterAddress(const char *r { "Y1", &dsp_core.registers[DSP_REG_Y1], 32, BITMASK(24) } }; /* left, right, middle, direction */ - int l, r, m, dir; - unsigned int i; + int l, r, m, dir = 0; + unsigned int i, len; char reg[MAX_REGNAME_LEN]; + if (!bDspEnabled) { + return 0; + } + for (i = 0; i < sizeof(reg) && regname[i]; i++) { - reg[i] = toupper(regname[i]); + reg[i] = toupper((unsigned char)regname[i]); } if (i < 2 || regname[i]) { /* too short or longer than any of the names */ return 0; } - + len = i; + /* bisect */ l = 0; - r = sizeof (registers) / sizeof (*registers) - 1; + r = ARRAY_SIZE(registers) - 1; do { m = (l+r) >> 1; - for (i = 0; i < sizeof(reg); i++) { + for (i = 0; i < len; i++) { dir = (int)reg[i] - registers[m].name[i]; if (dir) { break; @@ -449,9 +682,9 @@ int DSP_GetRegisterAddress(const char *r /** - * Set given DSP register value + * Set given DSP register value, return false if unknown register given */ -void DSP_Disasm_SetRegister(char *arg, Uint32 value) +bool DSP_Disasm_SetRegister(const char *arg, Uint32 value) { #if ENABLE_DSP_EMU Uint32 *addr, mask, sp_value; @@ -464,7 +697,7 @@ void DSP_Disasm_SetRegister(char *arg, U value &= BITMASK(4); dsp_core.registers[DSP_REG_SSH] = dsp_core.stack[0][value]; dsp_core.registers[DSP_REG_SSL] = dsp_core.stack[1][value]; - return; + return true; } if (arg[1]=='S' || arg[1]=='s') { sp_value = dsp_core.registers[DSP_REG_SP] & BITMASK(4); @@ -476,7 +709,7 @@ void DSP_Disasm_SetRegister(char *arg, U dsp_core.registers[DSP_REG_SSH] = value & BITMASK(16); dsp_core.stack[0][sp_value] = value & BITMASK(16); } - return; + return true; } if (arg[2]=='L' || arg[2]=='l') { if (sp_value == 0) { @@ -486,7 +719,7 @@ void DSP_Disasm_SetRegister(char *arg, U dsp_core.registers[DSP_REG_SSL] = value & BITMASK(16); dsp_core.stack[1][sp_value] = value & BITMASK(16); } - return; + return true; } } } @@ -496,17 +729,13 @@ void DSP_Disasm_SetRegister(char *arg, U switch (bits) { case 32: *addr = value & mask; - return; + return true; case 16: *(Uint16*)addr = value & mask; - return; + return true; } - fprintf(stderr,"\tError, usage: reg=value where: \n\t \ - reg=A0-A2, B0-B2, X0, X1, Y0, Y1, \n\t \ - R0-R7, N0-N7, M0-M7, LA, LC, PC \n\t \ - SR, SP, OMR, SSH, SSL \n\t \ - and value is a hex value.\n"); #endif + return false; } /** @@ -534,73 +763,108 @@ void DSP_SsiWriteRxValue(Uint32 value) /** * Signal SSI clock tick to DSP */ -void DSP_SsiReceiveSerialClock(void) + +void DSP_SsiReceive_SC0(void) { #if ENABLE_DSP_EMU - dsp_core_ssi_receive_serial_clock(&dsp_core); + dsp_core_ssi_Receive_SC0(); #endif } -void DSP_SsiReceive_SC2(Uint32 FrameCounter) +void DSP_SsiTransmit_SC0(void) { #if ENABLE_DSP_EMU - dsp_core_ssi_receive_SC2(&dsp_core, FrameCounter); #endif } -/** - * Hardware IO address read by CPU - */ -static Uint8 DSP_handleRead(Uint32 addr) +void DSP_SsiReceive_SC1(Uint32 FrameCounter) { - Uint8 value; #if ENABLE_DSP_EMU - value = dsp_core_read_host(&dsp_core, addr-DSP_HW_OFFSET); -#else - /* this value prevents TOS from hanging in the DSP init code */ - value = 0xff; + dsp_core_ssi_Receive_SC1(FrameCounter); #endif +} - Dprintf(("HWget_b(0x%08x)=0x%02x at 0x%08x\n", addr, value, m68k_getpc())); - return value; +void DSP_SsiTransmit_SC1(void) +{ +#if ENABLE_DSP_EMU + Crossbar_DmaPlayInHandShakeMode(); +#endif } -/** - * Read access wrapper for ioMemTabFalcon - */ -void DSP_HandleReadAccess(void) +void DSP_SsiReceive_SC2(Uint32 FrameCounter) { - Uint32 a; - Uint8 v; - for (a = IoAccessBaseAddress; a < IoAccessBaseAddress+nIoMemAccessSize; a++) - { - v = DSP_handleRead(a); - IoMem_WriteByte(a, v); - } +#if ENABLE_DSP_EMU + dsp_core_ssi_Receive_SC2(FrameCounter); +#endif +} + +void DSP_SsiTransmit_SC2(Uint32 frame) +{ +#if ENABLE_DSP_EMU + Crossbar_DmaRecordInHandShakeMode_Frame(frame); +#endif } +void DSP_SsiReceive_SCK(void) +{ +#if ENABLE_DSP_EMU + dsp_core_ssi_Receive_SCK(); +#endif +} + +void DSP_SsiTransmit_SCK(void) +{ +#if ENABLE_DSP_EMU +#endif +} /** - * Hardware IO address write by CPU + * Read access wrapper for ioMemTabFalcon (DSP Host port) + * DSP Host interface port is accessed by the 68030 in Byte mode. + * A move.w value,$ffA206 results in 2 bus access for the 68030. */ -static void DSP_handleWrite(Uint32 addr, Uint8 value) +void DSP_HandleReadAccess(void) { - Dprintf(("HWput_b(0x%08x,0x%02x) at 0x%08x\n", addr, value, m68k_getpc())); + Uint32 addr; + Uint8 value; + bool multi_access = false; + + for (addr = IoAccessBaseAddress; addr < IoAccessBaseAddress+nIoMemAccessSize; addr++) + { #if ENABLE_DSP_EMU - dsp_core_write_host(&dsp_core, addr-DSP_HW_OFFSET, value); + value = dsp_core_read_host(addr-DSP_HW_OFFSET); +#else + /* this value prevents TOS from hanging in the DSP init code */ + value = 0xff; #endif + if (multi_access == true) + M68000_WaitState(4); + multi_access = true; + + Dprintf(("HWget_b(0x%08x)=0x%02x at 0x%08x\n", addr, value, m68k_getpc())); + IoMem_WriteByte(addr, value); + } } /** - * Write access wrapper for ioMemTabFalcon + * Write access wrapper for ioMemTabFalcon (DSP Host port) + * DSP Host interface port is accessed by the 68030 in Byte mode. + * A move.w value,$ffA206 results in 2 bus access for the 68030. */ void DSP_HandleWriteAccess(void) { - Uint32 a; - Uint8 v; - for (a = IoAccessBaseAddress; a < IoAccessBaseAddress+nIoMemAccessSize; a++) + Uint32 addr; + bool multi_access = false; + + for (addr = IoAccessBaseAddress; addr < IoAccessBaseAddress+nIoMemAccessSize; addr++) { - v = IoMem_ReadByte(a); - DSP_handleWrite(a,v); +#if ENABLE_DSP_EMU + Uint8 value = IoMem_ReadByte(addr); + Dprintf(("HWput_b(0x%08x,0x%02x) at 0x%08x\n", addr, value, m68k_getpc())); + dsp_core_write_host(addr-DSP_HW_OFFSET, value); +#endif + if (multi_access == true) + M68000_WaitState(4); + multi_access = true; } }