--- /dev/null
+
+#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))<<reg(RS2field(incode));
+ reg(RBfield(incode)) = value&0xFFFF;
+ SetCCnzCAU(value);
+ break;
+
+ case 12: //logical right shift
+ if(RS2field(incode)==23) //+n
+ value = (int32_t)(((uint32_t)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))<<reg(RS2field(incode));
+ reg(RBfield(incode)) = value;
+ SetCCnzCAU(value);
+ break;
+
+ case 12: //logical right shift
+ if(RS2field(incode)==23) //+n
+ value = (int32_t)(((uint32_t)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 || dtemp<max_neg_float) DSP_exception_UOflow();
+ if((dtemp>0 && dtemp<min_pos_float) || (dtemp<0 && dtemp>min_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,
+};