#include "opcode.h" #include #if bench #include #endif #include #define THREADS 1 #define BENCH_INST 100000000 << (THREADS-1) #define CTRL_ADDR 0x100 #define TX_ADDR 0x101 #define RX_ADDR 0x102 #define STEP_ADDR 0x110 #define CURSES_BACKSPACE 0x7F extern uint8_t kbd_rdy; extern WINDOW *scr; #if debug extern uint8_t subdbg; #endif extern uint8_t step; extern uint8_t esc; #define setflag(flag, bit) ((flag)) ? (cpu->ps.u8[thread] |= bit) : (cpu->ps.u8[thread] &= ~bit) #define getflag(bit) (cpu->ps.u8[thread] & bit) extern pthread_mutex_t mutex; extern pthread_mutex_t main_mutex; extern pthread_cond_t cond; extern pthread_cond_t main_cond; #if debug extern void disasm(struct sux *cpu, uint64_t *operands, uint8_t lines, uint8_t opcode, uint8_t prefix, uint8_t thread); #endif extern void io(uint64_t address, uint8_t rw); static inline uint64_t get_addr(struct sux *cpu, uint64_t *tmpaddr, uint8_t opcode, uint8_t prefix, uint8_t thread) { union reg address; union reg value; uint8_t tmp = 0; uint64_t tmp2 = 0; union reg saveaddr; address.u64 = 0; value.u64 = 0; switch (optype[opcode]) { case IMPL: break; case IMM: address.u64 = cpu->pc; switch (opcode) { case LSL_IMM: case LSR_IMM: case ROL_IMM: case ROR_IMM: case ASR_IMM: ++cpu->pc; break; default : cpu->pc+=(1 << ((prefix >> 4) & 3)); /* Falls Through. */ case TXS_IMM: break; } break; case ZM: case ZMX: case ZMY: case IND: case INDX: case INDY: tmp = 0; address.u8[0] = addr[cpu->pc]; /* Unroll Loop by implementing Duff's Device. */ tmp = get_addrsize(prefix, ZM)+1; setreg_sw(address.u8, 0, addr, cpu->pc, prefix, ZM, AM); cpu->pc+=tmp; #if debug && !bench *tmpaddr = address.u64; #endif #if getclk iclk++; #endif uint64_t reg = 0; saveaddr.u64 = 0; if (prefix >> 6) { switch (prefix >> 6) { case 1: tmp2 = ((cpu->stk_st << 16) | cpu->sp); break; case 2: tmp2 = cpu->pc ; break; } saveaddr = address; switch ((prefix & 0x0C) >> 2) { case 0: saveaddr.u64 = tmp2 + (int8_t )address.u8[0] ; break; case 2: saveaddr.u64 = tmp2 + (int64_t)address.u64 ; break; case 1: case 3: saveaddr.u64 = tmp2 + (int32_t)address.u32[0]; break; } (optype[opcode] != INDY) ? (address.u64 = saveaddr.u64) : (reg = saveaddr.u64); } switch (optype[opcode]) { case ZMX: address.u64 += cpu->x; #if getclk iclk++; #endif break; case ZMY: address.u64 += cpu->y; #if getclk iclk++; #endif break; case INDX: case INDY: if (optype[opcode] == INDX) { address.u64 += cpu->x; #if getclk iclk++; #endif } else { reg += cpu->y; #if getclk iclk++; #endif } case IND: setreg(value.u8, +, 0, addr, +, address.u64, 7); #if getclk iclk++; #endif value.u64 += reg; address.u64 = value.u64; break; } break; case ABS: tmp = get_addrsize(prefix, ABS)+1; setreg_sw(address.u8, 0, addr, cpu->pc, prefix, ABS, AM); cpu->pc+=tmp; #if getclk iclk++; #endif saveaddr.u64 = 0; if (prefix >> 6) { switch (prefix >> 6) { case 1: tmp2 = ((cpu->stk_st << 16) | cpu->sp); break; case 2: tmp2 = cpu->pc ; break; } saveaddr = address; switch ((prefix & 0x0C) >> 2) { case 0: saveaddr.u64 = tmp2 + (int16_t)address.u16[0]; break; case 1: case 2: case 3: saveaddr.u64 = tmp2 + (int64_t)address.u64 ; break; } address.u64 = saveaddr.u64; } break; case REL: address.u64 = cpu->pc; cpu->pc+=(1 << ((prefix >> 4) & 3)); break; } return address.u64; } static inline void adc(struct sux *cpu, uint64_t value, uint8_t thread) { uint64_t sum = cpu->a+value+getflag(C); setflag(sum == 0, Z); setflag((sum >> 63), N); setflag(((cpu->a^value) >> 63) && ((cpu->a^sum) >> 63), V); setflag((sum < value), C); cpu->a = sum; } static inline void sbc(struct sux *cpu, uint64_t value, uint8_t thread) { uint64_t sum = cpu->a-value-!getflag(C); setflag(sum == 0, Z); setflag(sum >> 63, N); setflag(((cpu->a^value) >> 63) && ((cpu->a^sum) >> 63), V); setflag((sum > value), C); cpu->a = sum; } static inline void transfer(struct sux *cpu, uint64_t value, uint8_t opcode, uint8_t prefix, uint8_t thread) { uint64_t reg; switch (opcode) { case TBA_IMP: cpu->a = cpu->b; reg = cpu->a; break; case TXA_IMP: cpu->a = cpu->x; reg = cpu->a; break; case TYA_IMP: cpu->a = cpu->y; reg = cpu->a; break; case TAB_IMP: cpu->b = cpu->a; reg = cpu->b; break; case TAY_IMP: cpu->y = cpu->a; reg = cpu->y; break; case TXY_IMP: cpu->y = cpu->x; reg = cpu->y; break; case TAX_IMP: cpu->x = cpu->a; reg = cpu->x; break; case TYX_IMP: cpu->x = cpu->y; reg = cpu->x; break; case TSX_IMP: cpu->x = cpu->sp & 0xFFFF; cpu->x = cpu->stk_st << 16; break; case TXS_IMM: cpu->sp = cpu->x; if (prefix == 0x13 && (value == thread+1 || value > 8)) { cpu->stk_st = value & 0xFF; cpu->stk_st += value << 16; cpu->pc+=2; } break; } setflag(reg == 0, Z); setflag(reg >> 63, N); } static inline void push(struct sux *cpu, uint64_t value, uint8_t prefix, uint8_t thread) { union reg reg; reg.u64 = value; setreg(addr, -, (cpu->stk_st << 16)+cpu->sp, reg.u8, +, 0, (1 << ((prefix >> 4) & 3))-1); cpu->sp -= (1 << ((prefix >> 4) & 3)); } static inline uint64_t pull(struct sux *cpu, uint8_t prefix, uint8_t thread) { union reg reg; reg.u64 = 0; cpu->sp += (1 << ((prefix >> 4) & 3)); setreg(reg.u8, +, 0, addr, -, (cpu->stk_st << 16)+cpu->sp, (1 << ((prefix >> 4) & 3))-1); return reg.u64; } static inline void and(struct sux *cpu, uint64_t value, uint8_t thread) { cpu->a &= value; setflag(cpu->a == 0, Z); setflag(cpu->a >> 63, N); } static inline void or(struct sux *cpu, uint64_t value, uint8_t thread) { cpu->a |= value; setflag(cpu->a == 0, Z); setflag(cpu->a >> 63, N); } static inline void xor(struct sux *cpu, uint64_t value, uint8_t thread) { cpu->a ^= value; setflag(cpu->a == 0, Z); setflag(cpu->a >> 63, N); } static inline void lsl(struct sux *cpu, uint64_t value, uint8_t thread) { uint64_t sum = (value < 64) ? cpu->a << value : 0; setflag(sum == 0, Z); setflag(sum >> 63, N); setflag(cpu->a >> (64-value), C); cpu->a = sum; } static inline void lsr(struct sux *cpu, uint64_t value, uint8_t thread) { uint64_t sum = (value < 64) ? cpu->a >> value : 0; setflag(sum == 0, Z); setflag(sum >> 63, N); setflag(cpu->a & 1, C); cpu->a = sum; } static inline void asr(struct sux *cpu, uint64_t value, uint8_t thread) { uint8_t sign = cpu->a >> 63; uint64_t sum = (value < 64) ? (cpu->a >> value) | ((uint64_t)sign << 63) : 0; setflag(sum == 0, Z); setflag(sum >> 63, N); setflag(cpu->a & 1, C); cpu->a = sum; } static inline void rol(struct sux *cpu, uint64_t value, uint8_t thread) { uint64_t sum = cpu->a << value; sum |= getflag(C); setflag(sum == 0, Z); setflag(sum >> 63, N); setflag(cpu->a >> (uint64_t)(64-value), C); cpu->a = sum; } static inline void ror(struct sux *cpu, uint64_t value, uint8_t thread) { uint64_t sum = cpu->a >> value; sum |= (uint64_t)getflag(C) << (uint64_t)(64-value); setflag(sum == 0, Z); setflag(sum >> 63, N); setflag(cpu->a & 1, C); cpu->a = sum; } static inline void mul(struct sux *cpu, uint64_t value, uint8_t thread) { uint64_t sum = cpu->a*value; cpu->a = sum; setflag(sum == 0, Z); setflag(sum >> 63, N); setflag(!((cpu->a^value) >> 63) && ((cpu->a^sum) >> 63), V); } static inline void divd(struct sux *cpu, uint64_t value, uint8_t opcode, uint8_t thread) { uint64_t sum = cpu->a/value; if (opcode != DAB_IMP) { cpu->b = cpu->a % value; } else { value = cpu->b; cpu->x = cpu->a % value; } cpu->a = sum; setflag(sum == 0, Z); setflag((sum >> 63), N); } static inline void cmp(struct sux *cpu, uint64_t value, uint64_t reg, uint8_t thread) { uint64_t sum = reg-value; setflag(sum >> 63, N); setflag(((reg^value) >> 63) && ((reg^sum) >> 63), V); setflag(sum == 0, Z); setflag(reg >= value, C); } /* Increment, or Decrement register. */ static inline uint64_t idr(struct sux *cpu, uint64_t reg, uint8_t inc, uint8_t thread) { if (inc) { reg++; } else { reg--; } setflag(reg == 0, Z); setflag(reg >> 63, N); return reg; } /* Increment, or Decrement memory. */ static inline void idm(struct sux *cpu, uint64_t address, uint8_t prefix, uint8_t inc, uint8_t thread) { union reg value; value.u64 = 0; /* Unroll Loop by implementing Duff's Device. */ setreg_sw(value.u8, 0, addr, address, prefix, 0, RS); if (inc) { value.u64++; } else { value.u64--; } setflag(value.u64 == 0, Z); setflag(value.u64 >> 7, N); setreg_sw(addr, address, value.u8, 0, prefix, 0, RS); io(address, 0); } static inline uint64_t load(struct sux *cpu, uint64_t address, uint64_t reg, uint8_t prefix, uint8_t thread) { io(address, 1); union reg value; value.u64 = reg; setreg_sw(value.u8, 0, addr, address, prefix, 0, RS); setflag(value.u64 == 0, Z); setflag(value.u64 >> 63, N); return value.u64; } static inline void store(struct sux *cpu, uint64_t address, uint64_t reg, uint8_t prefix, uint8_t thread) { union reg value; value.u64 = reg; setreg_sw(addr, address, value.u8, 0, prefix, 0, RS); #if (IO || debug) && !branch #if keypoll pthread_mutex_lock(&mutex); #endif io(address, 0); #if keypoll pthread_mutex_unlock(&mutex); #endif #endif }