summaryrefslogtreecommitdiff
path: root/sux.h
diff options
context:
space:
mode:
Diffstat (limited to 'sux.h')
-rw-r--r--sux.h222
1 files changed, 132 insertions, 90 deletions
diff --git a/sux.h b/sux.h
index 9af8128..c028b84 100644
--- a/sux.h
+++ b/sux.h
@@ -22,6 +22,7 @@
#define copy64 1
extern uint8_t kbd_rdy;
+extern uint8_t dbg_print_per_inst;
extern WINDOW *scr;
extern WINDOW *regs;
@@ -292,6 +293,18 @@ static /*inline*/ uint8_t isread(uint8_t opcode, uint8_t ext_prefix) {
}
}
+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) {
#if copy64
uint64_t *d = dst;
@@ -510,7 +523,20 @@ static /*inline*/ uint64_t get_addr(struct sux *cpu, uint8_t opcode, uint8_t pre
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 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;
for (int i = 0; i < 2; i++) {
union reg tmp;
tmp.u64 = 0;
@@ -526,10 +552,8 @@ static /*inline*/ uint64_t get_ortho_addr(struct sux *cpu, uint8_t prefix, uint6
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, address, inst_size-1, 0, 0);
- if (inc_pc) {
- address += inst_size;
- }
+ 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]) {
@@ -539,18 +563,15 @@ static /*inline*/ uint64_t get_ortho_addr(struct sux *cpu, uint8_t prefix, uint6
}
if (addr_size != 0xFF) {
inst_size = addr_size+1;
- op[i].value = read_value(cpu, 0, address, inst_size-1, inc_clk, 0);
+ op[i].value = read_value(cpu, 0, tmp_addr, inst_size-1, inc_clk, 0);
value[i] = op[i].value;
- if (inc_pc) {
- address += inst_size;
- }
+ tmp_addr += inst_size;
}
if (rs && op[i].id == MEM_IMM) {
- value[i] = address;
- if (inc_pc) {
- address += rs;
- }
+ 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++) {
uint64_t reg;
@@ -572,17 +593,42 @@ static /*inline*/ uint64_t get_ortho_addr(struct sux *cpu, uint8_t prefix, uint6
case REG_R14: reg = cpu->r14; break;
case REG_R15: reg = cpu->r15; break;
}
- value[i] += reg;
+ tmp_val += reg;
}
if (op[i].id == MEM_SIB) {
- value[i] *= op[i].scale+1;
+ tmp_val *= op[i].scale+1;
+ } else 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;
}
@@ -859,6 +905,11 @@ static /*inline*/ uint64_t mov(struct sux *cpu, uint64_t src, uint64_t size, uin
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);
@@ -908,10 +959,30 @@ static /*inline*/ void exec_ortho_inst(struct sux *cpu, uint8_t opcode, uint8_t
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, 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, (op[1].id != MEM_IMM) ? op[1].value : address[1], size, 1, 1);
+ src = read_value(cpu, 0, address[1], size, 1, allow_io[1]);
} else {
switch (op[1].id) {
case REG_A : src = cpu->a; break;
@@ -934,7 +1005,7 @@ static /*inline*/ void exec_ortho_inst(struct sux *cpu, uint8_t opcode, uint8_t
}
if (op[0].type) {
if (op[0].id != MEM_IMM) {
- dst = read_value(cpu, 0, op[0].value, size, 1, 1);
+ dst = read_value(cpu, 0, address[0], size, 1, allow_io[0]);
}
} else {
switch (op[0].id) {
@@ -957,47 +1028,15 @@ static /*inline*/ void exec_ortho_inst(struct sux *cpu, uint8_t opcode, uint8_t
}
}
switch (opcode) {
- case ORTHO_2OP(MNG):
- if (getflag(N)) {
- dst = mov(cpu, src, size, thread);
- }
- break;
- case ORTHO_2OP(MPO):
- if (!getflag(N)) {
- dst = mov(cpu, src, size, thread);
- }
- break;
- case ORTHO_2OP(MCS):
- if (getflag(C)) {
- dst = mov(cpu, src, size, thread);
- }
- break;
- case ORTHO_2OP(MCC):
- if (!getflag(C)) {
- dst = mov(cpu, src, size, thread);
- }
- break;
- case ORTHO_2OP(MEQ):
- if (getflag(Z)) {
- dst = mov(cpu, src, size, thread);
- }
- break;
- case ORTHO_2OP(MNE):
- if (!getflag(Z)) {
- dst = mov(cpu, src, size, thread);
- }
- break;
- case ORTHO_2OP(MVS):
- if (getflag(V)) {
- dst = mov(cpu, src, size, thread);
- }
- break;
- case ORTHO_2OP(MVC):
- if (!getflag(V)) {
- dst = mov(cpu, src, size, thread);
- }
- break;
- case ORTHO_2OP(MOV): dst = mov(cpu, src, size, thread); break;
+ 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;
@@ -1012,34 +1051,35 @@ static /*inline*/ void exec_ortho_inst(struct sux *cpu, uint8_t opcode, uint8_t
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); 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 address;
+ uint64_t tmp_addr;
uint64_t mask;
if (op[1].type) {
uint8_t addr_size = get_ortho_addrsize(prefix, op[1].id);
- size = (!size) ? addr_size : size;
- address = op[1].value;
+ size = (!size) ? 7 : size;
+ tmp_addr = address[1];
} else {
- address = src;
+ tmp_addr = src;
}
mask = (-(uint64_t)1 >> ((7 - size) * 8));
- dst = (address & mask);
+ dst = (tmp_addr & mask);
} while (0);
break;
case ORTHO_1OP(PEA):
do {
- uint64_t address = (op[0].type) ? op[0].value : dst;
- push(cpu, address, 7, thread);
+ 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(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); 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;
@@ -1056,34 +1096,36 @@ static /*inline*/ void exec_ortho_inst(struct sux *cpu, uint8_t opcode, uint8_t
case ORTHO_1CC(SET, VC): dst = set(cpu, !getflag(V), thread); break;
}
- if (op[0].type) {
- if (op[0].id != MEM_IMM) {
- write_value(cpu, dst, op[0].value, size, 1, 1);
- }
- } 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 (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[0].id != MEM_IMM) {
- write_value(cpu, dst, op[1].value, size, 1, 1);
+ if (op[1].id != MEM_IMM) {
+ write_value(cpu, src, address[1], size, 1, 1);
}
} else {
switch (op[1].id) {