#include "opcode.h" #include #include #include #include #if bench #include #include #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 #define copy64 extern uint8_t kbd_rdy; extern uint8_t dbg_print_per_inst; extern WINDOW *scr; extern WINDOW *regs; extern WINDOW *inst_win; extern WINDOW *dbg_win; #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)) #define ORTHO_1CC(mne, cc) \ mne##_R##cc: case mne##_M##cc #define ORTHO_1OP(mne) \ mne##_R: case mne##_M #define ORTHO_2OP(mne) \ mne##_RR: case mne##_RM: case mne##_MR: case mne##_MM 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 print_info(struct sux *cpu, WINDOW *w, uint8_t lines, uint8_t thread); extern void print_regs(struct sux *cpu, WINDOW *w); extern void disasm(struct sux *cpu, WINDOW *w, uint8_t lines, uint8_t opcode, uint8_t prefix, uint8_t ext_prefix, uint8_t prefix2, uint8_t *op_type, uint8_t *op_id, 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*/ uint8_t get_addrsize(uint8_t prefix, uint8_t addrmode) { uint8_t id = (prefix & 0x0C) >> 2; switch (addrmode) { case ZM: case ZMX: case ZMY: case IND: case INDX: case INDY: switch (id) { case 2: return 5; case 3: return 3; case 1: return 2; case 0: return 0; } break; case ABS: case ABSX: case ABSY: case AIND: case AINDX: case AINDY: switch (id) { case 3: return 7; case 2: return 6; case 1: return 4; case 0: return 1; } break; } return 0xFF; } static /*inline*/ uint8_t get_ortho_addrsize(uint8_t prefix, uint8_t addrmode) { uint8_t type = IMM; switch (addrmode) { case MEM_ABS : case MEM_ABSR : case MEM_AIND : case MEM_AINDR: case MEM_ARIND: type = ABS; break; case MEM_ZM : case MEM_ZMR : case MEM_IND : case MEM_ZINDR: case MEM_ZRIND: type = ZM; break; } return get_addrsize(prefix, type); } static int is_1op(uint8_t opcode) { switch (opcode) { case ORTHO_1OP(JMP): case ORTHO_1OP(JSR): case ORTHO_1OP(PSH): case ORTHO_1OP(PEA): case ORTHO_1OP(PUL): case ORTHO_1OP(SWP): case ORTHO_1OP(NOT): case ORTHO_1OP(NEG): case ORTHO_1OP(DEC): case ORTHO_1OP(INC): case ORTHO_1OP(CLZ): case ORTHO_1OP(CLO): return 1; } return 0; } static int is_1cc(uint8_t opcode) { switch (opcode) { case ORTHO_1CC(SET, NG): case ORTHO_1CC(SET, PO): case ORTHO_1CC(SET, CS): case ORTHO_1CC(SET, CC): case ORTHO_1CC(SET, EQ): case ORTHO_1CC(SET, NE): case ORTHO_1CC(SET, VS): case ORTHO_1CC(SET, VC): return 1; } return 0; } static /*inline*/ uint8_t isrw(uint8_t opcode, uint8_t ext_prefix) { if ((ext_prefix & 0xD) == 0xD) { switch (ext_prefix >> 4) { case 0x0: switch (opcode) { case STA_E : case STB_E : case STX_E : case STY_E : case STE_AB: case STE_Z : case STS_AB: case STS_Z : case STS_E : case STZ_AB: case STZ_Z : case STZ_E : case SNG_E : case SPO_E : case SCC_E : case SCS_E : case SEQ_E : case SNE_E : case INC_E : case DEC_E : case NOT_AB: case NOT_Z : case NOT_E : case SWP_AB: case SWP_Z : case SWP_E : case LLM_AB: case LLM_Z : case LLM_E : case LRM_AB: case LRM_Z : case LRM_E : case RLM_AB: case RLM_Z : case RLM_E : case RRM_AB: case RRM_Z : case RRM_E : case ARM_AB: case ARM_Z : case ARM_E : return 0; default : return 1; } } } else { switch (opcode) { case STA_AB: /* STA Absolute. */ case STA_Z: /* STA Zero Matrix. */ case STA_ZX: /* STA Zero Matrix, Indexed with X. */ case STA_ZY: /* STA Zero Matrix, Indexed with Y. */ case STA_IN: /* STA Indirect. */ case STA_IX: /* STA Indexed Indirect. */ case STA_IY: /* STA Indirect Indexed. */ case STY_AB: /* STY Absolute. */ case STY_Z: /* STY Zero Matrix. */ case STY_IN: /* STY Indirect. */ case STX_AB: /* STX Absolute. */ case STX_Z: /* STX Zero Matrix. */ case STX_IN: /* STX Indirect. */ case STB_AB: /* STB Absolute. */ case STB_Z: /* STB Zero Matrix. */ case STB_ZX: /* STB Zero Matrix, Indexed with X. */ case STB_ZY: /* STB Zero Matrix, Indexed with Y. */ case STB_IN: /* STB Indirect. */ case STB_IX: /* STB Indexed Indirect. */ case STB_IY: /* STB Indirect Indexed. */ case INC_AB: /* INC Absolute. */ case INC_Z: /* INC Zero Matrix. */ case DEC_AB: /* DEC Absolute. */ case DEC_Z: /* DEC Zero Matrix. */ return 0; /* Writing. */ default: return 1; /* Reading. */ } } } static /*inline*/ uint8_t isread(uint8_t opcode, uint8_t ext_prefix) { if ((ext_prefix & 0xD) == 0xD) { switch (ext_prefix >> 4) { case 0x0: switch (opcode) { case LEA_AB : case LEA_AX : case LEA_AY : case LEA_AI : case LEA_AIX: case LEA_AIY: case LEA_Z : case LEA_ZX : case LEA_ZY : case LEA_IN : case LEA_IX : case LEA_IY : case PEA_AB : case PEA_AX : case PEA_AY : case PEA_AI : case PEA_AIX: case PEA_AIY: case PEA_Z : case PEA_ZX : case PEA_ZY : case PEA_IN : case PEA_IX : case PEA_IY : case LDS_IMM: case LDS_AB : case LDS_Z : case LDS_E : case LNG_IMM: case LNG_E : case LPO_IMM: case LPO_E : case LCC_IMM: case LCC_E : case LCS_IMM: case LCS_E : case LEQ_IMM: case LEQ_E : case LNE_IMM: case LNE_E : case LDA_E : case LDB_E : case LDX_E : case LDY_E : case JMP_E : case JSR_E : return 0; default : return 1; } } } else { switch (opcode) { case LDA_IMM: /* LDA Immediate. */ case LDA_AB: /* LDA Absolute. */ case LDA_Z: /* LDA Zero Matrix. */ case LDA_ZX: /* LDA Zero Matrix, Indexed with X. */ case LDA_ZY: /* LDA Zero Matrix, Indexed with Y. */ case LDA_IN: /* LDA Indirect. */ case LDA_IX: /* LDA Indexed Indirect. */ case LDA_IY: /* LDA Indirect Indexed. */ case LDB_IMM: /* LDB Immediate. */ case LDB_AB: /* LDB Absolute. */ case LDB_Z: /* LDB Zero Matrix. */ case LDB_ZX: /* LDB Zero Matrix, Indexed with X. */ case LDB_ZY: /* LDB Zero Matrix, Indexed with Y. */ case LDB_IN: /* LDB Indirect. */ case LDB_IX: /* LDB Indexed Indirect. */ case LDB_IY: /* LDB Indirect Indexed. */ case LDY_IMM: /* LDY Immediate. */ case LDY_AB: /* LDY Absolute. */ case LDY_Z: /* LDY Zero Matrix. */ case LDY_IN: /* LDY Indirect. */ case LDX_IMM: /* LDX Immediate. */ case LDX_AB: /* LDX Absolute. */ case LDX_Z: /* LDX Zero Matrix. */ case LDX_IN: /* LDX Indirect. */ case JMP_AB: /* JMP Absolute. */ case JMP_Z: /* JMP Zero Matrix. */ case JMP_IN: /* JMP Indirect. */ case JSR_IN: /* JSR Indirect. */ case JSR_AB: /* Jump to SubRoutine. */ case JSR_Z: /* JSR Zero Matrix. */ return 0; default: return 1; } } } static int is_ind(uint8_t type) { switch (type) { case MEM_AIND : case MEM_IND : case MEM_ARIND: case MEM_ZRIND: case MEM_AINDR: case MEM_ZINDR: return 1; } return 0; } static void *memcopy(void *restrict dst, const void *restrict src, unsigned int n) { #ifdef copy64 uint64_t *d = dst; const uint64_t *s = src; unsigned int r = n % 8; n /= 8; #else uint8_t *d = dst; const uint8_t *s = src; #endif for (; n; *d++ = *s++, n--); #ifdef copy64 if (r) { uint64_t mask = (-(uint64_t)1 >> ((8 - r) * 8)); *d = (*d & ~mask) | (*s & mask); } #endif return dst; } static /*inline*/ uint64_t read_value(struct sux *cpu, uint64_t reg, uint64_t address, uint8_t size, uint8_t inc_clk, uint8_t check_io) { #if getclk cpu->clk += inc_clk; #endif size = (size > 7) ? 7 : size; uint64_t mask = (-(uint64_t)1 >> ((7 - size) * 8)); if (address < mem_size) { #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 #if 1 if (size < 7) { return (reg & ~mask) | (*(uint64_t *)(addr+address) & mask); } else { return *(uint64_t *)(addr+address); } #else return *(uint64_t *)memcopy(®, addr+address, size+1); #endif } else { return (size < 7) ? (reg & ~mask) | (mask) : mask; } } static /*inline*/ void write_value(struct sux *cpu, uint64_t value, uint64_t address, uint8_t size, uint8_t inc_clk, uint8_t check_io) { if (address < mem_size) { size = (size > 7) ? 7 : size; #if 1 if (size < 7) { uint64_t mask = (-(uint64_t)1 >> ((7 - size) * 8)); *(uint64_t *)(addr+address) = (*(uint64_t *)(addr+address) & ~mask) | (value & mask); } else { *(uint64_t *)(addr+address) = value; } #else memcopy(addr+address, &value, size+1); #endif #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->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, 0, cpu->pc, size, inc_clk, 0), size, inc_clk, prefix); } else { address = read_value(cpu, 0, cpu->pc, size, inc_clk, 0); } if (inc_pc) { cpu->pc += size+1; } return address; } static /*inline*/ uint64_t idx_addr(struct sux *cpu, uint8_t prefix, uint8_t inc_clk, uint8_t type, uint8_t inc_pc, uint64_t idx_reg) { #if getclk cpu->clk += inc_clk; #endif return read_addr(cpu, prefix, inc_clk, type, inc_pc) + idx_reg; } static /*inline*/ uint64_t ind_addr(struct sux *cpu, uint8_t prefix, uint8_t inc_clk, uint8_t type, uint8_t inc_pc) { return read_value(cpu, 0, read_addr(cpu, prefix, inc_clk, type, inc_pc), 7, inc_clk, 0); } static /*inline*/ uint64_t ind_idx_addr(struct sux *cpu, uint8_t prefix, uint8_t inc_clk, uint8_t type, uint8_t inc_pc, uint64_t idx_reg, uint8_t pre_idx) { #if getclk cpu->clk += inc_clk; #endif if (pre_idx) { return read_value(cpu, 0, read_addr(cpu, prefix, inc_clk, type, inc_pc)+idx_reg, 7, inc_clk, 0); } else { return ind_addr(cpu, prefix, inc_clk, type, inc_pc) + idx_reg; } } 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, 0, 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 ext_prefix, uint8_t inc_pc, uint8_t inc_clk, uint8_t thread) { uint64_t address = 0; uint8_t type; if ((ext_prefix & 0xF) == 0xD) { switch (ext_prefix >> 4) { case 0x0: type = ext_optype[opcode]; break; } } else { type = optype[opcode]; } switch (type) { case BREG: case IMPL: break; case EIND: address = cpu->e; 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 ((ext_prefix & 0xD) != 0xD) { if (inc_pc) { ++cpu->pc; } break; } /* Falls Through. */ default: if (inc_pc) { cpu->pc+=(1 << ((prefix >> 4) & 3)); } break; } break; case ZM : return read_addr(cpu, prefix, inc_clk, ZM, inc_pc); case ZMX : return idx_addr(cpu, prefix, inc_clk, ZM, inc_pc, cpu->x); case ZMY : return idx_addr(cpu, prefix, inc_clk, ZM, inc_pc, cpu->y); case IND : return ind_addr(cpu, prefix, inc_clk, ZM, inc_pc); case INDX : return ind_idx_addr(cpu, prefix, inc_clk, ZM, inc_pc, cpu->x, 1); case INDY : return ind_idx_addr(cpu, prefix, inc_clk, ZM, inc_pc, cpu->y, 0); case ABS : return read_addr(cpu, prefix, inc_clk, ABS, inc_pc); case ABSX : return idx_addr(cpu, prefix, inc_clk, ABS, inc_pc, cpu->x); case ABSY : return idx_addr(cpu, prefix, inc_clk, ABS, inc_pc, cpu->y); case AIND : return ind_addr(cpu, prefix, inc_clk, ABS, inc_pc); case AINDX: return ind_idx_addr(cpu, prefix, inc_clk, ABS, inc_pc, cpu->x, 1); case AINDY: return ind_idx_addr(cpu, prefix, inc_clk, ABS, inc_pc, cpu->y, 0); case REL : return rel_addr(cpu, prefix, inc_clk, /**/ inc_pc); } return address; } static /*inline*/ uint64_t ortho_ind_addr(struct sux *cpu, uint8_t prefix, uint64_t address, uint8_t inc_clk) { return read_value(cpu, 0, address, 7, inc_clk, 0); } static /*inline*/ uint64_t ortho_ind_idx_addr(struct sux *cpu, uint8_t prefix, uint64_t address, uint8_t inc_clk, uint64_t idx_reg, uint8_t pre_idx) { if (pre_idx) { return read_value(cpu, 0, address+idx_reg, 7, inc_clk, 0); } else { return ortho_ind_addr(cpu, prefix, address, inc_clk) + idx_reg; } } static /*inline*/ uint64_t get_ortho_addr(struct sux *cpu, uint8_t opcode, uint8_t prefix, uint64_t address, operand *op, uint64_t *value, uint8_t *op_type, uint8_t *op_id, uint8_t inc_pc, uint8_t inc_clk, uint8_t thread) { uint64_t tmp_addr = address; int num_ops = 1 + !(is_1op(opcode) || is_1cc(opcode)); for (int i = 0; i < num_ops; i++) { union reg tmp; tmp.u64 = 0; op[i].type = op_type[i]; op[i].id = op_id[i]; op[i].value = 0; op[i].rind[0] = 0xFF; op[i].rind[1] = 0xFF; if (op[i].type) { int inst_size = 0; int addr_size = get_ortho_addrsize(prefix, op[i].id); int rs = (1 << (prefix >> 4)); int is_rind = (op[i].id != MEM_ABS && op[i].id != MEM_ZM && op[i].id != MEM_AIND && op[i].id != MEM_IND && op[i].id != MEM_IMM); if (is_rind) { inst_size = (op[i].id == MEM_SIB)+1; tmp.u64 = read_value(cpu, 0, tmp_addr, inst_size-1, 0, 0); tmp_addr += inst_size; op[i].rind[0] = (tmp.u8[inst_size-1] & 0x0F); op[i].rind[1] = (tmp.u8[inst_size-1] >> 4); if (op[i].rind[1] == op[i].rind[0]) { op[i].rind[1] = 0xFF; } op[i].scale = (inst_size == 2) ? tmp.u8[0] : 0; } if (addr_size != 0xFF) { inst_size = addr_size+1; op[i].value = read_value(cpu, 0, tmp_addr, inst_size-1, inc_clk, 0); value[i] = op[i].value; tmp_addr += inst_size; } if (rs && op[i].id == MEM_IMM) { value[i] = tmp_addr; tmp_addr += rs; } uint64_t tmp_val = 0; if (is_rind) { for (int j = 0; j < 2 && op[i].rind[j] != 0xFF; j++) { int is_index = ((!j && op[i].rind[1] == 0xFF) || j); uint64_t reg; switch (op[i].rind[j]) { case REG_A : reg = cpu->a; break; case REG_B : reg = cpu->b; break; case REG_X : reg = cpu->x; break; case REG_Y : reg = cpu->y; break; case REG_E : reg = cpu->e; break; case REG_C : reg = cpu->c; break; case REG_D : reg = cpu->d; break; case REG_S : reg = cpu->s; break; case REG_F : reg = cpu->f; break; case REG_SP : reg = cpu->sp; break; case REG_BP : reg = cpu->bp; break; case REG_R11: reg = cpu->r11; break; case REG_R12: reg = cpu->r12; break; case REG_R13: reg = cpu->r13; break; case REG_R14: reg = cpu->r14; break; case REG_R15: reg = cpu->r15; break; } reg *= (is_index && op[i].id == MEM_SIB) ? op[i].scale+1 : 1; tmp_val += reg; } if (addr_size != 0xFF) { switch (addr_size) { case 0: value[i] = (int8_t )value[i]; break; case 1: value[i] = (int16_t)value[i]; break; case 2: case 3: value[i] = (int32_t)value[i]; break; case 4: case 5: case 6: case 7: value[i] = (int64_t)value[i]; break; } } value[i] += (!is_ind(op[i].id)) ? tmp_val : 0; #if getclk cpu->clk += inc_clk; #endif } if (is_ind(op[i].id)) { uint8_t pre_idx = 0; uint8_t type = op[i].id; switch (type) { case MEM_AIND : case MEM_IND : value[i] = ortho_ind_addr(cpu, prefix, value[i], inc_clk); break; case MEM_ARIND: case MEM_ZRIND: pre_idx = 1; /* Falls through. */ case MEM_AINDR: case MEM_ZINDR: value[i] = ortho_ind_idx_addr(cpu, prefix, value[i], inc_clk, tmp_val, pre_idx); break; } } } } address = (inc_pc) ? tmp_addr : address; return address; } static /*inline*/ uint64_t adc(struct sux *cpu, uint64_t reg, uint64_t value, uint8_t carry, uint8_t size, uint8_t thread) { size = (size > 8) ? 8 : size; uint8_t msb = size*8; uint64_t sum = reg+value+carry; setflag(sum == 0, Z); setflag(sum >> (msb-1), N); setflag(((reg^value) >> (msb-1)) && ((reg^sum) >> (msb-1)), V); setflag((sum < value), C); return sum; } static /*inline*/ uint64_t transfer(struct sux *cpu, uint64_t src, uint64_t value, uint8_t thread) { setflag(src == 0, Z); setflag(src >> 63, N); return src; } static /*inline*/ void push(struct sux *cpu, uint64_t value, uint8_t size, uint8_t thread) { write_value(cpu, value, 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 value = read_value(cpu, 0, cpu->sp+1, size, 1, 0); cpu->sp += size+1; return value; } static /*inline*/ uint64_t and(struct sux *cpu, uint64_t reg, uint64_t value, uint8_t size, uint8_t thread) { size = (size > 8) ? 8 : size; uint8_t msb = size*8; reg &= value; setflag(reg == 0, Z); setflag(reg >> (msb-1), N); return reg; } static /*inline*/ uint64_t or(struct sux *cpu, uint64_t reg, uint64_t value, uint8_t size, uint8_t thread) { size = (size > 8) ? 8 : size; uint8_t msb = size*8; reg |= value; setflag(reg == 0, Z); setflag(reg >> (msb-1), N); return reg; } static /*inline*/ uint64_t xor(struct sux *cpu, uint64_t reg, uint64_t value, uint8_t size, uint8_t thread) { size = (size > 8) ? 8 : size; uint8_t msb = size*8; reg ^= value; setflag(reg == 0, Z); setflag(reg >> (msb-1), N); return reg; } static /*inline*/ uint64_t lsl(struct sux *cpu, uint64_t reg, uint64_t value, uint8_t size, uint8_t thread) { size = (size > 8) ? 8 : size; uint8_t msb = size*8; uint64_t sum = (value < msb) ? reg << value : 0; setflag(sum == 0, Z); setflag(sum >> (msb-1), N); setflag(reg >> (msb-value), C); return sum; } static /*inline*/ uint64_t lsr(struct sux *cpu, uint64_t reg, uint64_t value, uint8_t size, uint8_t thread) { size = (size > 8) ? 8 : size; uint8_t msb = size*8; uint64_t sum = (value < msb) ? reg >> value : 0; setflag(sum == 0, Z); setflag(sum >> (msb-1), N); setflag(reg & 1, C); return sum; } static /*inline*/ uint64_t asr(struct sux *cpu, uint64_t reg, uint64_t value, uint8_t size, uint8_t thread) { size = (size > 8) ? 8 : size; uint8_t msb = size*8; uint8_t sign = reg >> (msb-1); uint64_t sum = (value < msb) ? (reg >> value) | ((uint64_t)sign << (msb-1)) : 0; setflag(sum == 0, Z); setflag(sum >> (msb-1), N); setflag(reg & 1, C); return sum; } static /*inline*/ uint64_t rol(struct sux *cpu, uint64_t reg, uint64_t value, uint8_t size, uint8_t thread) { size = (size > 8) ? 8 : size; uint8_t msb = size*8; uint64_t sum; uint64_t c = getflag(C); switch (value & 0x3F) { case 0 : return reg; case 1 : sum = (reg << 1) | (c & 1); break; default: sum = (reg << value) | (c << (value-1)) | (reg >> ((msb+1)-value)); break; } setflag(sum == 0, Z); setflag(sum >> (msb-1), N); setflag((reg >> (msb-value)) & 1, C); return sum; } static /*inline*/ uint64_t ror(struct sux *cpu, uint64_t reg, uint64_t value, uint8_t size, uint8_t thread) { size = (size > 8) ? 8 : size; uint8_t msb = size*8; uint64_t sum; uint64_t c = getflag(C); switch (value & 0x3F) { case 0 : return reg; case 1 : sum = (reg >> 1) | (c << (msb-1)); break; default: sum = (reg >> value) | (c << (msb-value)) | (reg << ((msb+1)-value)); break; } setflag(sum == 0, Z); setflag(sum >> (msb-1), N); setflag((reg >> (value-1)) & 1, C); return sum; } static /*inline*/ uint64_t mul(struct sux *cpu, uint64_t reg, uint64_t value, uint8_t size, uint8_t thread) { size = (size > 8) ? 8 : size; uint8_t msb = size*8; uint64_t sum = reg*value; setflag(sum == 0, Z); setflag(sum >> (msb-1), N); setflag(!((reg^value) >> (msb-1)) && ((reg^sum) >> (msb-1)), V); return sum; } static /*inline*/ uint64_t divd(struct sux *cpu, uint64_t reg, uint64_t value, uint64_t *rem, uint8_t size, uint8_t thread) { size = (size > 8) ? 8 : size; uint8_t msb = size*8; uint64_t sum = reg/value; *rem = reg % value; setflag(sum == 0, Z); setflag(sum >> (msb-1), N); return sum; } 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) { reg += (inc) ? 1 : -1; setflag(reg == 0, Z); setflag(reg >> 63, N); return reg; } static /*inline*/ uint64_t lbcnt(struct sux *cpu, uint64_t value, uint8_t bit, uint8_t size, uint8_t thread) { size = (size > 8) ? 8 : size; uint8_t msb = size*8; if ((!bit && !value) || (bit && value == -1)) { return msb; } uint64_t j = 0; for (int i = msb-1; ((value >> i) & 1) == bit; i--, j++); setflag(j == 0, Z); return j; } static /*inline*/ void bit_test(struct sux *cpu, uint64_t reg, uint64_t value, uint8_t thread) { setflag((value >> 7) & 1, N); setflag((value >> 6) & 1, V); setflag((value & reg) == 0, Z); } static /*inline*/ uint64_t swap(struct sux *cpu, uint64_t reg, uint8_t size, uint8_t thread) { size = (size > 7) ? 7 : size; uint8_t half = ((size-1)*8) >> 1; uint64_t mask = (-(uint64_t)1 >> ((7 - size) * 8)); uint64_t lo_mask = mask >> half; uint64_t hi_mask = (mask << half) & mask; return (((reg >> half) & lo_mask) | ((reg << half) & hi_mask)); } static /*inline*/ uint64_t popcnt(struct sux *cpu, uint64_t value, uint8_t thread) { uint64_t count = 0; for (; value; count++, value &= value - 1); return count; } /* 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; uint64_t value; value = read_value(cpu, 0, address, size, 1, 0); value += (inc) ? 1 : -1; 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 == 0, Z); setflag(value >> sign, N); write_value(cpu, value, address, size, 1, 1); } static /*inline*/ void bitshft_mem(struct sux *cpu, uint8_t shft_type, uint64_t shft_cnt, uint64_t address, uint8_t prefix, uint8_t thread) { uint8_t size = (1 << ((prefix >> 4) & 3))-1; uint64_t value = read_value(cpu, 0, address, size, 1, 0); switch (shft_type) { case 0: value = lsl(cpu, value, shft_cnt, size+1, thread); break; case 1: value = lsr(cpu, value, shft_cnt, size+1, thread); break; case 2: value = rol(cpu, value, shft_cnt, size+1, thread); break; case 3: value = ror(cpu, value, shft_cnt, size+1, thread); break; case 4: value = asr(cpu, value, shft_cnt, size+1, thread); break; } write_value(cpu, value, address, size, 1, 1); } static /*inline*/ void not_mem(struct sux *cpu, uint64_t address, uint8_t prefix, uint8_t thread) { uint8_t size = (1 << ((prefix >> 4) & 3))-1; write_value(cpu, ~read_value(cpu, 0, address, size, 1, 0), address, size, 1, 1); } static /*inline*/ void lbcnt_mem(struct sux *cpu, uint64_t address, uint8_t bit, uint8_t size, uint8_t thread) { uint64_t value = read_value(cpu, 0, address, size, 1, 0); write_value(cpu, lbcnt(cpu, value, bit, size, thread), address, size, 1, 1); } static /*inline*/ void swap_mem(struct sux *cpu, uint64_t address, uint8_t size, uint8_t thread) { uint64_t value = read_value(cpu, 0, address, size, 1, 0); write_value(cpu, swap(cpu, value, size, thread), address, size, 1, 1); } static /*inline*/ uint64_t mem_move(struct sux *cpu, uint64_t n, uint64_t dst, uint64_t src, uint8_t rep, uint8_t size, uint8_t thread) { if (!rep) { uint64_t value = read_value(cpu, 0, src, size, 1, 1); write_value(cpu, value, dst, size, 1, 1); return n-(size+1); } else { if (src < mem_size && dst < mem_size) { memcopy(addr+dst, addr+src, n*(size+1)); } return 0; } } static /*inline*/ uint64_t load(struct sux *cpu, uint64_t reg, uint64_t address, uint8_t size, uint8_t thread) { uint64_t value = read_value(cpu, reg, address, size, 1, 1); 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; write_value(cpu, reg, address, size, 1, 1); } static /*inline*/ uint64_t mov(struct sux *cpu, uint64_t src, uint64_t size, uint8_t thread) { size = (size > 7) ? 7 : size; uint8_t msb = (size+1)*8; uint64_t dst = 0; uint64_t mask = (-(uint64_t)1 >> ((7 - size) * 8)); if (size < 7) { dst = (dst & ~mask) | (src & mask); } else { dst = src; } setflag(dst == 0, Z); setflag(dst >> (msb-1), N); return dst; } static /*inline*/ uint64_t cmov(struct sux *cpu, uint64_t src, uint64_t size, uint64_t dst, int flag, int *allow_io, uint8_t thread) { *allow_io = flag; return (flag) ? mov(cpu, src, size, thread) : dst; } static /*inline*/ uint64_t set(struct sux *cpu, uint8_t flag, uint8_t thread) { setflag(flag == 0, Z); return (flag != 0); } static /*inline*/ uint64_t inc_dec(struct sux *cpu, uint64_t value, uint8_t size, uint8_t inc, uint8_t thread) { size = (size > 8) ? 8 : size; uint8_t msb = size*8; value += (inc) ? 1 : -1; setflag(value == 0, Z); setflag(value >> (msb-1), N); return value; } static /*inline*/ uint64_t imul(struct sux *cpu, uint64_t dst, uint64_t value, uint8_t size, uint8_t thread) { size = (size > 8) ? 8 : size; uint8_t msb = size*8; int64_t sum = dst*value; setflag(sum == 0, Z); setflag(sum >> (msb-1), N); setflag(!((dst^value) >> (msb-1)) && ((dst^sum) >> (msb-1)), V); return sum; } static /*inline*/ uint64_t idiv(struct sux *cpu, uint64_t dst, uint64_t value, uint64_t *rem, uint8_t size, uint8_t thread) { size = (size > 8) ? 8 : size; uint8_t msb = size*8; int64_t sum = dst/value; *rem = dst % value; setflag(sum == 0, Z); setflag(sum >> (msb-1), N); return sum; } static /*inline*/ uint64_t neg(struct sux *cpu, uint64_t value, uint8_t size, uint8_t thread) { size = (size > 8) ? 8 : size; uint8_t msb = size*8; value = -value; setflag(value == 0, Z); setflag(value >> (msb-1), N); return value; } static /*inline*/ void exec_ortho_inst(struct sux *cpu, uint8_t opcode, uint8_t prefix, uint8_t size, uint8_t *op_type, uint8_t *op_id, uint8_t thread) { uint64_t dst = 0; uint64_t src = 0; uint64_t rem = 0; uint64_t address[2] = {0, 0}; int isdiv = 0; int allow_io[2] = {1, 1}; int is_lea = ((opcode & ~0x18) == LEA_RR); int is_write = 1; operand op[2]; cpu->pc = get_ortho_addr(cpu, opcode, prefix, cpu->pc, op, address, op_type, op_id, 1, 1, thread); for (int i = 0; i < 2; i++) { if (op[i].type) { if (is_lea) { switch (op[i].id) { case MEM_RIND: case MEM_ABS : case MEM_ZM : case MEM_ABSR: case MEM_ZMR : case MEM_SIB : case MEM_IMM : allow_io[i] = 0; break; } } else { allow_io[i] = (op[i].id != MEM_IMM); } } } if (op[1].type) { src = read_value(cpu, 0, address[1], size, 1, allow_io[1]); } else { switch (op[1].id) { case REG_A : src = cpu->a; break; case REG_B : src = cpu->b; break; case REG_X : src = cpu->x; break; case REG_Y : src = cpu->y; break; case REG_E : src = cpu->e; break; case REG_C : src = cpu->c; break; case REG_D : src = cpu->d; break; case REG_S : src = cpu->s; break; case REG_F : src = cpu->f; break; case REG_SP : src = cpu->sp; break; case REG_BP : src = cpu->bp; break; case REG_R11: src = cpu->r11; break; case REG_R12: src = cpu->r12; break; case REG_R13: src = cpu->r13; break; case REG_R14: src = cpu->r14; break; case REG_R15: src = cpu->r15; break; } } if (op[0].type) { if (op[0].id != MEM_IMM) { dst = read_value(cpu, 0, address[0], size, 1, allow_io[0]); } } else { switch (op[0].id) { case REG_A : dst = cpu->a; break; case REG_B : dst = cpu->b; break; case REG_X : dst = cpu->x; break; case REG_Y : dst = cpu->y; break; case REG_E : dst = cpu->e; break; case REG_C : dst = cpu->c; break; case REG_D : dst = cpu->d; break; case REG_S : dst = cpu->s; break; case REG_F : dst = cpu->f; break; case REG_SP : dst = cpu->sp; break; case REG_BP : dst = cpu->bp; break; case REG_R11: dst = cpu->r11; break; case REG_R12: dst = cpu->r12; break; case REG_R13: dst = cpu->r13; break; case REG_R14: dst = cpu->r14; break; case REG_R15: dst = cpu->r15; break; } } switch (opcode) { case ORTHO_2OP(MNG): dst = cmov(cpu, src, (op[0].type) ? size : 7, dst, getflag(N), &allow_io[0], thread); break; case ORTHO_2OP(MPO): dst = cmov(cpu, src, (op[0].type) ? size : 7, dst, !getflag(N), &allow_io[0], thread); break; case ORTHO_2OP(MCS): dst = cmov(cpu, src, (op[0].type) ? size : 7, dst, getflag(C), &allow_io[0], thread); break; case ORTHO_2OP(MCC): dst = cmov(cpu, src, (op[0].type) ? size : 7, dst, !getflag(C), &allow_io[0], thread); break; case ORTHO_2OP(MEQ): dst = cmov(cpu, src, (op[0].type) ? size : 7, dst, getflag(Z), &allow_io[0], thread); break; case ORTHO_2OP(MNE): dst = cmov(cpu, src, (op[0].type) ? size : 7, dst, !getflag(Z), &allow_io[0], thread); break; case ORTHO_2OP(MVS): dst = cmov(cpu, src, (op[0].type) ? size : 7, dst, getflag(V), &allow_io[0], thread); break; case ORTHO_2OP(MVC): dst = cmov(cpu, src, (op[0].type) ? size : 7, dst, !getflag(V), &allow_io[0], thread); break; case ORTHO_2OP(MOV): dst = mov(cpu, src, (op[0].type) ? size : 7, thread); break; case ORTHO_2OP(ADC): dst = adc(cpu, dst, src, getflag(C), (op[0].type) ? size+1 : 8, thread); break; case ORTHO_2OP(SBC): dst = adc(cpu, dst, ~src, getflag(C), (op[0].type) ? size+1 : 8, thread); break; case ORTHO_2OP(ADD): dst = adc(cpu, dst, src, 0, (op[0].type) ? size+1 : 8, thread); break; case ORTHO_2OP(SUB): dst = adc(cpu, dst, ~src, 1, (op[0].type) ? size+1 : 8, thread); break; case ORTHO_2OP(AND): dst = and(cpu, dst, src, (op[0].type) ? size+1 : 8, thread); break; case ORTHO_2OP(OR ): dst = or(cpu, dst, src, (op[0].type) ? size+1 : 8, thread); break; case ORTHO_2OP(XOR): dst = xor(cpu, dst, src, (op[0].type) ? size+1 : 8, thread); break; case ORTHO_2OP(LSL): dst = lsl(cpu, dst, src, (op[0].type) ? size+1 : 8, thread); break; case ORTHO_2OP(LSR): dst = lsr(cpu, dst, src, (op[0].type) ? size+1 : 8, thread); break; case ORTHO_2OP(ROL): dst = rol(cpu, dst, src, (op[0].type) ? size+1 : 8, thread); break; case ORTHO_2OP(ROR): dst = ror(cpu, dst, src, (op[0].type) ? size+1 : 8, thread); break; case ORTHO_2OP(ASR): dst = asr(cpu, dst, src, (op[0].type) ? size+1 : 8, thread); break; case ORTHO_2OP(MUL): dst = mul(cpu, dst, src, (op[0].type) ? size+1 : 8, thread); break; case ORTHO_2OP(DIV): dst = divd(cpu, dst, src, &rem, (op[0].type) ? size+1 : 8, thread); isdiv = 1; break; case ORTHO_2OP(CMP): adc(cpu, dst, ~src, 1, (op[0].type) ? size+1 : 8, thread); is_write = 0; break; case ORTHO_2OP(PCN): dst = popcnt(cpu, src, thread); break; case ORTHO_2OP(IML): dst = imul(cpu, dst, src, (op[0].type) ? size+1 : 8, thread); break; case ORTHO_2OP(IDV): dst = idiv(cpu, dst, src, &rem, (op[0].type) ? size+1 : 8, thread); isdiv = 1; break; case ORTHO_2OP(LEA): do { uint64_t tmp_addr; uint64_t mask; if (op[1].type) { uint8_t addr_size = get_ortho_addrsize(prefix, op[1].id); size = (!size) ? 7 : size; tmp_addr = address[1]; } else { tmp_addr = src; } mask = (-(uint64_t)1 >> ((7 - size) * 8)); dst = (tmp_addr & mask); } while (0); break; case ORTHO_1OP(PEA): do { uint64_t tmp_addr = (op[0].type) ? address[0] : dst; push(cpu, tmp_addr, 7, thread); is_write = 0; } while (0); break; case ORTHO_1OP(JSR): push(cpu, cpu->pc, (size) ? size : 7, thread); /* Falls Through. */ case ORTHO_1OP(JMP): cpu->pc = (op[0].type) ? address[0] : dst; break; case ORTHO_1OP(INC): dst = inc_dec(cpu, dst, (op[0].type) ? size+1 : 8, 1, thread); break; case ORTHO_1OP(DEC): dst = inc_dec(cpu, dst, (op[0].type) ? size+1 : 8, 0, thread); break; case ORTHO_1OP(PSH): push(cpu, dst, size, thread); is_write = 0; break; case ORTHO_1OP(PUL): dst = pull(cpu, size, thread); break; case ORTHO_1OP(NOT): dst = ~dst; break; case ORTHO_1OP(CLZ): dst = lbcnt(cpu, src, 0, size, thread); break; case ORTHO_1OP(CLO): dst = lbcnt(cpu, src, 1, size, thread); break; case ORTHO_1OP(SWP): dst = swap(cpu, dst, size, thread); break; case ORTHO_1OP(NEG): dst = neg(cpu, dst, size, thread); break; case ORTHO_1CC(SET, NG): dst = set(cpu, getflag(N), thread); break; case ORTHO_1CC(SET, PO): dst = set(cpu, !getflag(N), thread); break; case ORTHO_1CC(SET, CS): dst = set(cpu, getflag(C), thread); break; case ORTHO_1CC(SET, CC): dst = set(cpu, !getflag(C), thread); break; case ORTHO_1CC(SET, EQ): dst = set(cpu, getflag(Z), thread); break; case ORTHO_1CC(SET, NE): dst = set(cpu, !getflag(Z), thread); break; case ORTHO_1CC(SET, VS): dst = set(cpu, getflag(V), thread); break; case ORTHO_1CC(SET, VC): dst = set(cpu, !getflag(V), thread); break; } if (is_write) { if (op[0].type) { if (op[0].id != MEM_IMM) { write_value(cpu, dst, address[0], size, 1, allow_io[0]); } } else { switch (op[0].id) { case REG_A : cpu->a = dst; break; case REG_B : cpu->b = dst; break; case REG_X : cpu->x = dst; break; case REG_Y : cpu->y = dst; break; case REG_E : cpu->e = dst; break; case REG_C : cpu->c = dst; break; case REG_D : cpu->d = dst; break; case REG_S : cpu->s = dst; break; case REG_F : cpu->f = dst; break; case REG_SP : cpu->sp = dst; break; case REG_BP : cpu->bp = dst; break; case REG_R11: cpu->r11 = dst; break; case REG_R12: cpu->r12 = dst; break; case REG_R13: cpu->r13 = dst; break; case REG_R14: cpu->r14 = dst; break; case REG_R15: cpu->r15 = dst; break; } } } if (isdiv) { if (op[1].type) { if (op[1].id != MEM_IMM) { write_value(cpu, src, address[1], size, 1, 1); } } else { switch (op[1].id) { case REG_A : cpu->a = rem; break; case REG_B : cpu->b = rem; break; case REG_X : cpu->x = rem; break; case REG_Y : cpu->y = rem; break; case REG_E : cpu->e = rem; break; case REG_C : cpu->c = rem; break; case REG_D : cpu->d = rem; break; case REG_S : cpu->s = rem; break; case REG_F : cpu->f = rem; break; case REG_SP : cpu->sp = rem; break; case REG_BP : cpu->bp = rem; break; case REG_R11: cpu->r11 = rem; break; case REG_R12: cpu->r12 = rem; break; case REG_R13: cpu->r13 = rem; break; case REG_R14: cpu->r14 = rem; break; case REG_R15: cpu->r15 = rem; break; } } } } static /*inline*/ void exec_ext_inst(struct sux *cpu, uint8_t opcode, uint8_t prefix, uint64_t value, uint64_t address, uint8_t size, uint8_t thread) { uint8_t addr_size = get_addrsize(prefix, ext_optype[opcode]); uint8_t tmp = 0; switch (opcode) { case LEA_AB : /* LEA Absolute. */ case LEA_AX : /* LEA Absolute, Indexed with X. */ case LEA_AY : /* LEA Absolute, Indexed with Y. */ case LEA_AI : /* LEA Absolute Indirect. */ case LEA_AIX: /* LEA Absolute Indexed Idirect. */ case LEA_AIY: /* LEA Absolute Indirect Indexed. */ case LEA_Z : /* LEA Zero Matrix. */ case LEA_ZX : /* LEA Zero Matrix, Indexed with X. */ case LEA_ZY : /* LEA Zero Matrix, Indexed with Y. */ case LEA_IN : /* LEA Indirect. */ case LEA_IX : /* LEA Indexed Idirect. */ case LEA_IY : /* LEA Indirect Indexed. */ do { size = (!size) ? addr_size : size; uint64_t mask = (-(uint64_t)1 >> ((7 - size) * 8)); cpu->e = (address & mask); //cpu->e = load(cpu, address, 0, size, thread); } while (0); break; case PEA_AB : /* PEA Absolute. */ case PEA_AX : /* PEA Absolute, Indexed with X. */ case PEA_AY : /* PEA Absolute, Indexed with Y. */ case PEA_AI : /* PEA Absolute Indirect. */ case PEA_AIX: /* PEA Absolute Indexed Idirect. */ case PEA_AIY: /* PEA Absolute Indirect Indexed. */ case PEA_Z : /* PEA Zero Matrix. */ case PEA_ZX : /* PEA Zero Matrix, Indexed with X. */ case PEA_ZY : /* PEA Zero Matrix, Indexed with Y. */ case PEA_IN : /* PEA Indirect. */ case PEA_IX : /* PEA Indexed Idirect. */ case PEA_IY : /* PEA Indirect Indexed. */ push(cpu, address, 7, thread); break; case ADD_IMM: /* ADD Immediate. */ case ADD_AB : /* ADD Absolute. */ case ADD_Z : /* ADD Zero Matrix. */ case ADD_E : /* ADD E Indirect. */ cpu->a = adc(cpu, cpu->a, value, 0, 8, thread); break; case SUB_IMM: /* SUB Immediate. */ case SUB_AB : /* SUB Absolute. */ case SUB_Z : /* SUB Zero Matrix. */ case SUB_E : /* SUB E Indirect. */ cpu->a = adc(cpu, cpu->a, ~value, 1, 8, thread); break; case ADE_IMM: /* ADE Immediate. */ case ADE_AB : /* ADE Absolute. */ case ADE_Z : /* ADE Zero Matrix. */ cpu->e = adc(cpu, cpu->e, value, 0, 8, thread); break; case SBE_IMM: /* SBE Immediate. */ case SBE_AB : /* SBE Absolute. */ case SBE_Z : /* SBE Zero Matrix. */ cpu->e = adc(cpu, cpu->e, ~value, 1, 8, thread); break; case ADS_IMM: /* ADS Immediate. */ case ADS_AB : /* ADS Absolute. */ case ADS_Z : /* ADS Zero Matrix. */ case ADS_E : /* ADS E Indirect. */ cpu->sp = adc(cpu, cpu->sp, value, 0, 8, thread); break; case SBS_IMM: /* SBS Immediate. */ case SBS_AB : /* SBS Absolute. */ case SBS_Z : /* SBS Zero Matrix. */ case SBS_E : /* SBS E Indirect. */ cpu->sp = adc(cpu, cpu->sp, ~value, 1, 8, thread); break; case NOT_A : /* NOT Accumulator. */ cpu->a = ~cpu->a; break; case NOT_AB: /* NOT Absolute. */ case NOT_Z : /* NOT Zero Matrix. */ case NOT_E : /* NOT E Indirect. */ not_mem(cpu, address, prefix, thread); break; case LLM_AB: /* LLM Absolute. */ case LLM_Z : /* LLM Zero Matrix. */ case LLM_E : /* LLM E Indirect. */ case LRM_AB: /* LRM Absolute. */ case LRM_Z : /* LRM Zero Matrix. */ case LRM_E : /* LRM E Indirect. */ case RLM_AB: /* RLM Absolute. */ case RLM_Z : /* RLM Zero Matrix. */ case RLM_E : /* RLM E Indirect. */ case RRM_AB: /* RRM Absolute. */ case RRM_Z : /* RRM Zero Matrix. */ case RRM_E : /* RRM E Indirect. */ case ARM_AB: /* ARM Absolute. */ case ARM_Z : /* ARM Zero Matrix. */ case ARM_E : /* ARM E Indirect. */ switch (opcode) { case LLM_AB: case LLM_Z : case LLM_E : tmp = 0; break; case LRM_AB: case LRM_Z : case LRM_E : tmp = 1; break; case RLM_AB: case RLM_Z : case RLM_E : tmp = 2; break; case RRM_AB: case RRM_Z : case RRM_E : tmp = 3; break; case ARM_AB: case ARM_Z : case ARM_E : tmp = 4; break; } bitshft_mem(cpu, tmp, cpu->b, address, prefix, thread); break; case PHE_IMP: push(cpu, cpu->e, size, thread); break; /* PusH E register. */ case PLE_IMP: cpu->e = pull(cpu, size, thread); break; /* PuLl E register. */ case CPE_IMM: /* CPE Immediate. */ case CPE_AB : /* CPE Absolute. */ case CPE_Z : /* CPE Zero Matrix. */ adc(cpu, cpu->e, ~value, 1, 8, thread); break; case ICE_AB : /* ICE Absolute. */ case ICE_Z : /* ICE Zero Matrix. */ case ICE_E : /* ICE E Indirect. */ break; case LDS_IMM: /* LDS Immediate. */ case LDS_AB : /* LDS Absolute. */ case LDS_Z : /* LDS Zero Matrix. */ case LDS_E : /* LDS E Indirect. */ cpu->sp = load(cpu, cpu->sp, address, size, thread); break; case DEE_IMP: cpu->e = idr(cpu, cpu->e, 0, thread); break; /* DEcrement E register. */ case INE_IMP: cpu->e = idr(cpu, cpu->e, 1, thread); break; /* INcrement E register. */ case DES_IMP: cpu->sp = idr(cpu, cpu->sp, 0, thread); break; /* DEcrement Stack pointer. */ case INS_IMP: cpu->sp = idr(cpu, cpu->sp, 1, thread); break; /* INcrement Stack pointer. */ case STS_AB: /* STS Absolute. */ case STS_Z : /* STS Zero Matrix. */ case STS_E : /* STS E Indirect. */ store(cpu, address, cpu->sp, prefix, thread); break; case STE_AB: /* STE Absolute. */ case STE_Z : /* STE Zero Matrix. */ store(cpu, address, cpu->sp, prefix, thread); break; case STZ_AB: /* STZ Absolute. */ case STZ_Z : /* STZ Zero Matrix. */ case STZ_E : /* STZ E Indirect. */ store(cpu, address, 0, prefix, thread); break; case SCO_IMM: /* SCO Immediate. */ case SCO_AB : /* SCO Absolute. */ case SCO_Z : /* SCO Zero Matrix. */ case SCO_E : /* SCO E Indirect. */ break; case ECO_IMM: /* ECO Immediate. */ case ECO_AB : /* ECO Absolute. */ case ECO_Z : /* ECO Zero Matrix. */ case ECO_E : /* ECO E Indirect. */ break; case CLZ_AB: /* CLZ Absolute. */ case CLZ_Z : /* CLZ Zero Matrix. */ case CLZ_E : /* CLZ E Indirect. */ cpu->a = lbcnt(cpu, value, 0, size, thread); break; case CLO_AB: /* CLO Absolute. */ case CLO_Z : /* CLO Zero Matrix. */ case CLO_E : /* CLO E Indirect. */ cpu->a = lbcnt(cpu, value, 1, size, thread); break; case BIT_AB: /* BIT Absolute. */ case BIT_Z : /* BIT Zero Matrix. */ case BIT_E : /* BIT E Indirect. */ bit_test(cpu, cpu->a, value, thread); break; case MMV_IMP: /* Memory MoVe. */ cpu->b = mem_move(cpu, cpu->b, cpu->x, cpu->y, 1, size, thread); break; case SWP_A : /* SWaP lower half, with upper half. */ cpu->a = swap(cpu, cpu->a, size, thread); break; case SWP_AB: /* SWP Absolute. */ case SWP_Z : /* SWP Zero Matrix. */ case SWP_E : /* SWP E Indirect. */ swap_mem(cpu, address, size, thread); break; case PCN_AB: /* PCN Absolute. */ case PCN_Z : /* PCN Zero Matrix. */ case PCN_E : /* PCN E Indirect. */ cpu->a = popcnt(cpu, value, thread); break; case REP_REL: /* REP Relative. */ if (cpu->b != 0) { cpu->b--; cpu->pc = address; } break; case REQ_REL: /* REQ Relative. */ if (cpu->b != 0 && getflag(Z)) { cpu->b--; cpu->pc = address; } break; case RNE_REL: /* RNE Relative. */ if (cpu->b != 0 && !getflag(Z)) { cpu->b--; cpu->pc = address; } break; case LNG_IMM: /* LNG Immediate. */ case LNG_E : /* LNG E Indirect. */ if (getflag(N)) { cpu->a = load(cpu, cpu->a, address, size, thread); } break; case LPO_IMM: /* LPO Immediate. */ case LPO_E : /* LPO E Indirect. */ if (!getflag(N)) { cpu->a = load(cpu, cpu->a, address, size, thread); } break; case LCS_IMM: /* LCS Immediate. */ case LCS_E : /* LCS E Indirect. */ if (getflag(C)) { cpu->a = load(cpu, cpu->a, address, size, thread); } break; case LCC_IMM: /* LCC Immediate. */ case LCC_E : /* LCC E Indirect. */ if (!getflag(C)) { cpu->a = load(cpu, cpu->a, address, size, thread); } break; case LEQ_IMM: /* LEQ Immediate. */ case LEQ_E : /* LEQ E Indirect. */ if (getflag(Z)) { cpu->a = load(cpu, cpu->a, address, size, thread); } break; case LNE_IMM: /* LNE Immediate. */ case LNE_E : /* LNE E Indirect. */ if (!getflag(Z)) { cpu->a = load(cpu, cpu->a, address, size, thread); } break; case SNG_E : /* SNG E Indirect. */ if (getflag(N)) { store(cpu, address, cpu->a, prefix, thread); } break; case SPO_E : /* SPO E Indirect. */ if (!getflag(N)) { store(cpu, address, cpu->a, prefix, thread); } break; case SCS_E : /* SCS E Indirect. */ if (getflag(C)) { store(cpu, address, cpu->a, prefix, thread); } break; case SCC_E : /* SCC E Indirect. */ if (!getflag(C)) { store(cpu, address, cpu->a, prefix, thread); } break; case SEQ_E : /* SEQ E Indirect. */ if (getflag(Z)) { store(cpu, address, cpu->a, prefix, thread); } break; case SNE_E : /* SNE E Indirect. */ if (!getflag(Z)) { store(cpu, address, cpu->a, prefix, thread); } break; } } static /*inline*/ void exec_base_inst(struct sux *cpu, uint8_t opcode, uint8_t prefix, uint64_t value, uint64_t address, uint8_t size, uint8_t thread) { uint64_t *rem = 0; switch (opcode) { case CPS_IMP: /* Clear Processor Status. */ cpu->ps.u8[thread] = 0; break; case ADC_B: /* ADC B register. */ value = cpu->b; /* Falls Through. */ case ADC_IMM: /* ADC Immediate. */ case ADC_AB: /* ADC Absolute. */ case ADC_Z: /* ADC Zero Matrix. */ cpu->a = adc(cpu, cpu->a, value, getflag(C), 8, thread); break; case PHP_IMP: push(cpu, cpu->ps.u8[thread], 0, thread); break; /* PusH Processor status to stack. */ case PHA_IMP: push(cpu, cpu->a , size, thread); break; /* PusH Accumulator to stack. */ case PHB_IMP: push(cpu, cpu->b , size, thread); break; /* PusH B register to stack. */ case PHY_IMP: push(cpu, cpu->y , size, thread); break; /* PusH Y register to stack. */ case PHX_IMP: push(cpu, cpu->x , size, thread); break; /* PusH X register to stack. */ case TAY_IMP: cpu->y = transfer(cpu, cpu->a , value, thread); break; /* Transfer Accumulator to Y. */ case TAX_IMP: cpu->x = transfer(cpu, cpu->a , value, thread); break; /* Transfer Accumulator to Y. */ case TYX_IMP: cpu->x = transfer(cpu, cpu->y , value, thread); break; /* Transfer Y to X. */ case TYA_IMP: cpu->a = transfer(cpu, cpu->y , value, thread); break; /* Transfer Y to Accumulator. */ case TXA_IMP: cpu->a = transfer(cpu, cpu->x , value, thread); break; /* Transfer X to Accumulator. */ case TXY_IMP: cpu->y = transfer(cpu, cpu->x , value, thread); break; /* Transfer X to Y. */ case TAB_IMP: cpu->b = transfer(cpu, cpu->a , value, thread); break; /* Transfer Accumulator to B. */ case TSX_IMP: cpu->x = transfer(cpu, cpu->sp, value, thread); break; /* Transfer Stack pointer to X. */ case TBA_IMP: cpu->a = transfer(cpu, cpu->b , value, thread); break; /* Transfer B to Accumulator. */ case TXS_IMP: cpu->sp = transfer(cpu, cpu->x , value, thread); break; /* Transfer X to Stack pointer. */ case BRA_REL: /* BRA Relative. */ case JMP_AB: /* JMP Absolute. */ case JMP_Z: /* JMP Zero Matrix. */ case JMP_IN: /* JMP Indirect. */ cpu->pc = address; break; case SBC_B: /* SBC B register. */ value = cpu->b; /* Falls Through. */ case SBC_IMM: /* SBC Immediate. */ case SBC_AB: /* SBC Absolute. */ case SBC_Z: /* SBC Zero Matrix. */ cpu->a = adc(cpu, cpu->a, ~value, getflag(C), 8, thread); break; case PLP_IMP: cpu->ps.u8[thread] = pull(cpu, 0, thread); break; /* PuLl Processor status from stack. */ case PLA_IMP: cpu->a = pull(cpu, size, thread); break; /* PuLl Accumulator from stack. */ case PLB_IMP: cpu->b = pull(cpu, size, thread); break; /* PuLl B register from stack. */ case PLY_IMP: cpu->y = pull(cpu, size, thread); break; /* PuLl Y register from stack. */ case PLX_IMP: cpu->x = pull(cpu, size, thread); break; /* PuLl X register from stack. */ break; case AND_B: /* AND B register. */ value = cpu->b; /* Falls Through. */ case AND_IMM: /* AND Immediate. */ case AND_AB: /* AND Absolute. */ case AND_Z: /* AND Zero Matrix. */ cpu->a = and(cpu, cpu->a, value, 8, thread); break; case BPO_REL: /* BPO Relative. */ if (!getflag(N)) { cpu->pc = address; } break; case ORA_B: /* ORA B register. */ value = cpu->b; /* Falls Through. */ case ORA_IMM: /* ORA Immediate. */ case ORA_AB: /* ORA Absolute. */ case ORA_Z: /* ORA Zero Matrix. */ cpu->a = or(cpu, cpu->a, value, 8, thread); break; case SEI_IMP: /* SEt Interrupt. */ setflag(1, I); break; case BNG_REL: /* BNG Relative. */ if (getflag(N)) { cpu->pc = address; } break; case XOR_B: /* XOR B register. */ value = cpu->b; /* Falls Through. */ case XOR_IMM: /* XOR Immediate. */ case XOR_AB: /* XOR Absolute. */ case XOR_Z: /* XOR Zero Matrix. */ cpu->a = xor(cpu, cpu->a, value, 8, thread); break; case CLI_IMP: /* CLear Interrupt. */ setflag(0, I); break; case BCS_REL: /* BCS Relative. */ if (getflag(C)) { cpu->pc = address; } break; case LSL_B: /* LSL B register. */ value = cpu->b; /* Falls Through. */ case LSL_IMM: /* LSL Immediate. */ case LSL_AB: /* LSL Absolute. */ case LSL_Z: /* LSL Zero Matrix. */ cpu->a = lsl(cpu, cpu->a, value, 8, thread); break; case SEC_IMP: /* SEt Carry flag.*/ setflag(1, C); break; case STA_AB: /* STA Absolute. */ case STA_Z: /* STA Zero Matrix. */ case STA_ZX: /* STA Zero Matrix, Indexed with X. */ case STA_ZY: /* STA Zero Matrix, Indexed with Y. */ case STA_IN: /* STA Indirect. */ case STA_IX: /* STA Indexed Indirect. */ case STA_IY: /* STA Indirect Indexed. */ store(cpu, address, cpu->a, prefix, thread); break; case STY_AB: /* STY Absolute. */ case STY_Z: /* STY Zero Matrix. */ case STY_IN: /* STY Indirect. */ store(cpu, address, cpu->y, prefix, thread); break; case STX_AB: /* STX Absolute. */ case STX_Z: /* STX Zero Matrix. */ case STX_IN: /* STX Indirect. */ store(cpu, address, cpu->x, prefix, thread); break; case STB_AB: /* STB Absolute. */ case STB_Z: /* STB Zero Matrix. */ case STB_ZX: /* STB Zero Matrix, Indexed with X. */ case STB_ZY: /* STB Zero Matrix, Indexed with Y. */ case STB_IN: /* STB Indirect. */ case STB_IX: /* STB Indexed Indirect. */ case STB_IY: /* STB Indirect Indexed. */ store(cpu, address, cpu->b, prefix, thread); break; case BCC_REL: /* BCC Relative. */ if (!getflag(C)) { cpu->pc = address; } break; case LSR_B: /* LSR B register. */ value = cpu->b; /* Falls Through. */ case LSR_IMM: /* LSR Immediate. */ case LSR_AB: /* LSR Absolute. */ case LSR_Z: /* LSR Zero Matrix. */ cpu->a = lsr(cpu, cpu->a, value, 8, thread); break; case ASR_B: /* ASR B register. */ value = cpu->b; /* Falls Through. */ case ASR_IMM: /* ASR Immediate. */ case ASR_AB: /* ASR Absolute. */ case ASR_Z: /* ASR Zero Matrix. */ cpu->a = asr(cpu, cpu->a, value, 8, thread); break; case CLC_IMP: /* CLear Carry flag. */ setflag(0, C); break; case LDB_IMM: /* LDB Immediate. */ case LDB_AB: /* LDB Absolute. */ case LDB_Z: /* LDB Zero Matrix. */ case LDB_ZX: /* LDB Zero Matrix, Indexed with X. */ case LDB_ZY: /* LDB Zero Matrix, Indexed with Y. */ case LDB_IN: /* LDB Indirect. */ case LDB_IX: /* LDB Indexed Indirect. */ case LDB_IY: /* LDB Indirect Indexed. */ cpu->b = load(cpu, cpu->b, address, size, thread); break; case LDA_IMM: /* LDA Immediate. */ case LDA_AB: /* LDA Absolute. */ case LDA_Z: /* LDA Zero Matrix. */ case LDA_ZX: /* LDA Zero Matrix, Indexed with X. */ case LDA_ZY: /* LDA Zero Matrix, Indexed with Y. */ case LDA_IN: /* LDA Indirect. */ case LDA_IX: /* LDA Indexed Indirect. */ case LDA_IY: /* LDA Indirect Indexed. */ cpu->a = load(cpu, cpu->a, address, size, thread); break; case LDY_IMM: /* LDY Immediate. */ case LDY_AB: /* LDY Absolute. */ case LDY_Z: /* LDY Zero Matrix. */ case LDY_IN: /* LDY Indirect. */ cpu->y = load(cpu, cpu->y, address, size, thread); break; case LDX_IMM: /* LDX Immediate. */ case LDX_AB: /* LDX Absolute. */ case LDX_Z: /* LDX Zero Matrix. */ case LDX_IN: /* LDX Indirect. */ cpu->x = load(cpu, cpu->x, address, size, thread); break; case BEQ_REL: /* BEQ Relative. */ if (getflag(Z)) { cpu->pc = address; } break; case ROL_B: /* ROL B register. */ value = cpu->b; /* Falls Through. */ case ROL_IMM: /* ROL Immediate. */ case ROL_AB: /* ROL Absolute. */ case ROL_Z: /* ROL Zero Matrix. */ cpu->a = rol(cpu, cpu->a, value, 8, thread); break; case BNE_REL: /* BNE Relative. */ if (!getflag(Z)) { cpu->pc = address; } break; case ROR_B: /* ROR B register. */ value = cpu->b; /* Falls Through. */ case ROR_IMM: /* ROR Immediate. */ case ROR_AB: /* ROR Absolute. */ case ROR_Z: /* ROR Zero Matrix. */ cpu->a = ror(cpu, cpu->a, value, 8, thread); break; case BVS_REL: /* BVS Relative. */ if (getflag(V)) { cpu->pc = address; } break; case MUL_B: /* MUL B register. */ value = cpu->b; /* Falls Through. */ case MUL_IMM: /* MUL Immediate. */ case MUL_AB: /* MUL Absolute. */ case MUL_Z: /* MUL Zero Matrix. */ cpu->a = mul(cpu, cpu->a, value, 8, thread); break; case BVC_REL: /* BVC Relative. */ if (!getflag(V)) { cpu->pc = address; } break; case DIV_B: /* DIV B register. */ case DIV_IMM: /* DIV Immediate. */ case DIV_AB: /* DIV Absolute. */ case DIV_Z: /* DIV Zero Matrix. */ rem = (opcode != DIV_B) ? &cpu->b : &cpu->x; cpu->a = divd(cpu, cpu->a, value, rem, 8, thread); break; case CLV_IMP: /* CLear oVerflow flag. */ setflag(0, V); break; case CPB_IMM: /* CPB Immediate. */ case CPB_AB: /* CPB Absolute. */ case CPB_Z: /* CPB Zero Matrix. */ case CPB_IN: /* CPB Indirect. */ case CPB_IX: /* CPB Indexed Indirect. */ case CPB_IY: /* CPB Indirect Indexed. */ adc(cpu, cpu->b, ~value, 1, 8, thread); break; case CMP_B: /* CMP B register. */ value = cpu->b; /* Falls Through. */ case CMP_IMM: /* CMP Immediate. */ case CMP_AB: /* CMP Absolute. */ case CMP_Z: /* CMP Zero Matrix. */ case CMP_IN: /* CMP Indirect. */ case CMP_IX: /* CMP Indexed Indirect. */ case CMP_IY: /* CMP Indirect Indexed. */ adc(cpu, cpu->a, ~value, 1, 8, thread); break; case CPY_IMM: /* CPY Immediate. */ case CPY_AB: /* CPY Absolute. */ case CPY_Z: /* CPY Zero Matrix. */ adc(cpu, cpu->y, ~value, 1, 8, thread); break; case CPX_IMM: /* CPX Immediate. */ case CPX_AB: /* CPX Absolute. */ case CPX_Z: /* CPX Zero Matrix. */ adc(cpu, cpu->x, ~value, 1, 8, thread); break; case INC_IMP: cpu->a = idr(cpu, cpu->a, 1, thread); break; case INB_IMP: cpu->b = idr(cpu, cpu->b, 1, thread); break; case INY_IMP: cpu->y = idr(cpu, cpu->y, 1, thread); break; case INX_IMP: cpu->x = idr(cpu, cpu->x, 1, thread); break; case DEC_IMP: cpu->a = idr(cpu, cpu->a, 0, thread); break; case DEB_IMP: cpu->b = idr(cpu, cpu->b, 0, thread); break; case DEY_IMP: cpu->y = idr(cpu, cpu->y, 0, thread); break; case DEX_IMP: cpu->x = idr(cpu, cpu->x, 0, thread); break; case JSR_IN: /* JSR Indirect. */ case JSR_AB: /* Jump to SubRoutine. */ case JSR_Z: /* JSR Zero Matrix. */ push(cpu, cpu->pc, (size) ? size : 7, thread); cpu->pc = address; break; case INC_AB: /* INC Absolute. */ case INC_Z: /* INC Zero Matrix. */ idm(cpu, address, prefix, 1, thread); break; case NOP_IMP: /* No OPeration. */ break; case RTI_IMP: /* ReTurn from Interrupt routine. */ cpu->ps.u8[thread] = pull(cpu, 0, thread); size = 0; case RTS_IMP: /* ReTurn from Subroutine. */ cpu->pc = pull(cpu, (size) ? size : 7, thread); break; case DEC_AB: /* DEC Absolute. */ case DEC_Z: /* DEC Zero Matrix. */ idm(cpu, address, prefix, 0, thread); break; case BRK_IMP: /* BReaK. */ case WAI_IMP: /* WAit for Interrupt. */ if (opcode == WAI_IMP) { pthread_mutex_lock(&main_mutex); pthread_cond_signal(&main_cond); pthread_mutex_unlock(&main_mutex); pthread_mutex_lock(&mutex); pthread_cond_wait(&cond, &mutex); pthread_mutex_unlock(&mutex); } push(cpu, cpu->pc, 7, thread); push(cpu, cpu->ps.u8[thread], 0, thread); setflag(1, I); value = read_value(cpu, 0, (opcode == BRK) ? 0xFFE0 : 0xFFA0, 7, 1, 0); if (opcode == WAI_IMP) { kbd_rdy &= (uint8_t)~(1 << thread); } cpu->pc = value; default: break; } } #undef ORTHO_1CC #undef ORTHO_1OP #undef ORTHO_2OP