From 0293d194fc3b478562ff64ed7f3eb6438e5f29db Mon Sep 17 00:00:00 2001 From: Toni Wilen Date: Sun, 17 Sep 2023 18:00:26 +0300 Subject: [PATCH] DSP3210 --- a2091.cpp | 25 + devices.cpp | 7 + dsp3210/DSP3210_emulation.cpp | 2585 +++++++++++++++++ dsp3210/DSP3210_emulation.h | 81 + dsp3210/dsp_glue.cpp | 353 +++ dsp3210/dsp_glue.h | 7 + expansion.cpp | 9 + gayle.cpp | 20 +- include/rommgr.h | 1 + od-win32/sysconfig.h | 1 + od-win32/win32.cpp | 5 + od-win32/winuae_msvc15/winuae_msvc.vcxproj | 2 + .../winuae_msvc15/winuae_msvc.vcxproj.filters | 9 + 13 files changed, 3103 insertions(+), 2 deletions(-) create mode 100644 dsp3210/DSP3210_emulation.cpp create mode 100644 dsp3210/DSP3210_emulation.h create mode 100644 dsp3210/dsp_glue.cpp create mode 100644 dsp3210/dsp_glue.h diff --git a/a2091.cpp b/a2091.cpp index fb76d981..bb6b1220 100644 --- a/a2091.cpp +++ b/a2091.cpp @@ -45,6 +45,7 @@ #include "cpuboard.h" #include "rtc.h" #include "devices.h" +#include "dsp3210/dsp_glue.h" #define DMAC_8727_ROM_VECTOR 0x8000 #define CDMAC_ROM_VECTOR 0x2000 @@ -3625,6 +3626,12 @@ static void mbdmac_write_word (struct wd_state *wd, uae_u32 addr, uae_u32 val) case 0x46: wdscsi_put(&wd->wc, wd, val); break; + case 0x5e: + case 0x80: + if (is_dsp_installed) { + dsp_write(val); + } + break; } } @@ -3645,6 +3652,12 @@ static void mbdmac_write_byte (struct wd_state *wd, uae_u32 addr, uae_u32 val) case 0x47: wdscsi_put (&wd->wc, wd, val); break; + case 0x5f: + case 0x80: + if (is_dsp_installed) { + dsp_write(val); + } + break; default: if (addr & 1) mbdmac_write_word (wd, addr, val); @@ -3711,6 +3724,12 @@ static uae_u32 mbdmac_read_word (struct wd_state *wd, uae_u32 addr) case 0x46: v = wdscsi_get(&wd->wc, wd); break; + case 0x5e: + case 0x80: + if (is_dsp_installed) { + v = dsp_read(); + } + break; } #if A3000_DEBUG_IO > 1 write_log (_T("DMAC_WREAD %08X=%04X PC=%X\n"), vaddr, v & 0xffff, M68K_GETPC); @@ -3741,6 +3760,12 @@ static uae_u32 mbdmac_read_byte (struct wd_state *wd, uae_u32 addr) if (!(addr & 1)) v >>= 8; break; + case 0x5f: + case 0x80: + if (is_dsp_installed) { + v = dsp_read(); + } + break; } #if A3000_DEBUG_IO > 1 write_log (_T("DMAC_BREAD %08X=%02X PC=%X\n"), vaddr, v & 0xff, M68K_GETPC); diff --git a/devices.cpp b/devices.cpp index 1473677e..5c111794 100644 --- a/devices.cpp +++ b/devices.cpp @@ -63,6 +63,7 @@ #ifdef RETROPLATFORM #include "rp.h" #endif +#include "dsp3210/dsp_glue.h" #define MAX_DEVICE_ITEMS 64 @@ -438,6 +439,9 @@ void devices_pause(void) { #ifdef WITH_PPC uae_ppc_pause(1); +#endif +#ifdef WITH_DSP + dsp_pause(1); #endif blkdev_entergui(); #ifdef RETROPLATFORM @@ -455,6 +459,9 @@ void devices_unpause(void) #endif #ifdef WITH_PPC uae_ppc_pause(0); +#endif +#ifdef WITH_DSP + dsp_pause(0); #endif pausevideograb(0); ethernet_pause(0); diff --git a/dsp3210/DSP3210_emulation.cpp b/dsp3210/DSP3210_emulation.cpp new file mode 100644 index 00000000..99a0dc93 --- /dev/null +++ b/dsp3210/DSP3210_emulation.cpp @@ -0,0 +1,2585 @@ + +#include "stdlib.h" +#include "stdint.h" +#include "math.h" + +#include "DSP3210_emulation.h" + +extern void write_log(const char *, ...); +extern void activate_debugger(void); + +/* Typedefs */ +typedef union +{ + int32_t i; + float f; + +} intfloat; + +/* Variable declarations */ +static int32_t latency3[2][2]; //ticks to execution, PC address +static int32_t K_val = -1; +static int32_t loopcount = 0; +static int32_t loopstart = 0; +static int32_t bio6, bio7; //for M68k interrupts + +//externally used +int32_t DSP_reg_r[25]; +int32_t DSP_io_r[16]; +int32_t DSP_reg_irsh; //shadow instruction register +char DSP_irsh_flag; //1 indicates instruction in irsh to be executed +int32_t DSP_irsh_addr; +int32_t DSP_irsh_pcw; +float DSP_reg_a[4]; +float DSP_history_a[5][5]; +uint16_t DSP_history_CC[5]; +int32_t DSP_history_mem[5][5]; +void *DSP_onboard_RAM; +unsigned char DSP_onboard_ROM[]; +void *DSP_MMIO; + +/* Defines */ +#define CC DSP_io_r[0] +#define reg_evtp DSP_reg_r[22] +#define reg_PC DSP_reg_r[23] +#define reg_pcsh DSP_reg_r[24] +#define reg(val) DSP_reg_r[DSP_regno(val)] +#define regS(val) (int16_t)(reg(val) & 0xFFFF) +#define io(val) DSP_io_r[DSP_regno(val)] +#define io_emr DSP_io_r[8] //16 bit +#define io_pcw DSP_io_r[12] //16 bit +#define io_dauc DSP_io_r[14] //8 bit + +//CAU field definitions +#define Wfield(inst) (inst&0x00E00000)>>21 +#define RPfield(inst) (inst&0xF800)>>11 +#define RIfield(inst) (inst&0x1F) +#define RHfield(inst) (inst&0x1F0000)>>16 +#define RDfield(inst) (inst&0x03E00000)>>21 +#define RSfield(inst) (inst&0x001F0000)>>16 +#define Nfield(inst) (inst&0xFFFF) +#define NEfield(inst) (inst&0x1FE00000)>>21 +#define FCAUfield(inst) (inst&0x01E00000)>>21 +#define Cfield(inst) (inst&0x000007E0)>>5 +#define Cgotofield(inst) (inst&0x07E00000)>>21 +#define RLfield(inst) Nfield(inst) +#define RS1field(inst) RPfield(inst) +#define RS2field(inst) RIfield(inst) +#define RS3field(inst) RSfield(inst) +#define RBfield(inst) RSfield(inst) +#define RMfield(inst) RDfield(inst) + +//DAU field definitions +#define Mfield(inst) (inst&0x1C000000)>>26 +#define Ffield(inst) (inst&0x01000000)>>24 +#define Sfield(inst) (inst&0x00800000)>>23 +#define NDAUfield(inst) (inst&0x00600000)>>21 +#define Xfield(inst) (inst&0x001FC000)>>14 +#define Yfield(inst) (inst&0x00003F80)>>7 +#define Zfield(inst) (inst&0x0000007F) +#define Gfield(inst) (inst&0x07800000)>>23 + +#define FLOAT_TO_INT(x) ((x)>=0?(int32_t)((x)+0.5):(int32_t)((x)-0.5)) +#define Ssign(x) (Sfield(x)==0?1:-1) +#define Fsign(x) (Ffield(x)==0?1:-1) + +//condition codes +#define CCn 1 +#define CCz 2 +#define CCv 4 +#define CCc 8 +#define CCN 16 +#define CCZ 32 +#define CCU 64 +#define CCV 128 + +#define CCnf (CC&CCn) +#define CCzf (CC&CCz) +#define CCvf (CC&CCv) +#define CCcf (CC&CCc) +#define CCNf (CC&CCN) +#define CCZf (CC&CCZ) +#define CCUf (CC&CCU) +#define CCVf (CC&CCV) + +//latency timing +#define DSP_reg_atime 2 + +//for 64 bit manipulations +#define hi32 ~(int64_t)0xFFFFFFFF +#define bt32 (int64_t)0x80000000 +#define hi48 ~(int64_t)0xFFFF +#define bt16 (int64_t)0x8000 +static const double max_pos_float = (2-2^-31)*2^127; +static const double max_neg_float = -2*2^127; +static const double min_pos_float = 2^-127; +static const double min_neg_float = (-1+2^-31)*2^-127; + +//internal ROM/RAM locations +#define map0_ROM_start 0x50030000 +#define map0_ROM_end (map0_ROM_start + 0x3FF) +#define map0_RAM_start (map0_ROM_start + 0xE000) +#define map0_RAM_end (map0_ROM_start + 0xFFFF) +#define map0_MMIO_start (map0_ROM_start + 0x400) +#define map0_MMIO_end (map0_ROM_start + 0x7FF) +#define map1_ROM_start 0 +#define map1_ROM_end (map1_ROM_start + 0x3FF) +#define map1_RAM_start (map1_ROM_start + 0xE000) +#define map1_RAM_end (map1_ROM_start + 0xFFFF) +#define map1_MMIO_start (map1_ROM_start + 0x400) +#define map1_MMIO_end (map1_ROM_start + 0x7FF) + +/* Function declarations */ +static void doinst(int32_t addr); +static int32_t DAUXYZ(int32_t incode, int32_t field, int32_t *fld2); +static int32_t GetXYfield(int32_t fld1,int32_t fld2,int32_t incode); +static void DoLat3(int32_t pcval); +static void SetZfield(int32_t fld1, int32_t fld2, int32_t temp); +static void doDAU5(int32_t incode); +static float Mval(int32_t incode); +static float SetCC(double dtemp); +static int32_t SetCCCAU(int64_t res, int32_t input); +static int32_t SetCCCAU16(int64_t res, int32_t input); +static void SetCCnzCAU(int32_t res); +static int32_t TestCfield(int32_t code); +static float round_dsp(float num); +static int32_t bitreverse(int32_t n, int32_t bits); +static void DSP_exception_illegal(); +static void DSP_exception_UOflow(); +static void DSP_exception_NaN(); +static void DSP_undefined(); +static void DSP_breakpoint(); +static void DSP_check_interrupt(int32_t value, int32_t bitno); + +//externally used +int32_t DSP_swapl(int32_t a); +int16_t DSP_swapw(int16_t a); +int32_t DSP_regno(int32_t r); +int32_t DSP_float(float f); +int32_t DSP_negfloat(int32_t f); +int32_t DSP_dsp2ieee(int32_t f); +int32_t DSP_get_long(int32_t addr); +void DSP_set_long(int32_t addr, int32_t value); +int16_t DSP_get_short(int32_t addr); +void DSP_set_short(int32_t addr, int16_t value); +char DSP_get_char(int32_t addr); +void DSP_set_char(int32_t addr, char value); + +/********************************************************/ +/* Initialise the DSP emulator */ +/* */ +/********************************************************/ +void DSP_init_emu () +{ + DSP_onboard_RAM = malloc(8192); //8k onboard RAM + DSP_MMIO = malloc(0x800); + reg_PC = 0; + return; +} + +/********************************************************/ +/* Shut down the DSP emulator */ +/* */ +/********************************************************/ +void DSP_shutdown_emu () +{ + free(DSP_MMIO); + free(DSP_onboard_RAM); + return; +} + +/********************************************************/ +/* Trigger DSP reset */ +/* */ +/********************************************************/ +void DSP_reset() +{ + int32_t i; + for(i=0; i<22; i++) DSP_reg_r[i]=0; + for(i=0; i<4; i++) DSP_reg_a[i]=0; + latency3[0][0]=0; + latency3[1][0]=0; + reg_pcsh = 0; + + //The Information Manual only mentions the following registers being initialised + reg_evtp = 0; + DSP_reg_r[20] = reg_PC; + reg_PC = 0; + io_dauc = 0; + DSP_io_r[12] = 0x0F8F; //0b0000111110001111; bio 4,5 = 0 , bio 6,7 = 1, set pcw reg + io_emr = 0; + + //other MMUIO regs are set here too - see 7-11 + bio6 = 1; + bio7 = 1; + DSP_irsh_flag = 0; + return; +} + +bool DSP_int0_masked() +{ + return (io_emr & 0x0100) == 0; +} + +bool DSP_int1_masked() +{ + return (io_emr & 0x8000) == 0; +} + +/********************************************************/ +/* Trigger an interrupt level 0 */ +/* */ +/********************************************************/ +bool DSP_int0() +{ + if(!(io_emr & 0x0100)) + return false; //return if int0 masked out + + //save chip state: DO loop status, a0-a3, dauc + //not implemented yet + reg_pcsh = reg_PC; //save PC + reg_PC = reg_evtp + 8*8; //INT0 entry + DSP_irsh_flag = 2; //no more waiting, execute interrupt + return true; +} + +/********************************************************/ +/* Trigger an interrupt level 1 */ +/* */ +/********************************************************/ +bool DSP_int1() +{ + if(!(io_emr & 0x8000)) + return false; //return if int1 masked out + + //save chip state: DO loop status, a0-a3, dauc + //not implemented yet + reg_pcsh = reg_PC; //save PC + reg_PC = reg_evtp + 8*15; //INT1 entry + DSP_irsh_flag = 2; //no more waiting, execut interrupt + return true; +} + +/********************************************************/ +/* DSP reaches a breakpoint */ +/* */ +/********************************************************/ +void DSP_breakpoint() +{ + //It's unspecified in the DSP3210 Instruction Manual + //what actually happens on a 'bkpt' instruction + //In fact, the instruction isn't even listed in the + //instruction set! It only appears in the listing for + //the ROM code in Appendix A + + return; +} + +/********************************************************/ +/* Execute a single DSP instruction, allowing for */ +/* instruction and memory latencies */ +/********************************************************/ + +void DSP_execute_insn () +{ + int32_t i,j; + DSP_history_mem[2][0] = 0; //no mem to write by default + doinst(reg_PC); + + //update history of mem writes - latency 1 + for(j=4;j>0;j--) { + DSP_history_mem[0][j] = DSP_history_mem[0][j-1]; //location + DSP_history_mem[1][j] = DSP_history_mem[1][j-1]; //value + DSP_history_mem[2][j] = DSP_history_mem[2][j-1]; //flag for delayed write + } + switch(DSP_history_mem[2][4]) + { + case 1: + //do write + //*(int32_t *)DSP_history_mem[0][4]=DSP_history_mem[1][4]; //dummy + DSP_set_long(DSP_history_mem[0][4], DSP_history_mem[1][4]); + break; + + case 2: + //*(int16_t *)DSP_history_mem[0][4]=DSP_history_mem[1][4]; //dummy + DSP_set_short(DSP_history_mem[0][4], DSP_history_mem[1][4]); + break; + + default: + break; + } + + //update history of a registers - latency 2 + for(i=0;i<4;i++) { //step through registers + for(j=4;j>0;j--) + DSP_history_a[i][j] = DSP_history_a[i][j-1]; //age each entry + DSP_history_a[i][0] = DSP_reg_a[i]; //insert new aN values + } + + //update history of CC - latency 4 + for(j=4;j>0;j--) + DSP_history_CC[j] = DSP_history_CC[j-1]; + DSP_history_CC[0] = CC; + DSP_io_r[15] = ((DSP_io_r[15] << 1) | (CCNf >> 4)) &0x3F; //update ctr + + //deal with latency 3 - delayed jumps + if(latency3[0][0]) + { //we have a latent jump in the queue + if(latency3[0][0]--==1) //decrease counter + reg_PC = latency3[0][1]; //process the jump + } + if(latency3[1][0]) + { //latent jump in 2nd slot + if(latency3[1][0]--==1) + reg_PC = latency3[1][1]; //process the jump + } + + //do loop + if(reg_PC == K_val) { + loopcount--; + if(loopcount>=0) reg_PC = loopstart; + } +} + +/********************************************************/ +/* Main code to execute a single DSP instruction */ +/********************************************************/ + +void doinst(int32_t addr) +{ + int32_t valX, valY, fld1, fld2, fld3, fld4,value,tempc,pinc; + float ftemp,fvalX,fvalY; + float delayvalX, delayvalY, delayM; + double dtemp; + int64_t val64; + intfloat conv; + int32_t incode; + int32_t baseaddr; + + if(DSP_irsh_flag == 3) return; //nothing to do while in waiti + if(DSP_irsh_flag == 4) DSP_irsh_flag -= 1; //execute one more instruction + //int32_t incode = swapl(*(amiga_mem_base + addr)); + if(DSP_irsh_flag == 1) { + DSP_irsh_flag = 0; + incode = DSP_reg_irsh; + reg_PC = reg_PC - 4; //undo the PC increment coming up + } else { + //DSP_irsh_flag -= 1; + incode = DSP_swapl(DSP_get_long(addr)); + } + + switch((incode & 0xE0000000)>>29) + { + case 1: + case 2: + case 3: + if((incode & 0xF8000000)>>27 != 15) { + //do some preliminaries if DAU 1-4 + fld1=DAUXYZ(incode,1,&fld2); //get Xfield values + valX=GetXYfield(fld1,fld2,incode); //read value from Xfield reg and post inc + fld3=DAUXYZ(incode,2,&fld4); //get Yfield values + valY=GetXYfield(fld3,fld4,incode); //read value from Yfield reg and post inc + + //convert valX,Y to floats + //*(int32_t *)&fvalX=swapl(valX); //''' + conv.i = DSP_swapl(valX); + fvalX = conv.f; + + //*(int32_t *)&fvalY=swapl(valY); + conv.i = DSP_swapl(valY); + fvalY = conv.f; + + //factor in delayed a reg updates + if(!fld1&&fld2<4) delayvalX = DSP_history_a[fld2][DSP_reg_atime]; else delayvalX = fvalX; + if(!fld3&&fld4<4) delayvalY = DSP_history_a[fld4][DSP_reg_atime]; else delayvalY = fvalY; + + if(Mfield(incode)<4) delayM = DSP_history_a[Mfield(incode)][DSP_reg_atime]; else delayM = Mval(incode); + //can now use delayvals as multiplier inputs + } + break; + } + + reg_PC=reg_PC+4; + switch((incode & 0xE0000000)>>29) + { + case 1: + //DAU 1 or 4 instruction + //if(Mfield(incode)!=6) + switch(Mfield(incode)) + { + case 6: //DAU4 + dtemp = Fsign(incode)*fvalY+Ssign(incode)*fvalX; + ftemp = SetCC(dtemp); + DSP_reg_a[NDAUfield(incode)]=ftemp; //set aN to value + value = valY; //Zfield will be set to Yfield, if required + + fld1=DAUXYZ(incode,3,&fld2); //get Zfield values + SetZfield(fld1, fld2, DSP_swapl(value)); //and set Zfield if needed + break; + + case 7: + DSP_exception_illegal(); + break; + + default: + //DAU1 + dtemp = Fsign(incode)*fvalY+Ssign(incode)*delayM*delayvalX; + ftemp = SetCC(dtemp); + DSP_reg_a[NDAUfield(incode)]=ftemp; //set aN to value + //value = *(int32_t *)&ftemp; //convert to int ''' + conv.f = ftemp; + value = conv.i; + + fld1=DAUXYZ(incode,3,&fld2); //get Zfield values + SetZfield(fld1, fld2, DSP_swapl(value)); //and set Zfield if needed + break; + } + break; + + case 2: + //DAU 2 instruction + switch(Mfield(incode)) + { + case 6: + case 7: + DSP_exception_illegal(); + break; + + default: + dtemp = Fsign(incode)*Mval(incode)+Ssign(incode)*delayvalY*delayvalX; + ftemp = SetCC(dtemp); + DSP_reg_a[NDAUfield(incode)]=ftemp; //set aN to value + value = valY; //Zfield will be set to Yfield, if required + + fld1=DAUXYZ(incode,3,&fld2); //get Zfield values + SetZfield(fld1, fld2, DSP_swapl(value)); //and set Zfield if needed + break; + } + break; + + case 3: + //DAU 3 or 5 instruction + if(Mfield(incode)!=6 && Mfield(incode)!=7) + { //DAU 3 + dtemp = Fsign(incode)*Mval(incode)+Ssign(incode)*delayvalY*delayvalX; + ftemp = SetCC(dtemp); + DSP_reg_a[NDAUfield(incode)]=ftemp; //set aN to value + //value = *(int32_t *)&ftemp; //convert to int ''' + conv.f = ftemp; + value = conv.i; + + fld1=DAUXYZ(incode,3,&fld2); //get Zfield values + SetZfield(fld1, fld2, DSP_swapl(value)); //and set Zfield if needed + } else { //DAU 5 + doDAU5(incode); + } + break; + + case 5: + //Unconditional branch instruction GOTO rB+M + DoLat3((uint32_t)((NEfield(incode)<<16)|Nfield(incode))+4); + //latency 3! + break; + + case 6: + //24 bit immediate load instruction SET24 + reg(RSfield(incode)) = (uint32_t)((NEfield(incode)<<16)|Nfield(incode)); + break; + + case 7: + //call 24-bit immediate instruction CALL M,(rM) + reg(RSfield(incode)) = reg_PC+4; //return to the instruction after the latent one + DoLat3((uint32_t)((NEfield(incode)<<16)|Nfield(incode))+4); + //latency 3! + break; + + default: + switch((incode&0xF8000000)>>27) + { + case 0: //reserved + DSP_exception_illegal(); + break; + + case 16: + //conditional branch + switch(incode) + { + case 0x80000000: + //nop + reg_PC = reg_PC + 0; + break; + + case 0x803E0000: + //ireturn + DSP_irsh_flag = 1; + reg_PC = reg_pcsh; //jump execution to shadown PC + break; + + default: + if(TestCfield(Cgotofield(incode))) + { + DoLat3(reg(RBfield(incode))+(int16_t)Nfield(incode) + ((RBfield(incode)==15)?4:0)); + //if(RBfield(incode)==15) reg_PC+=4; //account for extra instr in pipeline + } + //latency 3! + break; + } + break; + + default: + switch((incode&0xFC000000)>>26) + { + case 2: //reserved + case 34: //reserved + DSP_exception_illegal(); + break; + + case 3: + //loop counter instruction GOTO-LOOP + reg(RMfield(incode))-=1; + if(reg(RMfield(incode))>=0) + { + DoLat3(reg(RBfield(incode)) + (int16_t)Nfield(incode) + ((RBfield(incode)==15)?4:0)); + //if(RBfield(incode)==15) reg_PC+=4; //account for extra instr in pipeline + } + break; + //latency 3!! + + case 35: + //DO loops + K_val = ((incode&0x3F800)>>9) + reg_PC + 4; + loopstart = reg_PC; + if((incode&0x02000000)>>25) + //reg + loopcount = reg(RS2field(incode)); + else + //immediate + loopcount = incode&0x7FF; + break; + + case 4: + //call reg with 16 bit N instruction CALL rB+N,(rM) + reg(RMfield(incode)) = reg_PC+4; //return to the instruction after the latent one + DoLat3(reg(RSfield(incode)) + (int16_t)Nfield(incode) + ((RSfield(incode)==15)?4:0)); + //if(RSfield(incode)==15) reg_PC+=4; //account for extra instr in pipeline + //latency 3! + break; + + case 36: + //SHIFT-OR + value = reg(RSfield(incode)) | (Nfield(incode)<<16); + reg(RDfield(incode)) = value; + SetCCnzCAU(value); + break; + + case 5: + //16-bit 3 operand add instruction ADD + value = reg(RS3field(incode)); + val64 = (int64_t)value + (int64_t)((int16_t)Nfield(incode)); + if(RS3field(incode)==15) //PC + val64+=4; //fudge + reg(RDfield(incode)) = SetCCCAU(val64,value); + break; + + case 37: + //32-bit 3 operand add instruction ADD + value = reg(RS3field(incode)); + val64 = (int64_t)value + (int64_t)Nfield(incode); + if(RS3field(incode)==15) //PC + val64+=4; //fudge + reg(RDfield(incode)) = SetCCCAU(val64,value); + + break; + + case 6: + //16-bit ALU instruction + if((incode&0x02000000)>>25) //indicates immediate + { + switch(FCAUfield(incode)) + { + case 7: //compare + value = regS(RBfield(incode)); + val64 = (int64_t)value - (int64_t)((int16_t)Nfield(incode)); + value = SetCCCAU16(val64,value); + break; + + case 15: //and, no store + value = regS(RBfield(incode))&((int16_t)Nfield(incode)); + SetCCnzCAU(value); + break; + + case 1: //left shift + value = regS(RBfield(incode)) << (int16_t)Nfield(incode); + reg(RBfield(incode)) = value&0xFFFF; + SetCCnzCAU(value); + break; + + case 12: //logical right shift + value = (int32_t)(((uint32_t)regS(RBfield(incode))) >> (int16_t)Nfield(incode)); + reg(RBfield(incode)) = value&0xFFFF; + SetCCnzCAU(value); + break; + + case 13: //arithmetic right shift + value = regS(RBfield(incode)) >> (int16_t)Nfield(incode); + reg(RBfield(incode)) = value&0xFFFF; + SetCCnzCAU(value); + break; + + case 2: // subtract N-rD + value = (int16_t)Nfield(incode); + val64 = (int64_t)value - (int64_t)regS(RBfield(incode)); + reg(RBfield(incode)) = SetCCCAU16(val64,value); + break; + + case 4: // subtract rD-N + value = regS(RBfield(incode)); + val64 = (int64_t)value - (int64_t)((int16_t)Nfield(incode)); + reg(RBfield(incode)) = SetCCCAU16(val64,value); + break; + + case 3: // reverse carry add + value = (int16_t)bitreverse(regS(RBfield(incode)), 16); + value += (int16_t)bitreverse((int32_t)Nfield(incode), 16); + value = (int16_t)bitreverse(value, 16); + reg(RBfield(incode)) = value; + SetCCnzCAU(value); + break; + + case 6: //and with complement + case 9: //rotate right + case 11: //rotate left + //not with immediate operand + DSP_undefined(); + break; + + case 8: //exclusive or + value = regS(RBfield(incode))^(int16_t)Nfield(incode); + reg(RBfield(incode)) = value; + SetCCnzCAU(value); + break; + + case 10: //or + value = regS(RBfield(incode))|(int16_t)Nfield(incode); + reg(RBfield(incode)) = value; + SetCCnzCAU(value); + break; + + case 14: //and + value = regS(RBfield(incode))&(int16_t)Nfield(incode); + reg(RBfield(incode)) = value; + SetCCnzCAU(value); + break; + + default: //Fcode 5 is reserved + DSP_undefined(); + break; + } + } else { //Reg source + if(TestCfield(Cfield(incode))) //ie not always false + { + switch(FCAUfield(incode)) + { + case 7: //compare + value = regS(RS1field(incode)); + val64 = (int64_t)value - (int64_t)regS(RS2field(incode)); + value = SetCCCAU16(val64, value); + break; + + case 15: //and, no store + value = regS(RS1field(incode))®S(RS2field(incode)); + SetCCnzCAU(value); + break; + + case 0: //add + value = regS(RS1field(incode)); + val64 = (int64_t)value + (int64_t)regS(RS2field(incode)); + reg(RBfield(incode)) = SetCCCAU16(val64, value); + break; + + case 1: //left shift + //no test of RS2>26 + //unclear what happens if RS2=22! + if(RS2field(incode)==23) //+n + value = regS(RS1field(incode))<<1; + else + value = regS(RS1field(incode))<>1); + else + value = (int32_t)(((uint32_t)regS(RS1field(incode)))>>reg(RS2field(incode))); + reg(RBfield(incode)) = value&0xFFFF; + SetCCnzCAU(value); + break; + + case 13: //arithmetic right shift + if(RS2field(incode)==23) //+n + value = regS(RS1field(incode))>>1; + else + value = regS(RS1field(incode))>>reg(RS2field(incode)); + reg(RBfield(incode)) = value&0xFFFF; + SetCCnzCAU(value); + break; + + case 2: // subtract N-rD + value = regS(RS1field(incode)); + val64 = (int64_t)value - (int64_t)regS(RS2field(incode)); + reg(RBfield(incode)) = SetCCCAU16(val64, value); + break; + + case 4: // subtract rD-N + value = regS(RS1field(incode)); + val64 = (int64_t)value - (int64_t)regS(RS2field(incode)); + reg(RBfield(incode)) = SetCCCAU16(val64, value); + break; + + case 3: // reverse carry add + value = (int16_t)bitreverse(regS(RS1field(incode)), 16); + value += (int16_t)bitreverse(regS(RS2field(incode)), 16); + value = (int16_t)bitreverse(value, 16); + reg(RBfield(incode)) = value; + SetCCnzCAU(value); + break; + + case 6: //and with complement + value = regS(RS1field(incode))&~regS(RS2field(incode)); + reg(RBfield(incode)) = value; + SetCCnzCAU(value); + break; + + case 9: //rotate right through carry + tempc = CCcf<<12; //shift c (bit 3) to bit 15 + if(reg(RS1field(incode))&1) { + value = (int32_t)((((uint16_t)regS(RS1field(incode)))>>1)|tempc); + CC|=CCc; //set c + } else { + value = (int32_t)((((uint16_t)regS(RS1field(incode)))>>1)|tempc); + CC&=~CCc; //clear c + } + if(!value) CC|=CCz; else CC&=~CCz; //set/clear z + if(value<0) CC|=CCn; else CC&=~CCn; //set/clear n + CC&=~CCv; //clear v + break; + + case 11: //rotate left + tempc = CCcf>>3; //shift c to bit 0 + value = regS(RS1field(incode)); + val64 = (int64_t)value << 1; + value = SetCCCAU16(val64,value); + value |= tempc; + break; + + case 8: //exclusive or + value = regS(RS1field(incode))^regS(RS2field(incode)); + reg(RBfield(incode)) = value; + SetCCnzCAU(value); + break; + + case 10: //or + value = regS(RS1field(incode))|regS(RS2field(incode)); + reg(RBfield(incode)) = value; + SetCCnzCAU(value); + break; + + case 14: //and + value = regS(RS1field(incode))®S(RS2field(incode)); + reg(RBfield(incode)) = value; + SetCCnzCAU(value); + break; + + default: //Fcode 5 is reserved + DSP_undefined(); + break; + } + } + } + break; + + case 38: + //32-bit ALU instruction, format 6b,6d + if((incode&0x02000000)>>25) //indicates immediate + { + switch(FCAUfield(incode)) + { + case 7: //compare + value = reg(RBfield(incode)); + val64 = (int64_t)value - (int64_t)Nfield(incode); + value = SetCCCAU(val64,value); + break; + + case 15: //and, no store + value = reg(RBfield(incode))&Nfield(incode); + SetCCnzCAU(value); + break; + + case 1: //left shift + value = reg(RBfield(incode)) << Nfield(incode); + reg(RBfield(incode)) = value; + SetCCnzCAU(value); + break; + + case 12: //logical right shift + value = (int32_t)(((uint32_t)reg(RBfield(incode))) >> Nfield(incode)); + reg(RBfield(incode)) = value; + SetCCnzCAU(value); + break; + + case 13: //arithmetic right shift + value = reg(RBfield(incode)) >> Nfield(incode); + reg(RBfield(incode)) = value; + SetCCnzCAU(value); + break; + + case 2: // subtract N-rD + value = Nfield(incode); + val64 = (int64_t)value - (int64_t)reg(RBfield(incode)); + reg(RBfield(incode)) = SetCCCAU(val64,value); + break; + + case 4: // subtract rD-N + value = reg(RBfield(incode)); + val64 = (int64_t)value - (int64_t)Nfield(incode); + reg(RBfield(incode)) = SetCCCAU(val64,value); + break; + + case 3: // reverse carry add + //not supported + value = bitreverse(regS(RBfield(incode)), 32); + value += bitreverse((int32_t)Nfield(incode), 32); + value = bitreverse(value, 32); + reg(RBfield(incode)) = value; + SetCCnzCAU(value); + break; + + case 6: //and with complement + case 9: //rotate right + case 11: //rotate left + //not with immediate operand + DSP_undefined(); + break; + + case 8: //exclusive or + value = reg(RBfield(incode))^Nfield(incode); + reg(RBfield(incode)) = value; + SetCCnzCAU(value); + break; + + case 10: //or + value = reg(RBfield(incode))|Nfield(incode); + reg(RBfield(incode)) = value; + SetCCnzCAU(value); + break; + + case 14: //and + value = reg(RBfield(incode))&Nfield(incode); + reg(RBfield(incode)) = value; + SetCCnzCAU(value); + break; + + default: //Fcode 5 is reserved + DSP_undefined(); + break; + } + } else { + if(TestCfield(Cfield(incode))) //ie not always false + { + switch(FCAUfield(incode)) + { + case 7: //compare + value = reg(RS1field(incode)); + val64 = (int64_t)value - (int64_t)reg(RS2field(incode)); + value = SetCCCAU(val64, value); + break; + + case 15: //and, no store + value = reg(RS1field(incode))®(RS2field(incode)); + SetCCnzCAU(value); + break; + + case 0: //add + value = reg(RS1field(incode)); + val64 = (int64_t)value + (int64_t)reg(RS2field(incode)); + reg(RBfield(incode)) = SetCCCAU(val64, value); + break; + + case 1: //left shift + if(RS2field(incode)==23) //+n + value = reg(RS1field(incode))<<1; + else + value = reg(RS1field(incode))<>1); + else + value = (int32_t)(((uint32_t)reg(RS1field(incode)))>>reg(RS2field(incode))); + reg(RBfield(incode)) = value; + SetCCnzCAU(value); + break; + + case 13: //arithmetic right shift + if(RS2field(incode)==23) //+n + value = reg(RS1field(incode))>>1; + else + value = reg(RS1field(incode))>>reg(RS2field(incode)); + reg(RBfield(incode)) = value; + SetCCnzCAU(value); + break; + + case 2: // subtract N-rD + value = reg(RS1field(incode)); + val64 = (int64_t)value - (int64_t)reg(RS2field(incode)); + reg(RBfield(incode)) = SetCCCAU(val64, value); + break; + + case 4: // subtract rD-N + value = reg(RS1field(incode)); + val64 = (int64_t)value - (int64_t)reg(RS2field(incode)); + reg(RBfield(incode)) = SetCCCAU(val64, value); + break; + + case 3: // reverse carry add + value = bitreverse(regS(RS1field(incode)), 32); + value += bitreverse(regS(RS2field(incode)), 32); + value = bitreverse(value, 32); + reg(RBfield(incode)) = value; + SetCCnzCAU(value); + break; + + case 6: //and with complement + value = reg(RS1field(incode))&~reg(RS2field(incode)); + reg(RBfield(incode)) = value; + SetCCnzCAU(value); + break; + + case 9: //rotate right through carry + tempc = CCcf<<28; //shift c (bit 3) to bit 31 + if(reg(RS1field(incode))&1) { + value = (int32_t)(((uint32_t)reg(RS1field(incode)))>>1); + CC|=CCc; //set c + } else { + value = (int32_t)(((uint32_t)reg(RS1field(incode)))>>1); + CC&=~CCc; //clear c + } + value |= tempc; //old c becomes bit 31 + if(!value) CC|=CCz; else CC&=~CCz; //set/clear z + if(value<0) CC|=CCn; else CC&=~CCn; //set/clear n + CC&=~CCv; //clear v + break; + + case 11: //rotate left + tempc = CCcf>>3; //shift c to bit 0 + value = reg(RS1field(incode)); + val64 = ((int64_t)value) << 1; + value = SetCCCAU(val64,value); + value |= tempc; + break; + + case 8: //exclusive or + value = reg(RS1field(incode))^reg(RS2field(incode)); + reg(RBfield(incode)) = value; + SetCCnzCAU(value); + break; + + case 10: //or + value = reg(RS1field(incode))|reg(RS2field(incode)); + reg(RBfield(incode)) = value; + SetCCnzCAU(value); + break; + + case 14: //and + value = reg(RS1field(incode))®(RS2field(incode)); + reg(RBfield(incode)) = value; + SetCCnzCAU(value); + break; + + default: //Fcode 5 is reserved + DSP_undefined(); + break; + } + } + } + break; + + case 7: + //move DA instruction LOAD/STORE rD=*L, *L=rS + //need to set upper 16 bits of address if necessary to 0x5003 based on pcw[10] + //disables interrupts for one cycle + if(io_pcw & 0x0400) //pcw bit 10 + baseaddr = map1_ROM_start; + else + baseaddr = map0_ROM_start; + + if((incode&0x01000000)>>24) //From a reg + { + switch(Wfield(incode)) + { + case 0: //char + case 1: + DSP_set_char(baseaddr | RLfield(incode), DSP_swapl(reg(RHfield(incode))&0xFF)); + break; + + case 2: //short + case 3: + DSP_set_short(baseaddr | RLfield(incode), DSP_swapw(reg(RHfield(incode))&0xFFFF)); + break; + + case 4: //unsigned high char + DSP_set_char(baseaddr | RLfield(incode), DSP_swapl((reg(RHfield(incode))&0xFF00)>>8)<<8); + break; + + case 7: //long + DSP_set_long(baseaddr | RLfield(incode), DSP_swapl(reg(RHfield(incode)))); + break; + + default: + DSP_undefined(); + break; + } + + } else { //To a reg + switch(Wfield(incode)) + { + case 0: //unsigned char + reg(RHfield(incode)) = DSP_swapl((uint32_t)DSP_get_char(baseaddr | RLfield(incode))); + break; + + case 1: //char + reg(RHfield(incode)) = DSP_swapl((int32_t)DSP_get_char(baseaddr | RLfield(incode))); + break; + + case 2: //unsigned short + reg(RHfield(incode)) = DSP_swapl((uint32_t)DSP_get_short(baseaddr | RLfield(incode))); + break; + + case 3: //short + reg(RHfield(incode)) = DSP_swapl((int32_t)DSP_get_short(baseaddr | RLfield(incode))); + break; + + case 4: //unsigned high char + reg(RHfield(incode)) = DSP_swapl(((uint32_t)DSP_get_short(baseaddr | RLfield(incode)))<<8); + break; + + case 7: //long + reg(RHfield(incode)) = DSP_swapl(DSP_get_long(baseaddr | RLfield(incode))); + break; + + default: + DSP_undefined(); + break; + } + } + break; + + case 39: + //move IO/post inc/mem instruction + switch((incode&0x400)>>10) + { + case 0: //move post inc or mem i/o + switch((incode&0x02000000)>>25) + { + case 0: //LOAD/STORE rD=MEM, MEM=rS ie move post inc 7c + if((incode&0x01000000)>>24) //move from reg to mem + { + switch(Wfield(incode)) + { + case 0: //char + case 1: + //*((char *)amiga_mem_base+reg(RPfield(incode))) = swapl(reg(RHfield(incode))&0xFF); + DSP_set_char(reg(RPfield(incode)), DSP_swapl(reg(RHfield(incode))&0xFF)); + pinc=1; + break; + + case 2: //short + case 3: + //*((int16_t*)amiga_mem_base+((reg(RPfield(incode)))>>1)) = (swapw(reg(RHfield(incode))&0xFFFF)); + DSP_set_short(reg(RPfield(incode)), DSP_swapw(reg(RHfield(incode))&0xFFFF)); + pinc=2; + break; + + case 4: //unsigned high char + //*((char *)amiga_mem_base+reg(RPfield(incode))) = swapl((reg(RHfield(incode))&0xFF00)>>8)<<8; + DSP_set_char(reg(RPfield(incode)), DSP_swapl((reg(RHfield(incode))&0xFF00)>>8)<<8); + pinc=1; + break; + + case 7: //long + //*(amiga_mem_base+((reg(RPfield(incode)))>>2)) = swapl(reg(RHfield(incode))); + DSP_set_long(reg(RPfield(incode)), DSP_swapl(reg(RHfield(incode)))); + pinc=4; + break; + + default: + DSP_undefined(); + break; + } + //do post inc + switch(RIfield(incode)) + { + case 0: //no post inc + break; + + case 22: //post dec + reg(RPfield(incode))-=pinc; + break; + + case 23: //post inc + reg(RPfield(incode))+=pinc; + break; + + default: //RI + reg(RPfield(incode))+=reg(RIfield(incode)); + break; + } + } else { //move to reg from mem + switch(Wfield(incode)) + { + case 0: //unsigned char + //reg(RHfield(incode)) = swapl((uint32_t)(*((unsigned char *)amiga_mem_base+reg(RPfield(incode))))); + reg(RHfield(incode)) = DSP_swapl((uint32_t)DSP_get_char(reg(RPfield(incode)))); + pinc=1; + break; + + case 1: //char + //reg(RHfield(incode)) = swapl((int32_t)(*((char *)amiga_mem_base+reg(RPfield(incode))))); + reg(RHfield(incode)) = DSP_swapl((int32_t)DSP_get_char(reg(RPfield(incode)))); + pinc=1; + break; + + case 2: //unsigned short + //reg(RHfield(incode)) = swapl((uint32_t)(*((uint16_t *)amiga_mem_base+((reg(RPfield(incode)))>>1)))); + reg(RHfield(incode)) = DSP_swapl((uint32_t)DSP_get_short(reg(RPfield(incode)))); + pinc=2; + break; + + case 3: //short + //reg(RHfield(incode)) = swapl((int32_t)(*((int16_t *)amiga_mem_base+((reg(RPfield(incode)))>>1)))); + reg(RHfield(incode)) = DSP_swapl((int32_t)DSP_get_short(reg(RPfield(incode)))); + pinc=2; + break; + + case 4: //unsigned high char + //reg(RHfield(incode)) = swapl(((uint32_t)(*((unsigned char *)amiga_mem_base+reg(RPfield(incode)))))<<8); + reg(RHfield(incode)) = DSP_swapl(((uint32_t)DSP_get_short(reg(RPfield(incode))))<<8); + pinc=1; + break; + + case 7: //long + //reg(RHfield(incode)) = swapl(*(amiga_mem_base+((reg(RPfield(incode)))>>2))); + reg(RHfield(incode)) = DSP_swapl(DSP_get_long(reg(RPfield(incode)))); + pinc=4; + break; + + default: + DSP_undefined(); + break; + } + //do post inc + switch(RIfield(incode)) + { + case 0: //no post inc + break; + + case 22: //post dec + reg(RPfield(incode))-=pinc; + break; + + case 23: //post inc + reg(RPfield(incode))+=pinc; + break; + + default: //RI + reg(RPfield(incode))+=reg(RIfield(incode)); + break; + } + } + break; //end 7c + + case 1: //move io 7d instruction + switch(RHfield(incode)) + { + case 0: //ps + case 8: //emr + case 12: //pcw + case 14: //dauc + case 15: //ctr + break; + + default: //only the above io registers are supported by the DSP3210 + DSP_undefined(); + break; + } + + if((incode&0x01000000)>>24) //move from reg to mem + { + switch(Wfield(incode)) + { + case 0: //char + DSP_set_char(reg(RPfield(incode)), DSP_swapl(io(RHfield(incode))&0xFF)); + pinc=1; + break; + + case 2: //short + DSP_set_short(reg(RPfield(incode)), DSP_swapw(io(RHfield(incode))&0xFFFF)); + pinc=2; + break; + + case 7: //long + DSP_set_long(reg(RPfield(incode)), DSP_swapl(io(RHfield(incode)))); + pinc=4; + break; + + default: + DSP_undefined(); + break; + } + //do post inc + switch(RIfield(incode)) + { + case 0: //no post inc + break; + + case 22: //post dec + reg(RPfield(incode))-=pinc; + break; + + case 23: //post inc + reg(RPfield(incode))+=pinc; + break; + + default: //RI + reg(RPfield(incode))+=reg(RIfield(incode)); + break; + } + } else { //move to reg from mem + if(RHfield(incode)!=15) //cannot write to ctr + switch(Wfield(incode)) + { + case 0: //unsigned char - do not change other bits + io(RHfield(incode)) = (io(RHfield(incode))&0xFFFFFF00) | (DSP_swapl((uint32_t)DSP_get_char(reg(RPfield(incode)))) & 0xFF); + pinc=1; + break; + + case 2: //unsigned short - do not change high word + io(RHfield(incode)) = (io(RHfield(incode))&0xFFFF0000) | (DSP_swapl((uint32_t)DSP_get_short(reg(RPfield(incode)))) & 0xFFFF); + pinc=2; + break; + + case 7: //long + io(RHfield(incode)) = DSP_swapl(DSP_get_long(reg(RPfield(incode)))); + pinc=4; + break; + + default: + DSP_undefined(); + break; + } + //do post inc + switch(RIfield(incode)) + { + case 0: //no post inc + break; + + case 22: //post dec + reg(RPfield(incode))-=pinc; + break; + + case 23: //post inc + reg(RPfield(incode))+=pinc; + break; + + default: //RI + reg(RPfield(incode))+=reg(RIfield(incode)); + break; + } + } + break; //end 7d + } + break; //end 7c and 7d + + case 1: //move io 7b instruction + switch(incode) + { + case 0x09DE0040A: + //execute waiti + DSP_reg_irsh = DSP_swapl(DSP_get_long(reg_PC + 4)); + DSP_irsh_flag = 4; //execute one more instruction, then pause DSP + DSP_irsh_addr = reg_PC + 4; + DSP_irsh_pcw = DSP_io_r[12]; + break; + + case 0x9D00040A: + //execute sftrst = reset + DSP_reset(); + break; + + case 0x9D60040A: + //execute breakpoint + DSP_breakpoint(); + break; + + default: + switch(RIfield(incode)) + { + case 0: //ps 16 + case 8: //emr 16 + case 10: //spc 32 + case 12: //pcw 16 + case 14: //dauc 8 + case 15: //ctr 8 + break; + + default: //only the above io registers are supported by the DSP3210 + DSP_undefined(); + break; + } + if((incode&0x01000000)>>24) //move from reg to io, iorD = rS + { + if(RHfield(incode)!=15) //cannot write to ctr + { + switch(Wfield(incode)) + { + case 1: //char + io(RIfield(incode)) = (io(RIfield(incode)) & 0xFFFFFF00) | (reg(RHfield(incode)) & 0xFF); + break; + + case 3: //short + if(RIfield(incode)<14) + io(RIfield(incode)) = (io(RIfield(incode)) & 0xFFFF0000) | (reg(RHfield(incode)) & 0xFFFF); + else + //cannot read 16 bits from an 8 bit io reg + DSP_undefined(); + break; + + case 4: //unsigned high char + if(RIfield(incode)<14) + io(RIfield(incode)) = (io(RIfield(incode)) & 0xFFFF00FF) | (reg(RHfield(incode)) & 0xFF00); + else + //cannot read 16 bits from an 8 bit io reg + DSP_undefined(); + break; + + case 7: + if(RIfield(incode) == 10) + io(RIfield(incode)) = reg(RHfield(incode)); + else + DSP_undefined(); + break; + + default: + DSP_undefined(); + break; + } + } else { + //exception due to write to ctr attempt? + } + } else { //move to reg from io rD = iorS + switch(Wfield(incode)) + { + case 0: //unsigned char + reg(RHfield(incode)) = io(RIfield(incode)) & 0xFF; + break; + + case 1: //signed char + reg(RHfield(incode)) = (int32_t)((char)(io(RIfield(incode)) & 0xFF)); + break; + + case 2: //unsigned short + if(RIfield(incode)<14) + reg(RHfield(incode)) = io(RIfield(incode)) & 0xFFFF; + else + DSP_undefined(); + break; + + case 3: //signed short + if(RIfield(incode)<14) + reg(RHfield(incode)) = (int32_t)((int16_t)(io(RIfield(incode)) & 0xFFFF)); + else + DSP_undefined(); + break; + + case 4: //high byte + reg(RHfield(incode)) = (io(RIfield(incode)) & 0xFF) << 8; + break; + + case 7: //long + if(RIfield(incode)==10) //read from spc to reg + reg(RHfield(incode)) = io(RIfield(incode)); + else + DSP_undefined(); + break; + + default: + DSP_undefined(); + break; + } + } + break; // end test for special instructions + } + break; //end 7b + } + break; //end case 39 + + default: + DSP_undefined(); + break; + } + break; + } + break; + } + return ; +} + +/********************************************************/ +/* Functions to support doinst */ +/********************************************************/ + +// Extract the two parts of an X, Y or Z field (depending on field) +// into the return value (fld1) and fld2 +int32_t DAUXYZ(int32_t incode, int32_t field, int32_t *fld2) +{ + int32_t fld1,temp; + switch(field) + { + case 1: + fld1=Xfield(incode)>>3; + temp=Xfield(incode)&0x7; + break; + case 2: + fld1=Yfield(incode)>>3; + temp=Yfield(incode)&0x7; + break; + case 3: + fld1=Zfield(incode)>>3; + temp=Zfield(incode)&0x7; + break; + } + + if(fld1) + { + if(temp>0&&temp<6) + *fld2=temp+14; + else + *fld2=temp; + } else { + *fld2=temp; + } + return fld1; +} + +//return the X or Y field determined by the field parameters +// as a _BE_ value +int32_t GetXYfield(int32_t fld1,int32_t fld2,int32_t incode) +{ + int32_t temp,g; + int32_t postinc=4; + intfloat conv; + + if((incode&0xF8000000)>>27==15) //true if DAU5 + { //change size field to short on int16/float16 + g=Gfield(incode); + switch(g) + { + case 2: + case 3: + postinc=2; + break; + + default: + break; + } + } + + if(!fld1) + { + if(fld2>3) + { + DSP_undefined(); + return 0; + } + //=aN + conv.f = DSP_reg_a[fld2]; + temp = DSP_swapl(conv.i); + } else { + switch(fld2) + { + case 0: + //=*rP + temp = DSP_get_long(DSP_reg_r[fld1]); + break; + + case 6: + //=*rP-- + temp = DSP_get_long(DSP_reg_r[fld1]); + DSP_reg_r[fld1]-=postinc; + break; + + case 7: + //=*rP++ + temp = DSP_get_long(DSP_reg_r[fld1]); + DSP_reg_r[fld1]+=postinc; + break; + + default: + //=*rP++rI + temp = DSP_get_long(DSP_reg_r[fld1]); + DSP_reg_r[fld1]+=DSP_reg_r[fld2]; + break; + } + + if((incode>>27)!=15) + //Not DAU5 + //having read a BE DSP float (as an int) from mem, convert to + //internal BE IEEE float (as an int) + return(DSP_swapl(DSP_dsp2ieee(DSP_swapl(temp)))); + + switch(Gfield(incode)) + { + case 2: //do nothing on float 16/32, dsp + case 8: + case 13: + break; + + default: + //having read a BE DSP float (as an int) from mem, convert to + //internal BE IEEE float (as an int) + temp = DSP_swapl(DSP_dsp2ieee(DSP_swapl(temp))); + break; + } + } + return temp; +} + +// Set up jump instructions with 3 clock latencies +void DoLat3(int32_t pcval) +{ + int32_t lat3ptr=0; + if(!latency3[0][0]) lat3ptr=1; //first slot occupied + latency3[lat3ptr][1]=pcval; //new PC value + latency3[lat3ptr][0]=2; //2 ticks to execute + return; +} + +// Set up Z-field writes with 2 instruction latency +// and post inc/dec +void SetZfield(int32_t fld1, int32_t fld2, int32_t temp) +//temp must be converted from BE IEEE to DSP BE +{ + int32_t postinc=4; //postinc always 4 + intfloat conv; + + if(fld1) //need to set Zfield + { //deal with write latency 1 here + int32_t temp2 = DSP_swapl(temp); //now LE + //float f = *((float *)&(temp2)); //input -> float (still LE IEEE) ''' + conv.i = temp2; + float f = conv.f; + temp2 = DSP_swapl(DSP_float(f)); + //DSP_history_mem[0][0] = (int32_t)(amiga_mem_base+(DSP_reg_r[fld1]>>2)); + DSP_history_mem[0][0] = DSP_reg_r[fld1]; //>>2; + DSP_history_mem[1][0] = temp2; + DSP_history_mem[2][0] = 1; //delayed write enabled + + switch(fld2) + { + case 0: + break; + + case 6: //*rP--= + DSP_reg_r[fld1]-=postinc; + break; + + case 7: //*rP++= + DSP_reg_r[fld1]+=postinc; + break; + + default: //*rP++rI= + DSP_reg_r[fld1]+=DSP_reg_r[fld2]; + break; + } + } +} + +// Execute DAU5 type instruction +void doDAU5(int32_t incode) +{ + int32_t value, fld1, fld2; + float ftemp; + fld1=DAUXYZ(incode,2,&fld2); //get Yfield values + value=GetXYfield(fld1,fld2,incode); //read value from Yfield reg and post inc + //NB value is BE + int32_t m0,m1, m2, m3; //### + intfloat conv; + + switch(Gfield(incode)) + { + case 0: //ic + case 1: //oc + //Unsupport instruction + break; + + case 2: + //float16 + ftemp = (float)DSP_swapl((value>>16)); //want first short + conv.f = ftemp; + value = DSP_swapl(conv.i); + break; + + case 3: + //int16 + m0 = DSP_swapl(value); //BE to LE + //get float value + conv.i = m0; + ftemp = conv.f; + ftemp = round_dsp(ftemp); //round + value = (int32_t)ftemp; //convert to int + if(value>0x7FFF||value<-0x8000) + value=0x7FFF; + else + value&=0xFFFF; + value = DSP_swapl(value); //convert to BE + break; + + case 4: + //round + //nothing to do as it rounds 40 bits to 32 bit + break; + + case 5: + //ifalt ie do nothing if Z-flag set or N-flag not set + if(!(CC&CCN)) + return; //Do nothing if Z-flag not set + //otherwise no other manipulation needed + break; + + case 6: + //ifaeq + if(!(CC&CCZ)) + return; //Do nothing if Z-flag not set + //otherwise no other manipulation needed + break; + + case 7: + //ifagt ie do nothing if Z-flag set or N-flag not set + if(CC&CCZ||CC&CCN) + return; //Do nothing if Z-flag not set + //otherwise no other manipulation needed + break; + + case 8: + //float32 + value = DSP_swapl(value); + ftemp = (float)value; + conv.f = ftemp; + value = DSP_swapl(conv.i); + break; + + case 9: + //int32 + m0 = DSP_swapl(value); //BE to LE IEEE + //get float value + conv.i = m0; + ftemp = conv.f; + ftemp = round_dsp(ftemp); //round + value = DSP_swapl((int32_t)ftemp); //convert to int and BE + break; + + case 10: + case 11: + DSP_undefined(); + break; + + case 12: + //ieee + //value = swapl(DSP_dsp2ieee(swapl(value))); + m0 = DSP_swapl(value); + if(((m0 & 0x7F800000) == 0x7F800000) && ((m0 & 0x007FFFFF) != 0)) + DSP_exception_NaN(); + break; + + case 13: + //dsp + /*m0 = swapl(value); //get BE IEEE float into LE IEEE + ftemp = DSP_float(*(float *)&m0); //convert to DSP float format + value = swapl(*(int *)&ftemp); //put into a BE int*/ + break; + + case 14: + //seed + m0 = DSP_swapl(value); //value now LE IEEE + //IEEE LE -> DSP LE + conv.i = m0; + m3 = DSP_float(conv.f); + //m1 = ((~DSP_float(*(float *)&m0))^0x80000000); //invert all bits except sign + m1 = ((~m3) ^ 0x80000000); + m2 = DSP_dsp2ieee(m1); //DSP LE -> IEEE LE + + value = DSP_swapl(m2); //value is IEEE BE + break; + + default: + //reserved + DSP_undefined(); + break; + } + + if(Gfield(incode)==3 || Gfield(incode)==9) //int16 or int32 + DSP_reg_a[NDAUfield(incode)]=(float)DSP_swapl(value); //set aN to int value + else { + //set aN to value + conv.i = DSP_swapl(value); + DSP_reg_a[NDAUfield(incode)] = conv.f; + } + + switch (Gfield(incode)) //set flags on required instructions + { + case 0: //ic + case 2: //float16 + case 4: //round + case 8: //float32 + case 14: //seed + if(DSP_swapl(value)<0) CC|=CCN; else CC&=~CCN; + if(!DSP_swapl(value)) CC|=CCZ; else CC&=~CCZ; + CC&=~CCU; + CC&=~CCV; + break; + + case 13: //dsp U and V already set + if(DSP_swapl(value)<0) CC|=CCN; else CC&=~CCN; + if(!DSP_swapl(value)) CC|=CCZ; else CC&=~CCZ; + break; + + default: + break; + } + + fld1=DAUXYZ(incode,3,&fld2); //get Zfield values + switch(Gfield(incode)) + { + case 3: + //int16 exception here. We need to do a version of + //SetZfield but without the conversion to a DSP float + + if(fld1) //need to set Zfield + { //deal with write latency 1 here + DSP_history_mem[0][0] = DSP_reg_r[fld1]; + DSP_history_mem[1][0] = value; + DSP_history_mem[2][0] = 2; //delayed write enabled + + switch(fld2) + { + case 0: + //*rP= + break; + + case 6: + //*rP--= + DSP_reg_r[fld1]-=2; + break; + + case 7: + //*rP++= + DSP_reg_r[fld1]+=2; + break; + + default: + //*rP++rI= + DSP_reg_r[fld1]+=DSP_reg_r[fld2]; + break; + } + } + break; + case 9: + case 12: + //int32, ieee exception here. We need to do a version of + //SetZfield but without the conversion to a DSP float + + if(fld1) //need to set Zfield + { //deal with write latency 1 here + //DSP_history_mem[0][0] = (int32_t)(amiga_mem_base+(DSP_reg_r[fld1]>>2)); + DSP_history_mem[0][0] = DSP_reg_r[fld1]; + DSP_history_mem[1][0] = value; + DSP_history_mem[2][0] = 1; //delayed write enabled + + switch(fld2) + { + case 0: + //*rP= + break; + + case 6: + //*rP--= + DSP_reg_r[fld1]-=4; + break; + + case 7: + //*rP++= + DSP_reg_r[fld1]+=4; + break; + + default: + //*rP++rI= + DSP_reg_r[fld1]+=DSP_reg_r[fld2]; + break; + } + } + break; + + default: + SetZfield(fld1, fld2, value); //and set Zfield if needed + break; + } +} + +// Extract float value out of M field +float Mval(int32_t incode) +{ + int32_t m = Mfield(incode); + switch(m) + { + case 4: + return 0.0; + break; + + case 5: + return 1.0; + break; + + case 0: + case 1: + case 2: + case 3: + return DSP_reg_a[m]; + + default: + return 0; + } +} + +// Set condition codes for DAU instructions +float SetCC(double dtemp) +{ + if(dtemp<0) CC|=CCN; else CC&=~CCN; + if(dtemp==0) CC|=CCZ; else CC&=~CCZ; + + //test for under/overflow situations + if(dtemp>max_pos_float || dtemp0 && dtempmin_neg_float)) DSP_exception_UOflow(); + + //test for UV flags + if(dtemp>3.40282e28||dtemp<-3.40282e28) { CC|=CCV; dtemp=0;} else CC&=~CCV; + if(dtemp<5.87747e-39&&dtemp>-5.87747e-39&&dtemp!=0) { CC|=CCU; dtemp=0;} else CC&=~CCU; + + return((float)dtemp); +} + +//Set confition codes for 32 bit CAU instructions +int32_t SetCCCAU(int64_t res, int32_t input) +{ + int64_t in = (int64_t)input; + if(res<0) CC|=CCn; else CC&=~CCn; + if(res==0) CC|=CCz; else CC&=~CCz; + if((res&hi32)^(in&hi32)) CC|=CCc; else CC&=~CCc; //set c if hi-32 bits change + if(((res&bt32)^(in&bt32))&!CCcf) CC|=CCv; else CC&=~CCv; //set v if bit 32 changes and c unset + return((int32_t)res); +} + +//Set condition codes for 16 bit CAU instructions +int32_t SetCCCAU16(int64_t res, int32_t input) +{ + int64_t in = (int64_t)input; + if(res<0) CC|=CCn; else CC&=~CCn; + if(res==0) CC|=CCz; else CC&=~CCz; + if((res&hi48)^(in&hi48)) CC|=CCc; else CC&=~CCc; //set c if hi-48 bits change + if(((res&bt16)^(in&bt16))&!CCcf) CC|=CCv; else CC&=~CCv; //set v if bit 16 changes and c unset + return((int32_t)res); +} + +//Set n,z condition codes, clear c, v +void SetCCnzCAU(int32_t res) +{ + if(res<0) CC|=CCn; else CC&=~CCn; + if(res==0) CC|=CCz; else CC&=~CCz; + CC&=~CCc; //clear c + CC&=~CCv; //clear v + return; +} + +//Test C field +int32_t TestCfield(int32_t code) //test CCs but U and V not supported +{ + int32_t res=0; + switch(code) + { + case 0: //false + break; + + case 1: //true + res=1; + break; + + case 2: //pl + if(!CCnf) res=1; + break; + + case 3: //mi + if(CCnf) res=1; + break; + + case 4: //ne + if(!CCzf) res=1; + break; + + case 5: //eq + if(CCzf) res=1; + break; + + case 6: //vc + if(!CCvf) res=1; + break; + + case 7: //vs + if(CCvf) res=1; + break; + + case 8: //cc + if(!CCcf) res=1; + break; + + case 9: //cs + if(CCcf) res=1; + break; + + case 10: //ge + if(!(CCnf^CCvf)) res=1; + break; + + case 11: //lt + if(CCnf^CCvf) res=1; + break; + + case 12: //gt + if(!CCzf&!(CCnf^CCvf)) res=1; + break; + + case 13: //le + if(CCzf|(CCnf^CCvf)) res=1; + break; + + case 14: //hi + if(!CCcf&!CCzf) res=1; + break; + + case 15: //ls + if(CCcf|CCzf) res=1; + break; + + case 18: //age + if(!(DSP_history_CC[3]&CCN)) res=1; + break; + + case 19: //alt + if(DSP_history_CC[3]&CCN) res=1; + break; + + case 20: //ane + if(!(DSP_history_CC[3]&CCZ)) res=1; + break; + + case 21: //aeq + if(DSP_history_CC[3]&CCZ) res=1; + break; + + case 24: //agt + if(!(DSP_history_CC[3]&CCN)&!(DSP_history_CC[3]&CCZ)) res=1; + break; + + case 25: //ale + if((DSP_history_CC[3]&CCN)|(DSP_history_CC[3]&CCZ)) res=1; + break; + + } + return res; +} + + + +/********************************************************/ +/* Utility functions */ +/********************************************************/ + +//BE <-> LE craziness +int32_t DSP_swapl(int32_t a) +{ + return ((a & 0x000000FF) << 24) | + ((a & 0x0000FF00) << 8) | + ((a & 0x00FF0000) >> 8) | + ((a & 0xFF000000) >> 24); +} + +int16_t DSP_swapw(int16_t a) +{ + return ((a & 0x00FF) << 8) | ((a & 0xFF00) >> 8); +} + +//map register code onto a uniform register number +int32_t DSP_regno(int32_t r) +{ + if(r<15) + return r; + if(r==15) + return 23; //map PC to reg 23 + if(r>16&&r<22) + return r-2; //map regs 15-19 + if(r>23&&r<27) + return r-4; + if(r==30) + return 24; //map pcsh to reg 24 + return 25; //trap illegal +} + +// LE IEEE to LE DSP +int32_t DSP_float(float f) +{ + int32_t neg = 0; + int32_t mant, exp; + intfloat intf; + + if(f < 0.0) { + f = -f; + neg = 1; + } + intf.f = f; + + mant = intf.i & 0x007FFFFF; + exp = (intf.i >> 23) & 0x000000FF; + + if(exp != 0) + { + exp += 1; + CC&=~CCU; //clear underflow flag + } + else + { + mant = 0; // unnormalized underflows ==> 0.0 + CC|=CCU; //set underflow flag + } + if(exp > 0xFF) { + exp = 0xFF; + mant = 0x007FFFFFL; + CC|=CCV; //set overflow flag + } else CC&=~CCV; //clear overflow flag + mant = (mant << 8) | exp; + + return neg ? DSP_negfloat(mant) : mant; +} + +int32_t DSP_negfloat(int32_t f) +{ + int32_t mant, exp; + if(f == 0) + return f; + + mant = f >> 8; + exp = f & 0xFF; + + mant = -mant; + if(f > 0 && mant == 0) { + exp -= 1; + mant = 0x00800000; + } else if(f < 0 && mant == 0) + exp += 1; + + return (mant<<8) | exp; +} + +int32_t bitreverse(int32_t n, int32_t bits) +{ + int32_t rv = 0; + int32_t i; + for(i = 0; i < bits; ++i, n >>= 1) { + rv = (rv << 1) | (n & 0x01); + } + return rv; +} + +//convert LE DSP float as int to LE IEEE float as int +int32_t DSP_dsp2ieee(int32_t f) +{ + int32_t neg = 0; + int32_t m,e; + + if(!f) return f; + if(f&0x80000000) + neg = 1; + + e = f&0xFFL; + m = (f>>8)&0x7FFFFF; + + if(!e) return 0; //zero even if dirty zero + + e-=1; + //cannot be a carry as e>0 + + if(neg) { + m = (-m) & 0x7FFFFF; + if(!m) e -= 1; + } + + m = m|(e<<23)|(neg?0x80000000:0); + + return m; +} + +static float round_dsp(float num) +{ + float integer = ceilf(num); //smallest integer >= num (-2>-2.8) + switch((DSP_io_r[14]&0x30)>>4) + { + case 0: //round nearest + case 2: + default: + if(num > 0) + return integer - num > 0.5f ? integer - 1.0f : integer; + return integer - num >= 0.5f ? integer - 1.0f : integer; + break; + + case 1: + return integer - 1.0f; + break; + + case 3: + if(num > 0) + return integer - 1.0f; + return integer; + break; + } +} + +/********************************************************/ +/* Illegal opcode exception */ +/* */ +/********************************************************/ +void DSP_exception_illegal() +{ + //non-maskable exception + //if(!(io_emr & 0x8000)) + //return; //return if int1 masked out + + //save chip state: DO loop status, a0-a3, dauc + //not implemented yet + DSP_reg_r[20] = reg_PC; + reg_pcsh = reg_PC; //save PC + reg_PC = reg_evtp + 8*2; //Illegal opcode entry + return; +} + +/********************************************************/ +/* Under/overflow exception */ +/* */ +/********************************************************/ +void DSP_exception_UOflow() +{ + if(!(io_emr & 0x0020)) + return; //return if NaN masked out + + //save chip state: DO loop status, a0-a3, dauc + //not implemented yet + DSP_reg_r[20] = reg_PC; + reg_pcsh = reg_PC; //save PC + reg_PC = reg_evtp + 8*5; //NaN opcode entry + return; +} + +/********************************************************/ +/* NaN opcode exception */ +/* */ +/********************************************************/ +void DSP_exception_NaN() +{ + if(!(io_emr & 0x0040)) + return; //return if NaN masked out + + //save chip state: DO loop status, a0-a3, dauc + //not implemented yet + DSP_reg_r[20] = reg_PC; + reg_pcsh = reg_PC; //save PC + reg_PC = reg_evtp + 8*6; //NaN opcode entry + return; +} + +/********************************************************/ +/* Undefined behaviour handling */ +/* */ +/********************************************************/ +void DSP_undefined() +{ + //certain instruction codes are marked as Reserved and yet + //aren't listed in the manual as triggering the illegal + //opcode exception. It's not known what happens in all these + //cases. Here they are assumed to trigger the illegal opcode + //exception. + DSP_exception_illegal(); + return; +} + +/********************************************************/ +/* Memory read/write routines */ +/********************************************************/ +int32_t *dsp_check_mem(int32_t addr, int32_t *flag) +{ + if(DSP_io_r[12] & 0x0400) { + //we are in memory map mode 1 + if(addr >= map1_ROM_start && addr <= map1_ROM_end) { + //we are accessing ROM + *flag = 1; + return (int32_t *)(DSP_onboard_ROM + addr - map1_ROM_start); + } + if(addr >= map1_RAM_start && addr <= map1_RAM_end) { + //we are accessing onboard RAM + *flag = 2; + return (int32_t *)((int32_t)DSP_onboard_RAM + addr - map1_RAM_start); + } + if(addr >= map1_MMIO_start && addr <= map1_MMIO_end) { + //access to MMIO space + *flag = 4; + return (int32_t *)((int32_t)DSP_MMIO + addr - map1_MMIO_start); + } + if (addr >= map1_ROM_start && addr < map1_RAM_end) { + write_log("1"); + } + } else { + //we are in memory map mode 0 + if(addr >= map0_ROM_start && addr <= map0_ROM_end) { + //we are accessing ROM + *flag = 1; + return (int32_t *)(DSP_onboard_ROM + addr - map0_ROM_start); + } + if(addr >= map0_RAM_start && addr <= map0_RAM_end) { + //we are accessing onboard RAM + *flag = 2; + return (int32_t *)((int32_t)DSP_onboard_RAM + addr - map0_RAM_start); + } + if(addr >= map0_MMIO_start && addr <= map0_MMIO_end) { + //access to MMIO space + *flag = 3; + return (int32_t *)((int32_t)DSP_MMIO + addr - map0_MMIO_start); + } + if (addr >= map0_ROM_start && addr < map0_RAM_end) { + write_log("1"); + } + } + *flag = 0; + return NULL; +} + +extern int log_dsp; +static const char *iotype[] = { "", "ROM", "RAM", "MMIO0", "MMIO1" }; + +int32_t DSP_get_long(int32_t addr) +{ + int32_t flag; + int32_t *actual_addr = dsp_check_mem(addr, &flag); + switch(flag) + { + case 0: //read Amiga mem + return DSP_get_long_ext(addr); + + default: //read onboard ROM, RAM, MMIO + if (log_dsp) { + write_log("LGET from DSP %s: %08x = %08x\n", iotype[flag], addr, *actual_addr); + } + return *actual_addr; + } +} + +void DSP_set_long(int32_t addr, int32_t value) +{ + int32_t flag; + int32_t *actual_addr = dsp_check_mem(addr, &flag); + switch(flag) + { + case 0: + DSP_set_long_ext(addr, value); //write to Amiga mem + break; + + case 1: + if (log_dsp) { + write_log("LPUT DSP ROM %08x = %08x\n", addr, *actual_addr); + } + break; //attempt to write to onboard ROM! Do nothing + + case 2: + if (log_dsp) { + write_log("LPUT DSP RAM %08x = %08x\n", addr, *actual_addr); + } + *actual_addr = value; //write to onboard RAM + break; + + case 3: + if (log_dsp) { + write_log("LPUT DSP MMIO0 %08x = %08x\n", addr, *actual_addr); + } + if(addr == (0x41C + map0_ROM_start)) //write to bio reg + DSP_check_interrupt(value, 28); + *actual_addr = value; + break; + + case 4: + if (log_dsp) { + write_log("LPUT DSP MMIO1 %08x = %08x\n", addr, *actual_addr); + } + if(addr == (0x41C + map1_ROM_start)) + DSP_check_interrupt(value, 28); + *actual_addr = value; + break; + } +} + +int16_t DSP_get_short(int32_t addr) +{ + int32_t flag; + int16_t *actual_addr = (int16_t *)dsp_check_mem(addr, &flag); + + switch(flag) + { + case 0: //read Amiga mem + return DSP_get_short_ext(addr); + + default: //read onboard ROM, RAM, MMIO + return *actual_addr; + } +} + +void DSP_set_short(int32_t addr, int16_t value) +{ + int32_t flag; + int16_t *actual_addr = (int16_t *)dsp_check_mem(addr, &flag); + + switch(flag) + { + case 0: + DSP_set_short_ext(addr, value); //write to Amiga mem + break; + + case 1: //attempt to write to onboard ROM! Do nothing + if (log_dsp) { + write_log("WPUT DSP ROM %08x = %04x\n", addr, *actual_addr); + } + break; + + case 2: //write to onboard RAM + if (log_dsp) { + write_log("WPUT DSP RAM %08x = %04x\n", addr, *actual_addr); + } + *actual_addr = value; + break; + + case 3: //write to MMIO space + if (log_dsp) { + write_log("WPUT DSP MMIO0 %08x = %04x\n", addr, *actual_addr); + } + if(addr == 0x41E + map0_ROM_start) //write to bio reg + DSP_check_interrupt(value, 12-8); + *actual_addr = value; + break; + + case 4: //write to MMIO space + if (log_dsp) { + write_log("WPUT DSP MMIO1 %08x = %04x\n", addr, *actual_addr); + } + if(addr == 0x41E + map1_ROM_start) + DSP_check_interrupt(value, 12-8); + *actual_addr = value; + break; + } + return; +} + +char DSP_get_char(int32_t addr) +{ + int32_t flag; + char *actual_addr = (char *)dsp_check_mem(addr, &flag); + + switch(flag) + { + case 0: //read Amiga mem + return DSP_get_char_ext(addr); + + default: //read onboard ROM, RAM, MMIO + return *actual_addr; + } +} + +void DSP_set_char(int32_t addr, char value) +{ + int32_t flag; + char *actual_addr = (char *)dsp_check_mem(addr, &flag); + + switch(flag) + { + case 0: //write to Amiga mem + DSP_set_char_ext(addr,value); + break; + + case 1: //attempt to write to onboard ROM! Do nothing + if (log_dsp) { + write_log("BPUT DSP ROM %08x = %02x\n", addr, *actual_addr); + } + break; + + case 2: //write to onboard RAM + if (log_dsp) { + write_log("BPUT DSP RAM %08x = %02x\n", addr, *actual_addr); + } + *actual_addr = value; + break; + + case 3: //write to MMIO space + if (log_dsp) { + write_log("BPUT DSP MMIO0 %08x = %02x\n", addr, *actual_addr); + } + if(addr == 0x41F + map0_ROM_start) //write to bio reg + DSP_check_interrupt(value, 4); + *actual_addr = value; + break; + + case 4: //write to MMIO space + if (log_dsp) { + write_log("BPUT DSP MMIO1 %08x = %02x\n", addr, *actual_addr); + } + if(addr == 0x41F + map1_ROM_start) + DSP_check_interrupt(value, 4); + *actual_addr = value; + break; + } + return ; +} + +void DSP_check_interrupt(int32_t value, int32_t bitno) +{ + int32_t mask; + mask = 3 << bitno; //test for bio[6] = INT6 + switch((value & mask) >> bitno) + { + case 0: //no change to reg + break; + + case 1: //set reg to 0 = trigger int + bio6 = 0; + DSP_external_interrupt(1, 0); + break; + + case 2: //set reg to 1 + bio6 = 1; + DSP_external_interrupt(1, 1); + break; + + case 3: //complement reg + bio6 = (1-bio6); + DSP_external_interrupt(1, bio6); + break; + } + + mask = 3 << (bitno + 2); //test for bio[7] = INT2 + switch((value & mask) >> (bitno+2)) + { + case 0: //no change to reg + break; + + case 1: //set reg to 0 = trigger int + bio7 = 0; + DSP_external_interrupt(0, 0); + break; + + case 2: //set reg to 1 + bio7 = 1; + DSP_external_interrupt(0, 1); + break; + + case 3: //complement reg + bio7 = (1-bio7); + DSP_external_interrupt(0, bio7); + break; + } + return; +} + +/********************************************************/ +/* Onboard boot rom binary */ +/********************************************************/ + +unsigned char DSP_onboard_ROM[] = +{ +/* [0000][0001][0002][0003][0004][0005][0006][0007]*/ +/*[0000]*/ 0x80, 0x2f, 0x00, 0x80, 0x9c, 0x61, 0x04, 0x0c, +/*[0008]*/ 0x80, 0x2f, 0x00, 0xec, 0x80, 0x00, 0x00, 0x00, +/*[0010]*/ 0x80, 0x2f, 0x00, 0xe4, 0x80, 0x00, 0x00, 0x00, +/*[0018]*/ 0x80, 0x2f, 0x00, 0xdc, 0x80, 0x00, 0x00, 0x00, +/*[0020]*/ 0x80, 0x2f, 0x00, 0xd4, 0x80, 0x00, 0x00, 0x00, +/*[0028]*/ 0x80, 0x2f, 0x00, 0xcc, 0x80, 0x00, 0x00, 0x00, +/*[0030]*/ 0x80, 0x2f, 0x00, 0xc4, 0x80, 0x00, 0x00, 0x00, +/*[0038]*/ 0x80, 0x2f, 0x00, 0xbc, 0x80, 0x00, 0x00, 0x00, +/*[0040]*/ 0x80, 0x2f, 0x00, 0xb4, 0x80, 0x00, 0x00, 0x00, +/*[0048]*/ 0x80, 0x2f, 0x00, 0xac, 0x80, 0x00, 0x00, 0x00, +/*[0050]*/ 0x80, 0x2f, 0x00, 0xa4, 0x80, 0x00, 0x00, 0x00, +/* [0058][0059][005a][005b][005c][005d][005e][005f]*/ +/*[0058]*/ 0x80, 0x2f, 0x00, 0xa8, 0x80, 0x00, 0x00, 0x00, +/*[0060]*/ 0x80, 0x2f, 0x00, 0x94, 0x80, 0x00, 0x00, 0x00, +/*[0068]*/ 0x80, 0x2f, 0x00, 0x8c, 0x80, 0x00, 0x00, 0x00, +/*[0070]*/ 0x80, 0x2f, 0x00, 0x84, 0x80, 0x00, 0x00, 0x00, +/*[0078]*/ 0x9c, 0xfe, 0x00, 0x00, 0x9d, 0x60, 0x04, 0x08, +/*[0080]*/ 0x80, 0x3e, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, +/*[0088]*/ 0x90, 0x40, 0x60, 0x00, 0x1b, 0xe1, 0x20, 0x00, +/*[0090]*/ 0x80, 0xaf, 0x00, 0x48, 0xc0, 0x03, 0xe0, 0x00, +/*[0098]*/ 0x8c, 0x00, 0x38, 0x02, 0x9c, 0xe4, 0x10, 0x17, +/*[00a0]*/ 0x80, 0x00, 0x00, 0x00, 0x9d, 0x04, 0x18, 0x17, +/*[00a8]*/ 0x1c, 0xe5, 0xe0, 0x04, 0x1c, 0xe1, 0xe0, 0x00, +/* [00b0][00b1][00b2][00b3][00b4][00b5][00b6][00b7]*/ +/*[00b0]*/ 0x80, 0xaf, 0x00, 0x18, 0x98, 0x03, 0x08, 0x20, +/*[00b8]*/ 0x9a, 0x85, 0x00, 0x02, 0x9c, 0xe4, 0x10, 0x17, +/*[00c0]*/ 0x0c, 0xaf, 0xff, 0xf4, 0x9d, 0x04, 0x18, 0x17, +/*[00c8]*/ 0xa0, 0x01, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, +/*[00d0]*/ 0x80, 0xaf, 0x00, 0x30, 0x80, 0x00, 0x00, 0x00, +/*[00d8]*/ 0xa0, 0x01, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, +/*[00e0]*/ 0x93, 0x40, 0x50, 0x03, 0xc0, 0x02, 0x80, 0x00, +/*[00e8]*/ 0x9d, 0x62, 0x04, 0x08, 0x9b, 0xc1, 0xfb, 0xff, +/*[00f0]*/ 0x9d, 0xe0, 0x04, 0x0a, 0x9d, 0x61, 0x04, 0x0c, +/*[00f8]*/ 0x9d, 0xe0, 0x00, 0x00, 0x9d, 0x60, 0x04, 0x0a, +/*[0100]*/ 0x80, 0x2f, 0xff, 0xf8, 0x80, 0x00, 0x00, 0x00, +/* [0108][0109][010a][010b][010c][010d][010e][010f]*/ +/*[0108]*/ 0x94, 0xcf, 0xfe, 0xf0, 0x95, 0x06, 0x03, 0xff, +/*[0110]*/ 0xc0, 0x07, 0xe0, 0x00, 0x98, 0x03, 0x30, 0x27, +/*[0118]*/ 0x9d, 0xe0, 0x18, 0x00, 0x30, 0x00, 0x0c, 0x07, +/*[0120]*/ 0x14, 0x40, 0x00, 0x01, 0x98, 0x24, 0x30, 0x20, +/*[0128]*/ 0x8c, 0x3f, 0xf8, 0x01, 0x49, 0xa8, 0x13, 0x9f, +/*[0130]*/ 0x99, 0xc4, 0x20, 0x28, 0x98, 0x73, 0x00, 0x20, +/*[0138]*/ 0x99, 0x0a, 0x30, 0x27, 0x8c, 0x07, 0xf8, 0x07, +/*[0140]*/ 0x79, 0x60, 0x2b, 0x87, 0x79, 0x40, 0x2b, 0x07, +/*[0148]*/ 0x9c, 0x74, 0x50, 0x17, 0x9c, 0x75, 0x50, 0x17, +/*[0150]*/ 0x34, 0x00, 0xc0, 0x07, 0x34, 0x00, 0x80, 0x07, +/*[0158]*/ 0x98, 0x13, 0x98, 0x34, 0x98, 0x13, 0x98, 0x35, +/* [0160][0161][0162][0163][0164][0165][0166][0167]*/ +/*[0160]*/ 0x98, 0x85, 0x00, 0x20, 0x99, 0x4b, 0x00, 0x20, +/*[0168]*/ 0xdf, 0xf5, 0xff, 0xff, 0x9a, 0x8a, 0x04, 0x00, +/*[0170]*/ 0x8c, 0x3f, 0xf8, 0x06, 0x9c, 0xe9, 0x50, 0x00, +/*[0178]*/ 0x98, 0x05, 0x28, 0x2b, 0x98, 0xd4, 0x48, 0x29, +/*[0180]*/ 0x9d, 0xf4, 0x50, 0x00, 0x9c, 0xe6, 0x50, 0x17, +/*[0188]*/ 0x98, 0x05, 0x48, 0x25, 0x98, 0xcb, 0x30, 0x34, +/*[0190]*/ 0x95, 0x6a, 0xe0, 0x00, 0x7c, 0xa0, 0x00, 0x58, +/*[0198]*/ 0x1c, 0xf1, 0x04, 0x0c, 0x1c, 0xee, 0x04, 0x14, +/*[01a0]*/ 0x9c, 0x11, 0x04, 0x0e, 0x9c, 0xec, 0x58, 0x00, +/*[01a8]*/ 0x1c, 0xf2, 0x04, 0x20, 0x98, 0x8c, 0x60, 0x33, +/*[01b0]*/ 0x98, 0x0c, 0x60, 0x25, 0xa0, 0x01, 0x00, 0x00, +/* [01b8][01b9][01ba][01bb][01bc][01bd][01be][01bf]*/ +/*[01b8]*/ 0x98, 0x02, 0xb0, 0xa2, 0x87, 0x64, 0x7f, 0x67, +}; diff --git a/dsp3210/DSP3210_emulation.h b/dsp3210/DSP3210_emulation.h new file mode 100644 index 00000000..189e78cc --- /dev/null +++ b/dsp3210/DSP3210_emulation.h @@ -0,0 +1,81 @@ + + + +/********************************************************/ +/* Initialise the DSP emulator */ +/* */ +/********************************************************/ +void DSP_init_emu (); + +/********************************************************/ +/* Shut down the DSP emulator */ +/* */ +/********************************************************/ +void DSP_shutdown_emu (); + +/********************************************************/ +/* Reset the DSP */ +/* */ +/********************************************************/ +void DSP_reset(); +//note this is triggered via bit 7 of 0xDD0080 going from 1 to 0 + +/********************************************************/ +/* Trigger an interrupt level 0 */ +/* */ +/********************************************************/ +bool DSP_int0(); +bool DSP_int0_masked(); +//note this is triggered via bit 0 of 0xDD0080 going from 1 to 0 + +/********************************************************/ +/* Trigger an interrupt level 1 */ +/* */ +/********************************************************/ +bool DSP_int1(); +bool DSP_int1_masked(); +//note this is triggered via bit 1 of 0xDD0080 going from 1 to 0 + +/********************************************************/ +/* DSP has changed M68k interrupt line */ +/* */ +/********************************************************/ +void DSP_external_interrupt(int32_t level, int32_t state); +//state is the state of the associated line, 0 triggers an M68k interrupt +//level=0 corresponds to INT2, level=1 corresponds to INT6 +//this routine needs to mask interrupts + +/********************************************************/ +/* Execute a single DSP instruction, allowing for */ +/* instruction and memory latencies */ +/********************************************************/ +void DSP_execute_insn (); + +/********************************************************/ +/* Read values from the Amiga's memory space */ +/* */ +/********************************************************/ + +uint32_t DSP_get_long_ext(uint32_t addr); +uint16_t DSP_get_short_ext(uint32_t addr); +unsigned char DSP_get_char_ext(uint32_t addr); + + +/********************************************************/ +/* Set values in the Amiga's memory space */ +/* */ +/********************************************************/ + +void DSP_set_long_ext(uint32_t addr, uint32_t value); +void DSP_set_short_ext(uint32_t addr, uint16_t value); +void DSP_set_char_ext(uint32_t addr, unsigned char value); + +extern char DSP_irsh_flag; + +//Notes: +//The DSP write register is byte sized and located at 0xDD0080 +//The DSP read register (which should mirror the write register) +//is long word sized and located at 0xDD005C +// +//For more details on the Amiga interface to the DSP3210, see here: +//http://www.devili.iki.fi/mirrors/haynie/research/a3000p/docs/dspprg.pdf \ No newline at end of file diff --git a/dsp3210/dsp_glue.cpp b/dsp3210/dsp_glue.cpp new file mode 100644 index 00000000..5c9b88c5 --- /dev/null +++ b/dsp3210/dsp_glue.cpp @@ -0,0 +1,353 @@ + +#include "stdlib.h" +#include "stdint.h" + +#include "dsp3210/DSP3210_emulation.h" + +#include "sysconfig.h" +#include "sysdeps.h" +#include "options.h" +#include "memory.h" +#include "custom.h" +#include "devices.h" +#include "uae.h" +#include "autoconf.h" +#include "debug.h" +#include "newcpu.h" +#include "threaddep/thread.h" +#include "dsp_glue.h" + +#define DSP_INST_COUNT_WAIT 1000 + +int log_dsp = 0; +static volatile uae_u8 dsp_status; +bool is_dsp_installed; +static volatile int dsp_thread_running; +static uae_sem_t reset_sem, pause_sem; +static volatile uae_atomic dsp_int; +static volatile uae_atomic dsp_int_ext; +static int dsp_int0_delay, dsp_int1_delay; +static volatile bool dsp_running; +static volatile uae_u32 dsp_inst_cnt; +static bool dsp_paused; + +static bool dsp_addr_check(uint32_t addr) +{ + addrbank *ab = &get_mem_bank(addr); + if ((ab->flags & ABFLAG_THREADSAFE) == 0 && ab != &dummy_bank) { + write_log("DSP accesses non-threadsafe address %08x!\n", addr); + return false; + } + return true; +} +static uint32_t safe_memory_read(uint32_t addr, int size) +{ + return 0; +} +static void safe_memory_write(uint32_t addr, uint32_t data, int size) +{ +} + +uint32_t DSP_get_long_ext(uint32_t addr) +{ + int32_t v; + if (dsp_addr_check(addr)) { + v = get_long(addr); + } else { + v = safe_memory_read(addr, 4); + } + v = _byteswap_ulong(v); + if (log_dsp) { + write_log("DSP LGET %08x = %08x\n", addr, v); + } + return v; +} + +uint16_t DSP_get_short_ext(uint32_t addr) +{ + uint16_t v; + if (dsp_addr_check(addr)) { + v = get_word(addr); + } else { + v = safe_memory_read(addr, 2); + } + v = _byteswap_ushort(v); + if (log_dsp) { + write_log("DSP WGET %08x = %04x\n", addr, v & 0xffff); + } + return v; +} + +unsigned char DSP_get_char_ext(uint32_t addr) +{ + unsigned char v; + if (dsp_addr_check(addr)) { + v = get_byte(addr); + } else { + v = safe_memory_read(addr, 1); + } + if (log_dsp) { + write_log("DSP BGET %08x = %02x\n", addr, v & 0xff); + } + return v; +} + +void DSP_set_long_ext(uint32_t addr, uint32_t v) +{ + v = _byteswap_ulong(v); + if (log_dsp) { + write_log("DSP LPUT %08x = %08x\n", addr, v); + } + if (dsp_addr_check(addr)) { + put_long(addr, v); + } else { + safe_memory_write(addr, v, 4); + } +} + +void DSP_set_short_ext(uint32_t addr, uint16_t v) +{ + v = _byteswap_ushort(v); + if (log_dsp) { + write_log("DSP WPUT %08x = %04x\n", addr, v & 0xffff); + } + if (dsp_addr_check(addr)) { + put_word(addr, v); + } else { + safe_memory_write(addr, v, 2); + } +} + +void DSP_set_char_ext(uint32_t addr, unsigned char v) +{ + if (log_dsp) { + write_log("DSP BPUT %08x = %02x\n", addr, v & 0xff); + } + if (dsp_addr_check(addr)) { + put_byte(addr, v); + } else { + safe_memory_write(addr, v, 1); + } +} + +static void dsp_status_intx(void) +{ + dsp_status &= ~(1 | 2 | 4 | 8); + dsp_status |= dsp_int; + dsp_status |= dsp_int_ext; +} + +static void dsp_rethink(void) +{ + dsp_status_intx(); + if ((dsp_status & 0x20) && !(dsp_status & 8)) { + if (log_dsp) { + write_log("DSP INTREQ level 6\n"); + } + INTREQ_0(0x8000 | 0x2000); + } + if ((dsp_status & 0x10) && !(dsp_status & 4)) { + if (log_dsp) { + write_log("DSP INTREQ level 2\n"); + } + INTREQ_0(0x8000 | 0x0008); + } +} + +static void dsp_reset(void) +{ + dsp_int = 0x01 | 0x02; + dsp_int_ext = 0x04 | 0x08; +} + +static void cpu_wait(void) +{ + while (dsp_inst_cnt < DSP_INST_COUNT_WAIT && dsp_thread_running > 0) { + x_do_cycles(CYCLE_UNIT * 8); + } +} + +// stop CPU for a while if DSP was not waiting for interrupt +static void dsp_do_int(int i) +{ + int mask = ~(1 << i); + if (log_dsp) { + write_log("DSP INT%d\n", i); + } + // stop CPU if DSP is not waiting for interrupt + if (DSP_irsh_flag != 4) { + dsp_inst_cnt = 0; + atomic_and(&dsp_int, mask); + cpu_wait(); + } else { + atomic_and(&dsp_int, mask); + } +} + +void dsp_write(uae_u8 v) +{ + dsp_status_intx(); + if (log_dsp) { + write_log("DSP write %02x (%02x) PC=%08x\n", v, dsp_status, M68K_GETPC); + } + if (!(dsp_status & 0x80) && (v & 0x80)) { + dsp_status |= 0x80; + write_log("DSP reset released\n"); + dsp_inst_cnt = 0; + uae_sem_post(&reset_sem); + cpu_wait(); + write_log("DSP reset delay end\n"); + } else if ((dsp_status & 0x80) && !(v & 0x80)) { + write_log("DSP reset activated\n"); + dsp_status &= ~0x80; + dsp_reset(); + } + if ((dsp_status & 1) && !(v & 1)) { + dsp_do_int(0); + } else if (v & 1) { + atomic_or(&dsp_int, 1); + } + if ((dsp_status & 2) && !(v & 2)) { + dsp_do_int(1); + } else if (v & 2) { + atomic_or(&dsp_int, 2); + } + dsp_status = (v & (0x40 | 0x20 | 0x10)) | (dsp_status & 0x80); + dsp_status_intx(); + if (log_dsp) { + write_log("-> %02x\n", dsp_status); + } +} + +uae_u8 dsp_read(void) +{ + dsp_status_intx(); + uae_u8 v = dsp_status; + if (log_dsp) { + write_log("DSP read %02x\n", v); + } + return v; +} + +void DSP_external_interrupt(int32_t level, int32_t state) +{ + int32_t mask = level ? 0x08 : 0x04; + if (state) { + if (log_dsp && !(dsp_status & mask)) { + write_log("DSP interrupt %d = %d\n", level, state); + } + atomic_and(&dsp_int_ext, ~mask); + } else { + if (log_dsp && (dsp_status & mask)) { + write_log("DSP interrupt %d = %d\n", level, state); + } + atomic_or(&dsp_int_ext, mask); + } + atomic_or(&uae_int_requested, 0x010000); +} + +static void dsp_thread(void *v) +{ + dsp_thread_running = 1; + DSP_init_emu(); + dsp_reset(); + dsp_int0_delay = 0; + dsp_int1_delay = 0; + + while (dsp_thread_running > 0) { + if (!(dsp_status & 0x80)) { + uae_sem_wait(&reset_sem); + dsp_reset(); + DSP_reset(); + dsp_inst_cnt = 0; + } + if (dsp_paused) { + uae_sem_wait(&pause_sem); + continue; + } + if (dsp_status & 0x80) { + DSP_execute_insn(); + dsp_inst_cnt++; + if (!(dsp_int & 1)) { + dsp_int0_delay++; + if (DSP_int0_masked()) { + dsp_int0_delay = 0; + if (log_dsp) { + write_log("DSP interrupt 0 masked\n"); + } + } + if (dsp_int0_delay > 2) { + if (DSP_int0()) { + if (log_dsp) { + write_log(_T("DSP interrupt 0 started\n")); + } + } + atomic_or(&dsp_int, 1); + dsp_int0_delay = 0; + } + } + if (!(dsp_int & 2)) { + dsp_int1_delay++; + if (DSP_int1_masked()) { + dsp_int1_delay = 0; + if (log_dsp) { + write_log("DSP interrupt 1 masked\n"); + } + } + if (dsp_int1_delay > 2) { + if (DSP_int1()) { + if (log_dsp) { + write_log(_T("DSP interrupt 1 started\n")); + } + } + atomic_or(&dsp_int, 2); + dsp_int1_delay = 0; + } + } + } + } + DSP_shutdown_emu(); + dsp_status = 0; + dsp_thread_running = 0; +} + +static void dsp_free(void) +{ + write_log("DSP free\n"); + if (dsp_thread_running > 0) { + dsp_status &= ~0x80; + dsp_thread_running = -1; + uae_sem_post(&reset_sem); + uae_sem_post(&pause_sem); + while (dsp_thread_running) { + sleep_millis(2); + } + uae_sem_destroy(&reset_sem); + } + is_dsp_installed = false; +} + +bool dsp_init(struct autoconfig_info *aci) +{ + aci->start = 0xdd0000; + aci->size = 0x10000; + dsp_status = 0; + dsp_reset(); + dsp_status_intx(); + if (aci->doinit) { + is_dsp_installed = true; + write_log("DSP init\n"); + device_add_rethink(dsp_rethink); + device_add_exit(NULL, dsp_free); + uae_sem_init(&reset_sem, 0, 0); + uae_sem_init(&pause_sem, 0, 0); + uae_start_thread(NULL, dsp_thread, NULL, NULL); + } + return true; +} + +void dsp_pause(int pause) +{ + dsp_paused = pause; + uae_sem_post(&pause_sem); +} diff --git a/dsp3210/dsp_glue.h b/dsp3210/dsp_glue.h new file mode 100644 index 00000000..47a4807f --- /dev/null +++ b/dsp3210/dsp_glue.h @@ -0,0 +1,7 @@ + +bool dsp_init(struct autoconfig_info *aci); +void dsp_write(uae_u8); +uae_u8 dsp_read(void); +void dsp_pause(int); + +extern bool is_dsp_installed; diff --git a/expansion.cpp b/expansion.cpp index 0f962275..93266a1e 100644 --- a/expansion.cpp +++ b/expansion.cpp @@ -50,6 +50,7 @@ #include "sana2.h" #include "arcadia.h" #include "devices.h" +#include "dsp3210/dsp_glue.h" #define CARD_FLAG_CAN_Z3 1 @@ -5289,6 +5290,14 @@ const struct expansionromtype expansionroms[] = { NULL, 0, false, EXPANSIONTYPE_INTERNAL }, +#ifdef WITH_DSP + { + _T("dsp3210"), _T("DSP3210"), _T("AT&T"), + NULL, dsp_init, NULL, NULL, ROMTYPE_DSP3210 | ROMTYPE_NOT, 0, 0, BOARD_NONAUTOCONFIG_BEFORE, true, + NULL, 0, + false, EXPANSIONTYPE_INTERNAL + }, +#endif /* PCI Bridgeboards */ diff --git a/gayle.cpp b/gayle.cpp index 312d2210..cc807faf 100644 --- a/gayle.cpp +++ b/gayle.cpp @@ -36,6 +36,7 @@ #include "autoconf.h" #include "rommgr.h" #include "devices.h" +#include "dsp3210/dsp_glue.h" #define PCMCIA_SRAM 1 #define PCMCIA_IDE 2 @@ -475,6 +476,14 @@ static int gayle_read (uaecptr addr) uaecptr oaddr = addr; uae_u32 v = 0; int got = 0; + + if (is_dsp_installed) { + uaecptr daddr = addr & 0xffff; + if (daddr == 0x5f || daddr == 0x80) { + v = dsp_read(); + return v; + } + } if (currprefs.cs_ide == IDE_A600A1200) { if ((addr & 0xA0000) != 0xA0000) return 0; @@ -513,9 +522,17 @@ static void gayle_write (uaecptr addr, int val) { uaecptr oaddr = addr; int got = 0; + + if (is_dsp_installed) { + uaecptr daddr = addr & 0xffff; + if (daddr == 0x5f || daddr == 0x80) { + dsp_write(val); + } + } if (currprefs.cs_ide == IDE_A600A1200) { - if ((addr & 0xA0000) != 0xA0000) + if ((addr & 0xA0000) != 0xA0000) { return; + } } addr &= 0xffff; if (currprefs.cs_pcmcia) { @@ -540,7 +557,6 @@ static void gayle_write (uaecptr addr, int val) write_log (_T("PCMCIA CONFIG WRITE %08X=%02X PC=%08X\n"), oaddr, (uae_u32)val & 0xff, M68K_GETPC); } } - if (GAYLE_LOG) write_log (_T("GAYLE_WRITE %08X=%02X PC=%08X\n"), oaddr, (uae_u32)val & 0xff, M68K_GETPC); if (!got) diff --git a/include/rommgr.h b/include/rommgr.h index e7973aee..ca34b6dd 100644 --- a/include/rommgr.h +++ b/include/rommgr.h @@ -206,6 +206,7 @@ extern int decode_cloanto_rom_do(uae_u8 *mem, int size, int real_size); #define ROMTYPE_DEVHD 0x0010008c #define ROMTYPE_CSMK1SCSI 0x0010008d #define ROMTYPE_GVPA1208 0x0010008e +#define ROMTYPE_DSP3210 0x0010008f #define ROMTYPE_NOT 0x00800000 #define ROMTYPE_QUAD 0x01000000 diff --git a/od-win32/sysconfig.h b/od-win32/sysconfig.h index 04e917c1..62499a03 100644 --- a/od-win32/sysconfig.h +++ b/od-win32/sysconfig.h @@ -117,6 +117,7 @@ #define WITH_SOFTFLOAT #define FLOPPYBRIDGE #define WITH_MIDIEMU +#define WITH_DSP #else diff --git a/od-win32/win32.cpp b/od-win32/win32.cpp index 04c6008d..718b4743 100644 --- a/od-win32/win32.cpp +++ b/od-win32/win32.cpp @@ -125,6 +125,7 @@ extern int log_a2065, a2065_promiscuous, log_ethernet; extern int rawinput_enabled_hid, rawinput_log; extern int log_filesys; extern int forcedframelatency; +extern int log_dsp; int log_scsi; int log_net; int log_vsync, debug_vsync_min_delay, debug_vsync_forced_delay; @@ -6774,6 +6775,10 @@ static int parseargs(const TCHAR *argx, const TCHAR *np, const TCHAR *np2) log_rp = 3; return 1; } + if (!_tcscmp(arg, _T("dsplog"))) { + log_dsp = 1; + return 1; + } if (!_tcscmp(arg, _T("nomultidisplay"))) { return 1; } diff --git a/od-win32/winuae_msvc15/winuae_msvc.vcxproj b/od-win32/winuae_msvc15/winuae_msvc.vcxproj index 35119929..c2a8abe1 100644 --- a/od-win32/winuae_msvc15/winuae_msvc.vcxproj +++ b/od-win32/winuae_msvc15/winuae_msvc.vcxproj @@ -1327,6 +1327,8 @@ + + diff --git a/od-win32/winuae_msvc15/winuae_msvc.vcxproj.filters b/od-win32/winuae_msvc15/winuae_msvc.vcxproj.filters index 9a92b75e..3cc05090 100644 --- a/od-win32/winuae_msvc15/winuae_msvc.vcxproj.filters +++ b/od-win32/winuae_msvc15/winuae_msvc.vcxproj.filters @@ -74,6 +74,9 @@ {5c4c971a-37b6-4c1e-82f1-d225ebb12808} ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe + + {6f046035-4e6d-4038-a65f-d789a89ee702} + @@ -991,6 +994,12 @@ common + + dsp3210 + + + dsp3210 + -- 2.47.3