#include "opcode.h" #include #include #include #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 static const uint64_t mem_size = 0x04000000; /* Size of address space. */ extern uint8_t step; extern uint8_t end; #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, uint8_t lines, uint8_t opcode, uint8_t prefix, uint8_t thread); #endif /*#define KEYBUF_SIZE 0x40 char key[KEYBUF_SIZE];*/ extern int get_key(WINDOW *scr); extern void io(uint64_t address, uint8_t rw); extern void init_scr(); static inline uint64_t read_value(struct sux *cpu, uint64_t address, uint8_t size, uint8_t inc_clk, uint8_t check_io) { union reg value; value.u64 = 0; #if (IO || debug) && !branch #if keypoll pthread_mutex_lock(&mutex); #endif if (check_io) { io(address, 1); } #if keypoll pthread_mutex_unlock(&mutex); #endif #endif switch (size) { case 7: value.u8[7] = addr[address+7]; case 6: value.u8[6] = addr[address+6]; case 5: value.u8[5] = addr[address+5]; case 4: value.u8[4] = addr[address+4]; case 3: value.u8[3] = addr[address+3]; case 2: value.u8[2] = addr[address+2]; case 1: value.u8[1] = addr[address+1]; case 0: value.u8[0] = addr[address+0]; } #if getclk cpu->clk += inc_clk; #endif return value.u64; } static inline void write_value(struct sux *cpu, union reg value, uint64_t address, uint8_t size, uint8_t inc_clk, uint8_t check_io) { switch (size) { case 7: addr[address+7] = value.u8[7]; case 6: addr[address+6] = value.u8[6]; case 5: addr[address+5] = value.u8[5]; case 4: addr[address+4] = value.u8[4]; case 3: addr[address+3] = value.u8[3]; case 2: addr[address+2] = value.u8[2]; case 1: addr[address+1] = value.u8[1]; case 0: addr[address+0] = value.u8[0]; } #if (IO || debug) && !branch #if keypoll pthread_mutex_lock(&mutex); #endif if (check_io) { io(address, 0); } #if keypoll pthread_mutex_unlock(&mutex); #endif #endif #if getclk cpu->clk += inc_clk; #endif } static inline uint64_t offset_addr(struct sux *cpu, uint64_t offset, uint8_t size, uint8_t inc_clk, uint8_t prefix) { uint64_t of; switch (prefix >> 6) { case 1: of = ((cpu->stk_st << 16) | cpu->sp); break; case 2: of = cpu->pc ; break; } #if getclk cpu->clk += inc_clk; #endif switch (size) { case 0: return of + (int8_t )offset; case 1: return of + (int16_t)offset; case 2: case 3: return of + (int32_t)offset; case 4: case 5: case 6: case 7: return of + (int64_t)offset; } } static inline uint64_t imm_addr(struct sux *cpu) { return cpu->pc; } static inline uint64_t read_addr(struct sux *cpu, uint8_t prefix, uint8_t inc_clk, uint8_t type, uint8_t inc_pc) { uint64_t address; uint8_t size = get_addrsize(prefix, type); if (prefix >> 6) { address = offset_addr(cpu, read_value(cpu, cpu->pc, size, inc_clk, 0), size, inc_clk, prefix); } else { address = read_value(cpu, cpu->pc, size, inc_clk, 0); } if (inc_pc) { cpu->pc += size+1; } return address; } static inline uint64_t zmx_addr(struct sux *cpu, uint8_t prefix, uint8_t inc_clk, uint8_t inc_pc) { #if getclk cpu->clk += inc_clk; #endif return read_addr(cpu, prefix, inc_clk, ZM, inc_pc) + cpu->x; } static inline uint64_t zmy_addr(struct sux *cpu, uint8_t prefix, uint8_t inc_clk, uint8_t inc_pc) { #if getclk cpu->clk += inc_clk; #endif return read_addr(cpu, prefix, inc_clk, ZM, inc_pc) + cpu->y; } static inline uint64_t ind_addr(struct sux *cpu, uint8_t prefix, uint8_t inc_clk, uint8_t inc_pc) { return read_value(cpu, read_addr(cpu, prefix, inc_clk, ZM, inc_pc), 7, inc_clk, 0); } static inline uint64_t indx_addr(struct sux *cpu, uint8_t prefix, uint8_t inc_clk, uint8_t inc_pc) { #if getclk cpu->clk += inc_clk; #endif return read_value(cpu, read_addr(cpu, prefix, inc_clk, ZM, inc_pc)+cpu->x, 7, inc_clk, 0); } static inline uint64_t indy_addr(struct sux *cpu, uint8_t prefix, uint8_t inc_clk, uint8_t inc_pc) { #if getclk cpu->clk += inc_clk; #endif return ind_addr(cpu, prefix, inc_clk, inc_pc) + cpu->y; } static inline uint64_t rel_addr(struct sux *cpu, uint8_t prefix, uint8_t inc_clk, uint8_t inc_pc) { uint8_t rs = (prefix >> 4) & 3; uint8_t size = (1 << rs) - 1; uint64_t offset = read_value(cpu, cpu->pc, size, inc_clk, 0); uint64_t address; if (inc_pc) { cpu->pc += (size + 1); } #if getclk cpu->clk += inc_clk; #endif switch (rs) { default: return cpu->pc + (int8_t )offset; case 1 : return cpu->pc + (int16_t)offset; case 2 : return cpu->pc + (int32_t)offset; case 3 : return cpu->pc + (int64_t)offset; } } static inline uint64_t get_addr(struct sux *cpu, uint8_t opcode, uint8_t prefix, uint8_t inc_pc, uint8_t inc_clk, uint8_t thread) { uint64_t address = 0; switch (optype[opcode]) { case BREG: case IMPL: break; case IMM: address = imm_addr(cpu); switch (opcode) { case LSL_IMM: case LSR_IMM: case ROL_IMM: case ROR_IMM: case ASR_IMM: if (inc_pc) { ++cpu->pc; } break; default: if (inc_pc) { cpu->pc+=(1 << ((prefix >> 4) & 3)); } /* Falls Through. */ case TXS_IMM: break; } break; case ZM : return read_addr(cpu, prefix, inc_clk, ZM, inc_pc); case ABS : return read_addr(cpu, prefix, inc_clk, ABS, inc_pc); case ZMX : return zmx_addr(cpu, prefix, inc_clk, /**/ inc_pc); case ZMY : return zmy_addr(cpu, prefix, inc_clk, /**/ inc_pc); case IND : return ind_addr(cpu, prefix, inc_clk, /**/ inc_pc); case INDX: return indx_addr(cpu, prefix, inc_clk, /**/ inc_pc); case INDY: return indy_addr(cpu, prefix, inc_clk, /**/ inc_pc); case REL : return rel_addr(cpu, prefix, inc_clk, /**/ inc_pc); } return address; } 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 size, uint8_t thread) { union reg reg; reg.u64 = value; uint64_t sbr = (cpu->stk_st << 16); write_value(cpu, reg, (sbr+cpu->sp)-size, size, 1, 0); cpu->sp -= size+1; } static inline uint64_t pull(struct sux *cpu, uint8_t size, uint8_t thread) { uint64_t sbr = (cpu->stk_st << 16); uint64_t value = read_value(cpu, sbr+cpu->sp+1, size, 1, 0); cpu->sp += size+1; return value; } 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 != DIV_B) { 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) { uint8_t size = (1 << ((prefix >> 4) & 3))-1; union reg value; value.u64 = read_value(cpu, address, size, 1, 0); if (inc) { value.u64++; } else { value.u64--; } uint8_t sign = 0; switch ((prefix >> 4) & 3) { default: sign = 7; break; case 1: sign = 15; break; case 2: sign = 31; break; case 3: sign = 63; break; } setflag(value.u64 == 0, Z); setflag(value.u64 >> sign, N); write_value(cpu, value, address, size, 1, 1); } static inline uint64_t load(struct sux *cpu, uint64_t value, uint8_t thread) { setflag(value == 0, Z); setflag(value >> 63, N); return value; } static inline void store(struct sux *cpu, uint64_t address, uint64_t reg, uint8_t prefix, uint8_t thread) { uint8_t size = (1 << ((prefix >> 4) & 3))-1; union reg value; value.u64 = reg; write_value(cpu, value, address, size, 1, 1); }