auto HG51B::push() -> void { stack[7] = stack[6]; stack[6] = stack[5]; stack[5] = stack[4]; stack[4] = stack[3]; stack[3] = stack[2]; stack[2] = stack[1]; stack[1] = stack[0]; stack[0] = regs.pc; } auto HG51B::pull() -> void { regs.pc = stack[0]; stack[0] = stack[1]; stack[1] = stack[2]; stack[2] = stack[3]; stack[3] = stack[4]; stack[4] = stack[5]; stack[5] = stack[6]; stack[6] = stack[7]; stack[7] = 0x0000; } //Shift-A: math opcodes can shift A register prior to ALU operation auto HG51B::sa() -> uint { switch(opcode & 0x0300) { default: case 0x0000: return regs.a << 0; case 0x0100: return regs.a << 1; case 0x0200: return regs.a << 8; case 0x0300: return regs.a << 16; } } //Register-or-Immediate: most opcodes can load from a register or immediate auto HG51B::ri() -> uint { if(opcode & 0x0400) return opcode & 0xff; return registerRead(opcode & 0xff); } //New-PC: determine jump target address; opcode.d9 = long jump flag (1 = yes) auto HG51B::np() -> uint { if(opcode & 0x0200) return (regs.p << 8) | (opcode & 0xff); return (regs.pc & 0xffff00) | (opcode & 0xff); } auto HG51B::instruction() -> void { if((opcode & 0xffff) == 0x0000) { //0000 0000 0000 0000 //nop } else if((opcode & 0xdd00) == 0x0800) { //00.0 10.0 .... .... //jump i if(opcode & 0x2000) push(); regs.pc = np(); } else if((opcode & 0xdd00) == 0x0c00) { //00.0 11.0 .... .... //jumpeq i if(regs.z) { if(opcode & 0x2000) push(); regs.pc = np(); } } else if((opcode & 0xdd00) == 0x1000) { //00.1 00.0 .... .... //jumpge i if(regs.c) { if(opcode & 0x2000) push(); regs.pc = np(); } } else if((opcode & 0xdd00) == 0x1400) { //00.1 01.0 .... .... //jumpmi i if(regs.n) { if(opcode & 0x2000) push(); regs.pc = np(); } } else if((opcode & 0xffff) == 0x1c00) { //0001 1100 0000 0000 //loop? } else if((opcode & 0xfffe) == 0x2500) { //0010 0101 0000 000. //skiplt/skipge if(regs.c == (opcode & 1)) regs.pc++; } else if((opcode & 0xfffe) == 0x2600) { //0010 0110 0000 000. //skipne/skipeq if(regs.z == (opcode & 1)) regs.pc++; } else if((opcode & 0xfffe) == 0x2700) { //0010 0111 0000 000. //skipmi/skippl if(regs.n == (opcode & 1)) regs.pc++; } else if((opcode & 0xffff) == 0x3c00) { //0011 1100 0000 0000 //ret pull(); } else if((opcode & 0xffff) == 0x4000) { //0100 0000 0000 0000 //rdbus regs.busdata = read(regs.busaddr++); } else if((opcode & 0xf800) == 0x4800) { //0100 1... .... .... //cmpr a<= 0; } else if((opcode & 0xf800) == 0x5000) { //0101 0... .... .... //cmp a<= 0; } else if((opcode & 0xfb00) == 0x5900) { //0101 1.01 .... .... //sxb regs.a = (int8)ri(); } else if((opcode & 0xfb00) == 0x5a00) { //0101 1.10 .... .... //sxw regs.a = (int16)ri(); } else if((opcode & 0xfb00) == 0x6000) { //0110 0.00 .... .... //ld a,ri regs.a = ri(); } else if((opcode & 0xfb00) == 0x6100) { //0110 0.01 .... .... //ld ?,ri } else if((opcode & 0xfb00) == 0x6300) { //0110 0.11 .... .... //ld p,ri regs.p = ri(); } else if((opcode & 0xfb00) == 0x6800) { //0110 1.00 .... .... //rdraml uint24 target = ri() + (opcode & 0x0400 ? regs.ramaddr : (uint24)0); if(target < 0xc00) regs.ramdata = (regs.ramdata & 0xffff00) | (dataRAM[target] << 0); } else if((opcode & 0xfb00) == 0x6900) { //0110 1.01 .... .... //rdramh uint24 target = ri() + (opcode & 0x0400 ? regs.ramaddr : (uint24)0); if(target < 0xc00) regs.ramdata = (regs.ramdata & 0xff00ff) | (dataRAM[target] << 8); } else if((opcode & 0xfb00) == 0x6a00) { //0110 1.10 .... .... //rdramb uint24 target = ri() + (opcode & 0x0400 ? regs.ramaddr : (uint24)0); if(target < 0xc00) regs.ramdata = (regs.ramdata & 0x00ffff) | (dataRAM[target] << 16); } else if((opcode & 0xffff) == 0x7000) { //0111 0000 0000 0000 //rdrom regs.romdata = dataROM[regs.a & 0x3ff]; } else if((opcode & 0xff00) == 0x7c00) { //0111 1100 .... .... //ld pl,i regs.p = (regs.p & 0xff00) | ((opcode & 0xff) << 0); } else if((opcode & 0xff00) == 0x7d00) { //0111 1101 .... .... //ld ph,i regs.p = (regs.p & 0x00ff) | ((opcode & 0xff) << 8); } else if((opcode & 0xf800) == 0x8000) { //1000 0... .... .... //add a< 0xffffff; } else if((opcode & 0xf800) == 0x8800) { //1000 1... .... .... //subr a<= 0; } else if((opcode & 0xf800) == 0x9000) { //1001 0... .... .... //sub a<= 0; } else if((opcode & 0xfb00) == 0x9800) { //1001 1.00 .... .... //mul a,ri int64 x = (int24)regs.a; int64 y = (int24)ri(); x *= y; regs.accl = x >> 0ull; regs.acch = x >> 24ull; regs.n = regs.acch & 0x800000; regs.z = x == 0; } else if((opcode & 0xf800) == 0xa800) { //1010 1... .... .... //xor a<> ri(); regs.n = regs.a & 0x800000; regs.z = regs.a == 0; } else if((opcode & 0xfb00) == 0xc800) { //1100 1.00 .... .... //asr a,ri regs.a = (int24)regs.a >> ri(); regs.n = regs.a & 0x800000; regs.z = regs.a == 0; } else if((opcode & 0xfb00) == 0xd000) { //1101 0.00 .... .... //ror a,ri uint24 length = ri(); regs.a = (regs.a >> length) | (regs.a << (24 - length)); regs.n = regs.a & 0x800000; regs.z = regs.a == 0; } else if((opcode & 0xfb00) == 0xd800) { //1101 1.00 .... .... //shl a,ri regs.a = regs.a << ri(); regs.n = regs.a & 0x800000; regs.z = regs.a == 0; } else if((opcode & 0xff00) == 0xe000) { //1110 0000 .... .... //st r,a registerWrite(opcode & 0xff, regs.a); } else if((opcode & 0xfb00) == 0xe800) { //1110 1.00 .... .... //wrraml uint24 target = ri() + (opcode & 0x0400 ? regs.ramaddr : (uint24)0); if(target < 0xc00) dataRAM[target] = regs.ramdata >> 0; } else if((opcode & 0xfb00) == 0xe900) { //1110 1.01 .... .... //wrramh uint24 target = ri() + (opcode & 0x0400 ? regs.ramaddr : (uint24)0); if(target < 0xc00) dataRAM[target] = regs.ramdata >> 8; } else if((opcode & 0xfb00) == 0xea00) { //1110 1.10 .... .... //wrramb uint24 target = ri() + (opcode & 0x0400 ? regs.ramaddr : (uint24)0); if(target < 0xc00) dataRAM[target] = regs.ramdata >> 16; } else if((opcode & 0xff00) == 0xf000) { //1111 0000 .... .... //swap a,r uint24 source = registerRead(opcode & 0xff); uint24 target = regs.a; regs.a = source; registerWrite(opcode & 0xff, target); } else if((opcode & 0xffff) == 0xfc00) { //1111 1100 0000 0000 //halt regs.halt = true; } else { print("Hitachi DSP: unknown opcode @ ", hex(regs.pc - 1, 4L), " = ", hex(opcode, 4L), "\n"); regs.halt = true; } }