diff options
Diffstat (limited to 'sux.h')
-rw-r--r-- | sux.h | 222 |
1 files changed, 132 insertions, 90 deletions
@@ -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) { |