#ifndef SUX_H
#define SUX_H
#include "opcode.h"
#include <pthread.h>
#include <ctype.h>
#include <string.h>
#include <limits.h>
#if bench
#include <sys/time.h>
#include <signal.h>
#include <math.h>
#endif
#include <curses.h>
#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;
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, int opcode, uint8_t prefix, uint8_t ext_prefix, uint8_t prefix2, uint8_t *op_type, uint8_t *op_id, uint8_t thread);
#endif
extern int get_key(WINDOW *scr, int delay, uint64_t cycles);
extern void io(uint64_t address, uint8_t rw, uint64_t cycles);
extern void init_scr();
static 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 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 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:
case STA_Z:
case STA_ZX:
case STA_ZY:
case STA_IN:
case STA_IX:
case STA_IY:
case STY_AB:
case STY_Z:
case STY_IN:
case STX_AB:
case STX_Z:
case STX_IN:
case STB_AB:
case STB_Z:
case STB_ZX:
case STB_ZY:
case STB_IN:
case STB_IX:
case STB_IY:
case INC_AB:
case INC_Z:
case DEC_AB:
case DEC_Z:
return 0;
default:
return 1;
}
}
}
static 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:
case LDA_AB:
case LDA_Z:
case LDA_ZX:
case LDA_ZY:
case LDA_IN:
case LDA_IX:
case LDA_IY:
case LDB_IMM:
case LDB_AB:
case LDB_Z:
case LDB_ZX:
case LDB_ZY:
case LDB_IN:
case LDB_IX:
case LDB_IY:
case LDY_IMM:
case LDY_AB:
case LDY_Z:
case LDY_IN:
case LDX_IMM:
case LDX_AB:
case LDX_Z:
case LDX_IN:
case JMP_AB:
case JMP_Z:
case JMP_IN:
case JSR_IN:
case JSR_AB:
case JSR_Z:
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 void tick(struct sux *cpu, uint8_t inc_clk) {
#if getclk
cpu->clk += inc_clk;
#endif
#if (IO || debug) && !branch
#if keypoll
pthread_mutex_lock(&mutex);
#endif
get_key(scr, 0, cpu->clk);
#if keypoll
pthread_mutex_unlock(&mutex);
#endif
#endif
}
static 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 (inc_clk) {
tick(cpu, inc_clk);
}
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, cpu->clk);
}
#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
#endif
} else {
return (size < 7) ? (reg & ~mask) | (mask) : mask;
}
}
static 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
#endif
#if (IO || debug) && !branch
#if keypoll
pthread_mutex_lock(&mutex);
#endif
if (check_io) {
io(address, 0, cpu->clk);
}
#if keypoll
pthread_mutex_unlock(&mutex);
#endif
#endif
}
if (inc_clk) {
tick(cpu, inc_clk);
}
}
static 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;
}
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 uint64_t imm_addr(struct sux *cpu) {
return cpu->pc;
}
static 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 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) {
return read_addr(cpu, prefix, inc_clk, type, inc_pc) + idx_reg;
}
static 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 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 (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 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);
}
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 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;
}
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 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 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 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 (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;
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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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);
}
static 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 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 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 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 uint64_t popcnt(struct sux *cpu, uint64_t value, uint8_t thread) {
uint64_t count = 0;
for (; value; count++, value &= value - 1);
return count;
}
static 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 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 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 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 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 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 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 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 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 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 uint64_t set(struct sux *cpu, uint8_t flag, uint8_t thread) {
setflag(flag == 0, Z);
return (flag != 0);
}
static 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 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 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 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 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);
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 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 :
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 :
do {
size = (!size) ? addr_size : size;
uint64_t mask = (-(uint64_t)1 >> ((7 - size) * 8));
cpu->e = (address & mask);
} while (0);
break;
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 :
push(cpu, address, 7, thread);
break;
case ADD_IMM:
case ADD_AB :
case ADD_Z :
case ADD_E :
cpu->a = adc(cpu, cpu->a, value, 0, 8, thread);
break;
case SUB_IMM:
case SUB_AB :
case SUB_Z :
case SUB_E :
cpu->a = adc(cpu, cpu->a, ~value, 1, 8, thread);
break;
case ADE_IMM:
case ADE_AB :
case ADE_Z :
cpu->e = adc(cpu, cpu->e, value, 0, 8, thread);
break;
case SBE_IMM:
case SBE_AB :
case SBE_Z :
cpu->e = adc(cpu, cpu->e, ~value, 1, 8, thread);
break;
case ADS_IMM:
case ADS_AB :
case ADS_Z :
case ADS_E :
cpu->sp = adc(cpu, cpu->sp, value, 0, 8, thread);
break;
case SBS_IMM:
case SBS_AB :
case SBS_Z :
case SBS_E :
cpu->sp = adc(cpu, cpu->sp, ~value, 1, 8, thread);
break;
case NOT_A :
cpu->a = ~cpu->a;
break;
case NOT_AB:
case NOT_Z :
case NOT_E :
not_mem(cpu, address, prefix, thread);
break;
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 :
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;
case PLE_IMP: cpu->e = pull(cpu, size, thread); break;
case CPE_IMM:
case CPE_AB :
case CPE_Z :
adc(cpu, cpu->e, ~value, 1, 8, thread);
break;
case ICE_AB :
case ICE_Z :
case ICE_E :
break;
case LDS_IMM:
case LDS_AB :
case LDS_Z :
case LDS_E :
cpu->sp = load(cpu, cpu->sp, address, size, thread);
break;
case DEE_IMP: cpu->e = idr(cpu, cpu->e, 0, thread); break;
case INE_IMP: cpu->e = idr(cpu, cpu->e, 1, thread); break;
case DES_IMP: cpu->sp = idr(cpu, cpu->sp, 0, thread); break;
case INS_IMP: cpu->sp = idr(cpu, cpu->sp, 1, thread); break;
case STS_AB:
case STS_Z :
case STS_E :
store(cpu, address, cpu->sp, prefix, thread);
break;
case STE_AB:
case STE_Z :
store(cpu, address, cpu->sp, prefix, thread);
break;
case STZ_AB:
case STZ_Z :
case STZ_E :
store(cpu, address, 0, prefix, thread);
break;
case SCO_IMM:
case SCO_AB :
case SCO_Z :
case SCO_E :
break;
case ECO_IMM:
case ECO_AB :
case ECO_Z :
case ECO_E :
break;
case CLZ_AB:
case CLZ_Z :
case CLZ_E :
cpu->a = lbcnt(cpu, value, 0, size, thread);
break;
case CLO_AB:
case CLO_Z :
case CLO_E :
cpu->a = lbcnt(cpu, value, 1, size, thread);
break;
case BIT_AB:
case BIT_Z :
case BIT_E :
bit_test(cpu, cpu->a, value, thread);
break;
case MMV_IMP:
cpu->b = mem_move(cpu, cpu->b, cpu->x, cpu->y, 1, size, thread);
break;
case SWP_A :
cpu->a = swap(cpu, cpu->a, size, thread);
break;
case SWP_AB:
case SWP_Z :
case SWP_E :
swap_mem(cpu, address, size, thread);
break;
case PCN_AB:
case PCN_Z :
case PCN_E :
cpu->a = popcnt(cpu, value, thread);
break;
case REP_REL:
if (cpu->b != 0) {
cpu->b--;
cpu->pc = address;
}
break;
case REQ_REL:
if (cpu->b != 0 && getflag(Z)) {
cpu->b--;
cpu->pc = address;
}
break;
case RNE_REL:
if (cpu->b != 0 && !getflag(Z)) {
cpu->b--;
cpu->pc = address;
}
break;
case LNG_IMM:
case LNG_E :
if (getflag(N)) {
cpu->a = load(cpu, cpu->a, address, size, thread);
}
break;
case LPO_IMM:
case LPO_E :
if (!getflag(N)) {
cpu->a = load(cpu, cpu->a, address, size, thread);
}
break;
case LCS_IMM:
case LCS_E :
if (getflag(C)) {
cpu->a = load(cpu, cpu->a, address, size, thread);
}
break;
case LCC_IMM:
case LCC_E :
if (!getflag(C)) {
cpu->a = load(cpu, cpu->a, address, size, thread);
}
break;
case LEQ_IMM:
case LEQ_E :
if (getflag(Z)) {
cpu->a = load(cpu, cpu->a, address, size, thread);
}
break;
case LNE_IMM:
case LNE_E :
if (!getflag(Z)) {
cpu->a = load(cpu, cpu->a, address, size, thread);
}
break;
case SNG_E :
if (getflag(N)) {
store(cpu, address, cpu->a, prefix, thread);
}
break;
case SPO_E :
if (!getflag(N)) {
store(cpu, address, cpu->a, prefix, thread);
}
break;
case SCS_E :
if (getflag(C)) {
store(cpu, address, cpu->a, prefix, thread);
}
break;
case SCC_E :
if (!getflag(C)) {
store(cpu, address, cpu->a, prefix, thread);
}
break;
case SEQ_E :
if (getflag(Z)) {
store(cpu, address, cpu->a, prefix, thread);
}
break;
case SNE_E :
if (!getflag(Z)) {
store(cpu, address, cpu->a, prefix, thread);
}
break;
}
}
static 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:
cpu->ps.u8[thread] = 0;
break;
case ADC_B:
value = cpu->b;
case ADC_IMM:
case ADC_AB:
case ADC_Z:
cpu->a = adc(cpu, cpu->a, value, getflag(C), 8, thread);
break;
case PHP_IMP: push(cpu, cpu->ps.u8[thread], 0, thread); break;
case PHA_IMP: push(cpu, cpu->a , size, thread); break;
case PHB_IMP: push(cpu, cpu->b , size, thread); break;
case PHY_IMP: push(cpu, cpu->y , size, thread); break;
case PHX_IMP: push(cpu, cpu->x , size, thread); break;
case TAY_IMP: cpu->y = transfer(cpu, cpu->a , value, thread); break;
case TAX_IMP: cpu->x = transfer(cpu, cpu->a , value, thread); break;
case TYX_IMP: cpu->x = transfer(cpu, cpu->y , value, thread); break;
case TYA_IMP: cpu->a = transfer(cpu, cpu->y , value, thread); break;
case TXA_IMP: cpu->a = transfer(cpu, cpu->x , value, thread); break;
case TXY_IMP: cpu->y = transfer(cpu, cpu->x , value, thread); break;
case TAB_IMP: cpu->b = transfer(cpu, cpu->a , value, thread); break;
case TSX_IMP: cpu->x = transfer(cpu, cpu->sp, value, thread); break;
case TBA_IMP: cpu->a = transfer(cpu, cpu->b , value, thread); break;
case TXS_IMP: cpu->sp = transfer(cpu, cpu->x , value, thread); break;
case BRA_REL:
case JMP_AB:
case JMP_Z:
case JMP_IN:
cpu->pc = address;
break;
case SBC_B:
value = cpu->b;
case SBC_IMM:
case SBC_AB:
case SBC_Z:
cpu->a = adc(cpu, cpu->a, ~value, getflag(C), 8, thread);
break;
case PLP_IMP: cpu->ps.u8[thread] = pull(cpu, 0, thread); break;
case PLA_IMP: cpu->a = pull(cpu, size, thread); break;
case PLB_IMP: cpu->b = pull(cpu, size, thread); break;
case PLY_IMP: cpu->y = pull(cpu, size, thread); break;
case PLX_IMP: cpu->x = pull(cpu, size, thread); break;
break;
case AND_B:
value = cpu->b;
case AND_IMM:
case AND_AB:
case AND_Z:
cpu->a = and(cpu, cpu->a, value, 8, thread);
break;
case BPO_REL:
if (!getflag(N)) {
cpu->pc = address;
}
break;
case ORA_B:
value = cpu->b;
case ORA_IMM:
case ORA_AB:
case ORA_Z:
cpu->a = or(cpu, cpu->a, value, 8, thread);
break;
case SEI_IMP:
setflag(1, I);
break;
case BNG_REL:
if (getflag(N)) {
cpu->pc = address;
}
break;
case XOR_B:
value = cpu->b;
case XOR_IMM:
case XOR_AB:
case XOR_Z:
cpu->a = xor(cpu, cpu->a, value, 8, thread);
break;
case CLI_IMP:
setflag(0, I);
break;
case BCS_REL:
if (getflag(C)) {
cpu->pc = address;
}
break;
case LSL_B:
value = cpu->b;
case LSL_IMM:
case LSL_AB:
case LSL_Z:
cpu->a = lsl(cpu, cpu->a, value, 8, thread);
break;
case SEC_IMP:
setflag(1, C);
break;
case STA_AB:
case STA_Z:
case STA_ZX:
case STA_ZY:
case STA_IN:
case STA_IX:
case STA_IY:
store(cpu, address, cpu->a, prefix, thread);
break;
case STY_AB:
case STY_Z:
case STY_IN:
store(cpu, address, cpu->y, prefix, thread);
break;
case STX_AB:
case STX_Z:
case STX_IN:
store(cpu, address, cpu->x, prefix, thread);
break;
case STB_AB:
case STB_Z:
case STB_ZX:
case STB_ZY:
case STB_IN:
case STB_IX:
case STB_IY:
store(cpu, address, cpu->b, prefix, thread);
break;
case BCC_REL:
if (!getflag(C)) {
cpu->pc = address;
}
break;
case LSR_B:
value = cpu->b;
case LSR_IMM:
case LSR_AB:
case LSR_Z:
cpu->a = lsr(cpu, cpu->a, value, 8, thread);
break;
case ASR_B:
value = cpu->b;
case ASR_IMM:
case ASR_AB:
case ASR_Z:
cpu->a = asr(cpu, cpu->a, value, 8, thread);
break;
case CLC_IMP:
setflag(0, C);
break;
case LDB_IMM:
case LDB_AB:
case LDB_Z:
case LDB_ZX:
case LDB_ZY:
case LDB_IN:
case LDB_IX:
case LDB_IY:
cpu->b = load(cpu, cpu->b, address, size, thread);
break;
case LDA_IMM:
case LDA_AB:
case LDA_Z:
case LDA_ZX:
case LDA_ZY:
case LDA_IN:
case LDA_IX:
case LDA_IY:
cpu->a = load(cpu, cpu->a, address, size, thread);
break;
case LDY_IMM:
case LDY_AB:
case LDY_Z:
case LDY_IN:
cpu->y = load(cpu, cpu->y, address, size, thread);
break;
case LDX_IMM:
case LDX_AB:
case LDX_Z:
case LDX_IN:
cpu->x = load(cpu, cpu->x, address, size, thread);
break;
case BEQ_REL:
if (getflag(Z)) {
cpu->pc = address;
}
break;
case ROL_B:
value = cpu->b;
case ROL_IMM:
case ROL_AB:
case ROL_Z:
cpu->a = rol(cpu, cpu->a, value, 8, thread);
break;
case BNE_REL:
if (!getflag(Z)) {
cpu->pc = address;
}
break;
case ROR_B:
value = cpu->b;
case ROR_IMM:
case ROR_AB:
case ROR_Z:
cpu->a = ror(cpu, cpu->a, value, 8, thread);
break;
case BVS_REL:
if (getflag(V)) {
cpu->pc = address;
}
break;
case MUL_B:
value = cpu->b;
case MUL_IMM:
case MUL_AB:
case MUL_Z:
cpu->a = mul(cpu, cpu->a, value, 8, thread);
break;
case BVC_REL:
if (!getflag(V)) {
cpu->pc = address;
}
break;
case DIV_B:
case DIV_IMM:
case DIV_AB:
case DIV_Z:
rem = (opcode != DIV_B) ? &cpu->b : &cpu->x;
cpu->a = divd(cpu, cpu->a, value, rem, 8, thread);
break;
case CLV_IMP:
setflag(0, V);
break;
case CPB_IMM:
case CPB_AB:
case CPB_Z:
case CPB_IN:
case CPB_IX:
case CPB_IY:
adc(cpu, cpu->b, ~value, 1, 8, thread);
break;
case CMP_B:
value = cpu->b;
case CMP_IMM:
case CMP_AB:
case CMP_Z:
case CMP_IN:
case CMP_IX:
case CMP_IY:
adc(cpu, cpu->a, ~value, 1, 8, thread);
break;
case CPY_IMM:
case CPY_AB:
case CPY_Z:
adc(cpu, cpu->y, ~value, 1, 8, thread);
break;
case CPX_IMM:
case CPX_AB:
case CPX_Z:
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:
case JSR_AB:
case JSR_Z:
push(cpu, cpu->pc, (size) ? size : 7, thread);
cpu->pc = address;
break;
case INC_AB:
case INC_Z:
idm(cpu, address, prefix, 1, thread);
break;
case NOP_IMP:
break;
case RTI_IMP:
cpu->ps.u8[thread] = pull(cpu, 0, thread);
size = 0;
case RTS_IMP:
cpu->pc = pull(cpu, (size) ? size : 7, thread);
break;
case DEC_AB:
case DEC_Z:
idm(cpu, address, prefix, 0, thread);
break;
case BRK_IMP:
case WAI_IMP:
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;
}
}
#define shift(reg, value, sign, shift) (((reg) shift (value)) | ((sign)))
#define rotate(sum, reg, value, shift1, shift2, c1, c2) \
switch (value & 0x3F) { \
case 0: sum = (reg); break; \
case 1: sum = shift(reg, value, c1, shift1); break; \
default: sum = shift(reg, value, c2, shift1) | shift(reg, (msb+1)-value, 0, shift2); break; \
}
#if 0
#else
#define t(w8, w7, w6, w5, w4, w3, w2, w1, w0) \
if ((o8<1?w0 : o8<2?w1 : o8<3?w2 : o8<4?w3 : \
o8<5?w4 : o8<6?w5 : o8<7?w6 : o8<8?w7 : w8) & o8m)
#endif
#define inst(op, ext) \
static void inst_##op(struct sux *cpu, uint8_t prefix, uint8_t size, int inc_pc, int inc_clk, uint8_t thread) { \
const unsigned int o8 = 0x##op / 32, o8m = 1 << (0x##op % 32); \
uint8_t rs = ((1 << ((prefix >> 4) & 3)) - 1); \
uint8_t msb = size*8; \
uint8_t carry = 0; \
uint64_t sign = 0; \
uint64_t addr = 0, idx = 0, tmp = 0, tmp2 = 0; \
uint64_t dummy = 0, *reg = &dummy; \
uint64_t dummy2 = 0, *reg2 = &dummy2; \
int pre_idx = 0, mem_type = ZM; \
\
t(1, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000) { addr = 0xFFA0; } \
t(2, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000) { addr = 0xFFC0; } \
t(4, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000) { addr = 0xFFE0; } \
t(0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000200, 0x00000000, 0x00000000, 0x00000000) { addr = 0xFFF0; } \
t(7, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000200, 0x00000000, 0x00000000, 0x00000000) { rs = 7; } \
t(0, 0x00060000, 0x00060000, 0x00160000, 0x00160000, 0x01160000, 0x01160000, 0x01170000, 0x01170000) { mem_type = ABS; } \
t(0, 0x01000100, 0x01000100, 0x04000400, 0x00000000, 0x00000000, 0x40004000, 0x40004000, 0x00000000) { idx = cpu->x; } \
t(0, 0x06400200, 0x06400400, 0x00000000, 0x00000000, 0x00000000, 0x10000000, 0x10000000, 0x00000000) { idx = cpu->y; } \
t(0, 0x00460160, 0x00460160, 0x00160160, 0x00160160, 0x01161160, 0x11165161, 0x11175161, 0x01171160) { addr = read_addr(cpu, prefix, inc_clk, mem_type, inc_pc) + idx; } \
t(0, 0x01000000, 0x01000000, 0x04000400, 0x00000000, 0x00000000, 0x40000000, 0x40000000, 0x00000000) { pre_idx = 1; } \
t(0, 0x07101210, 0x17101410, 0x14001400, 0x10001000, 0x10000000, 0x40000000, 0x40000000, 0x00000000) { addr = ind_idx_addr(cpu, prefix, inc_clk, ZM, inc_pc, idx, pre_idx); } \
t(0, 0x07561370, 0x17561570, 0x14161560, 0x10161160, 0x11161160, 0x51165161, 0x51175161, 0x01171160) { idx = 0; } \
t(0, 0x00010001, 0x00010001, 0x00010001, 0x00010001, 0x00010000, 0x00000000, 0x00000000, 0x00000000) { addr = rel_addr(cpu, prefix, inc_clk, inc_pc); } \
\
t(0, 0x02220022, 0x03760576, 0x00220432, 0x40665076, 0x00660066, 0x04660066, 0x55665066, 0x04660066) { reg = &cpu->a; } \
t(0, 0x05540354, 0x04000000, 0x44004200, 0x02000000, 0x10000000, 0x51005000, 0x00000000, 0x00100510) { reg = &cpu->b; } \
t(0, 0x40004000, 0x00001200, 0x12000000, 0x00001400, 0x01101510, 0x00000400, 0x00100110, 0x00000000) { reg = &cpu->x; } \
t(0, 0x00000000, 0x40004000, 0x00041044, 0x10001200, 0x06000000, 0x00100110, 0x00000400, 0x01001000) { reg = &cpu->y; } \
t(0, 0x00000000, 0x00000000, 0x00000000, 0x04000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000) { reg = &cpu->sp; } \
t(5, 0x00010001, 0x00010001, 0x00010001, 0x00010001, 0x40014200, 0x00000200, 0x02000200, 0x02000201) { reg = (uint64_t *)&cpu->ps.u8[thread]; } \
t(7, 0x07470371, 0x03470171, 0x14171561, 0x00171161, 0x10170360, 0x00160160, 0x00160160, 0x00160160) { tmp = read_value(cpu, 0, addr, rs, inc_clk, 1); } \
t(0, 0x00000006, 0x00000006, 0x00000006, 0x00000006, 0x00000016, 0x00000016, 0x00000016, 0x00000016) { tmp = read_value(cpu, 0, cpu->pc, rs, inc_clk, 0); cpu->pc += rs+1; } \
t(0, 0x00200000, 0x00200000, 0x00200000, 0x00600000, 0x00600000, 0x00600000, 0x00600000, 0x00600000) { tmp = cpu->b; } \
t(7, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000200, 0x00000000, 0x00000000, 0x00000000) { addr = tmp; } \
\
t(0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000400, 0x00000400, 0x00000400) { reg2 = &cpu->a; } \
t(0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00040044, 0x00000000, 0x04000000) { reg2 = &cpu->b; } \
t(0, 0x00000000, 0x00000000, 0x00000000, 0x04000000, 0x04000000, 0x04400000, 0x00000000, 0x00000000) { reg2 = &cpu->x; } \
t(0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000400, 0x00000000, 0x04000000, 0x00000000) { reg2 = &cpu->y; } \
t(0, 0x00000000, 0x00000000, 0x00000000, 0x00000400, 0x00000000, 0x00000000, 0x00000000, 0x00000000) { reg2 = &cpu->sp; } \
\
t(0, 0x00100000, 0x04101600, 0x02000210, 0x12000210, 0x03001000, 0x51005000, 0x51005000, 0x01001000) { tmp = *reg; } \
t(0, 0x00000000, 0x00000200, 0x00100310, 0x00000200, 0x00000000, 0x00000000, 0x00000000, 0x00000000) { ++tmp; } \
t(0, 0x00000000, 0x00000000, 0x02000000, 0x02100110, 0x02000000, 0x00000000, 0x00000000, 0x00000000) { --tmp; } \
\
t(0, 0x00100000, 0x04101400, 0x00100100, 0x10100100, 0x01001000, 0x51005000, 0x51005000, 0x01001000) { write_value(cpu, tmp, addr, rs, inc_clk, 1); } \
\
t(5, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x40004200, 0x00000000, 0x00000000, 0x00000000) { rs = 0; } \
t(0, 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000001, 0x00000000, 0x00000000, 0x00000000) { *reg = pull(cpu, rs, thread); } \
t(0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000001, 0x00010000, 0x00000000, 0x00000000) { cpu->pc = pull(cpu, (rs) ? rs : 7, thread); } \
t(5, 0x00000000, 0x10000000, 0x00000000, 0x00000000, 0x00000200, 0x00000001, 0x00010000, 0x00000000) { push(cpu, cpu->pc, (rs) ? rs : 7, thread); } \
t(5, 0x00004000, 0x00004000, 0x00004000, 0x00004000, 0x00004200, 0x00000000, 0x00000000, 0x00000000) { push(cpu, *reg, rs, thread); } \
\
t(7, 0x00011001, 0x10010001, 0x00010001, 0x00010001, 0x00010200, 0x00000201, 0x02010201, 0x02010200) { tmp = 1; } \
t(0, 0x00000000, 0x00000001, 0x00010000, 0x00000001, 0x00010000, 0x00000000, 0x00000000, 0x00000000) { tmp <<= 1; } \
t(5, 0x00000001, 0x00010000, 0x00000000, 0x00000001, 0x00010200, 0x00000200, 0x02000200, 0x00000000) { tmp <<= 2; } \
t(0, 0x00000000, 0x00000000, 0x00000000, 0x00000001, 0x00010000, 0x00000000, 0x00000000, 0x00000000) { tmp <<= 4; } \
t(0, 0x06000000, 0x00000000, 0x04000400, 0x00441044, 0x10000000, 0x00100310, 0x00320332, 0x00100310) { tmp = ~tmp; } \
t(5, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00220222, 0x00000000, 0x02000000, 0x02000000) { tmp |= *reg; } \
t(0, 0x00000001, 0x00010001, 0x00010001, 0x00010001, 0x00010000, 0x00220222, 0x00000200, 0x00000200) { tmp &= *reg; } \
t(0, 0x00000000, 0x00000000, 0x00000000, 0x00220022, 0x00000000, 0x00000000, 0x00000000, 0x00000000) { tmp ^= *reg; } \
\
\
t(7, 0x00011000, 0x10010000, 0x00010000, 0x00010001, 0x00000200, 0x00000001, 0x00010001, 0x00010000) { if (tmp) { cpu->pc = addr; } } \
t(0, 0x00000001, 0x00000001, 0x00000001, 0x00000000, 0x00010000, 0x00000000, 0x00000000, 0x00000000) { if (!tmp) { cpu->pc = addr; } } \
\
t(0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00440044, 0x00000000, 0x00000000, 0x00000000) { sign = -(uint64_t)(*reg >> (msb-1)) << (msb-1)-tmp2; } \
t(0, 0x00220022, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00220022, 0x00660066) { carry = getflag(C); } \
t(0, 0x06000000, 0x00000000, 0x04000400, 0x00441044, 0x10000000, 0x00100110, 0x00100110, 0x00100110) { carry = 1; } \
t(0, 0x06220022, 0x00220022, 0x04220422, 0x00441044, 0x10440044, 0x00540154, 0x00760176, 0x00760176) { tmp2 = tmp; } \
t(0, 0x06000000, 0x00000000, 0x04000400, 0x00441044, 0x10000000, 0x00100110, 0x00320132, 0x00320132) { tmp += *reg + carry; carry = tmp < tmp2; } \
t(0, 0x00000000, 0x00000000, 0x00220022, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000) { tmp = (tmp2 < msb) ? shift(*reg, tmp2, 0, <<) : 0; } \
t(0, 0x00000000, 0x00220022, 0x00000000, 0x00000000, 0x00440044, 0x00000000, 0x00000000, 0x00000000) { tmp = (tmp2 < msb) ? shift(*reg, tmp2, sign, >>) : 0; } \
t(0, 0x00220022, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000) { rotate(tmp, *reg, tmp2, <<, >>, carry & 1, carry << (tmp2-1)); } \
t(0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00440044) { rotate(tmp, *reg, tmp2, >>, <<, carry << (msb-1), carry << (msb-tmp2)); } \
t(0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00440044, 0x00000000) { tmp *= *reg; } \
t(0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00440044, 0x00000000, 0x00000000) { tmp = *reg / tmp; *reg2 = *reg % tmp2; } \
t(0, 0x00220022, 0x00000000, 0x00220022, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000) { carry = (*reg >> (msb-(tmp2+!tmp2))) & 1; } \
t(0, 0x00000000, 0x00220022, 0x00000000, 0x00000000, 0x00440044, 0x00000000, 0x00000000, 0x00440044) { carry = (*reg >> tmp2-(tmp2 != 0)) & 1; } \
\
t(5, 0x01660376, 0x03660376, 0x12261276, 0x02220232, 0x02760376, 0x00660266, 0x02660266, 0x02660267) { *reg = tmp; } \
t(0, 0x00000000, 0x00000000, 0x00000000, 0x04000400, 0x04000400, 0x04000400, 0x04000400, 0x04000400) { *reg = *reg2; } \
\
t(0, 0x00000000, 0x00000000, 0x00100100, 0x00100100, 0x00000000, 0x00000000, 0x00000000, 0x00000000) { msb = rs*8; } \
t(0, 0x00000000, 0x00000000, 0x00000000, 0x04000400, 0x04000400, 0x04000400, 0x04000400, 0x04000400) { tmp = *reg2; } \
t(0, 0x06220022, 0x00220022, 0x04220422, 0x00441044, 0x10440044, 0x00100110, 0x00320132, 0x00760176) { setflag(carry, C); } \
t(0, 0x07660376, 0x03660376, 0x16361776, 0x06761776, 0x16760576, 0x04760576, 0x04760576, 0x04760576) { setflag(tmp == 0, Z); } \
t(0, 0x06000000, 0x00000000, 0x04000400, 0x00441044, 0x10000000, 0x00100110, 0x00760176, 0x00320132) { setflag(((*reg^tmp2) >> (msb-1)) && ((*reg^tmp) >> (msb-1)), V); } \
t(0, 0x07660376, 0x03660376, 0x16361776, 0x06761776, 0x16760576, 0x04760576, 0x04760576, 0x04760576) { setflag(tmp >> (msb-1), N); } \
}
typedef void (inst_func)(struct sux *cpu, uint8_t prefix, uint8_t size, int inc_pc, int inc_clk, uint8_t thread);
#define inst_func(op) inst_##op
#define INST \
o(00) o(01) o(02) o(03) o(04) o(05) o(06) o(07) \
o(08) o(09) o(0A) o(0B) o(0C) o(0D) o(0E) o(0F) \
o(10) o(11) o(12) o(13) o(14) o(15) o(16) o(17) \
o(18) o(19) o(1A) o(1B) o(1C) o(1D) o(1E) o(1F) \
o(20) o(21) o(22) o(23) o(24) o(25) o(26) o(27) \
o(28) o(29) o(2A) o(2B) o(2C) o(2D) o(2E) o(2F) \
o(30) o(31) o(32) o(33) o(34) o(35) o(36) o(37) \
o(38) o(39) o(3A) o(3B) o(3C) o(3D) o(3E) o(3F) \
o(40) o(41) o(42) o(43) o(44) o(45) o(46) o(47) \
o(48) o(49) o(4A) o(4B) o(4C) o(4D) o(4E) o(4F) \
o(50) o(51) o(52) o(53) o(54) o(55) o(56) o(57) \
o(58) o(59) o(5A) o(5B) o(5C) o(5D) o(5E) o(5F) \
o(60) o(61) o(62) o(63) o(64) o(65) o(66) o(67) \
o(68) o(69) o(6A) o(6B) o(6C) o(6D) o(6E) o(6F) \
o(70) o(71) o(72) o(73) o(74) o(75) o(76) o(77) \
o(78) o(79) o(7A) o(7B) o(7C) o(7D) o(7E) o(7F) \
o(80) o(81) o(82) o(83) o(84) o(85) o(86) o(87) \
o(88) o(89) o(8A) o(8B) o(8C) o(8D) o(8E) o(8F) \
o(90) o(91) o(92) o(93) o(94) o(95) o(96) o(97) \
o(98) o(99) o(9A) o(9B) o(9C) o(9D) o(9E) o(9F) \
o(A0) o(A1) o(A2) o(A3) o(A4) o(A5) o(A6) o(A7) \
o(A8) o(A9) o(AA) o(AB) o(AC) o(AD) o(AE) o(AF) \
o(B0) o(B1) o(B2) o(B3) o(B4) o(B5) o(B6) o(B7) \
o(B8) o(B9) o(BA) o(BB) o(BC) o(BD) o(BE) o(BF) \
o(C0) o(C1) o(C2) o(C3) o(C4) o(C5) o(C6) o(C7) \
o(C8) o(C9) o(CA) o(CB) o(CC) o(CD) o(CE) o(CF) \
o(D0) o(D1) o(D2) o(D3) o(D4) o(D5) o(D6) o(D7) \
o(D8) o(D9) o(DA) o(DB) o(DC) o(DD) o(DE) o(DF) \
o(E0) o(E1) o(E2) o(E3) o(E4) o(E5) o(E6) o(E7) \
o(E8) o(E9) o(EA) o(EB) o(EC) o(ED) o(EE) o(EF) \
o(F0) o(F1) o(F2) o(F3) o(F4) o(F5) o(F6) o(F7) \
o(F8) o(F9) o(FA) o(FB) o(FC) o(FD) o(FE) o(FF) \
i(100) i(101) i(102)
#if 1
#define i(n) inst(n, 0)
#define o(n) inst(n, 0)
INST
#undef o
#undef i
#else
#endif
#if 0
#else
#define i(n) inst_func(n),
#define o(n) inst_func(n),
#endif
static inst_func *const i[] = {
INST
};
#undef o
#undef i
#undef ORTHO_1CC
#undef ORTHO_1OP
#undef ORTHO_2OP
#endif