diff options
Diffstat (limited to 'sux.h')
-rw-r--r-- | sux.h | 343 |
1 files changed, 212 insertions, 131 deletions
@@ -39,7 +39,7 @@ extern pthread_cond_t cond; extern pthread_cond_t main_cond; #if debug -extern void disasm(struct sux *cpu, uint64_t *operands, uint8_t lines, uint8_t opcode, uint8_t prefix, uint8_t thread); +extern void disasm(struct sux *cpu, uint8_t lines, uint8_t opcode, uint8_t prefix, uint8_t thread); #endif /*#define KEYBUF_SIZE 0x40 @@ -49,7 +49,181 @@ extern int get_key(WINDOW *scr); extern void io(uint64_t address, uint8_t rw); extern void init_scr(); -static inline uint64_t get_addr(struct sux *cpu, uint64_t *tmpaddr, uint8_t opcode, uint8_t prefix, uint8_t thread) { +static inline union reg read_value(struct sux *cpu, uint64_t address, uint8_t size, uint8_t inc_clk, uint8_t check_io) { + union reg value; + value.u64 = 0; + #if (IO || debug) && !branch + #if keypoll + pthread_mutex_lock(&mutex); + #endif + if (check_io) { + io(address, 1); + } + #if keypoll + pthread_mutex_unlock(&mutex); + #endif + #endif + switch (size) { + case 7: value.u8[7] = addr[address+7]; + case 6: value.u8[6] = addr[address+6]; + case 5: value.u8[5] = addr[address+5]; + case 4: value.u8[4] = addr[address+4]; + case 3: value.u8[3] = addr[address+3]; + case 2: value.u8[2] = addr[address+2]; + case 1: value.u8[1] = addr[address+1]; + case 0: value.u8[0] = addr[address+0]; + } + #if getclk + if (inc_clk) { + ++cpu->clk; + } + #endif + return value; +} + +static inline void write_value(struct sux *cpu, union reg value, uint64_t address, uint8_t size, uint8_t inc_clk, uint8_t check_io) { + switch (size) { + case 7: addr[address+7] = value.u8[7]; + case 6: addr[address+6] = value.u8[6]; + case 5: addr[address+5] = value.u8[5]; + case 4: addr[address+4] = value.u8[4]; + case 3: addr[address+3] = value.u8[3]; + case 2: addr[address+2] = value.u8[2]; + case 1: addr[address+1] = value.u8[1]; + case 0: addr[address+0] = value.u8[0]; + } + #if (IO || debug) && !branch + #if keypoll + pthread_mutex_lock(&mutex); + #endif + if (check_io) { + io(address, 0); + } + #if keypoll + pthread_mutex_unlock(&mutex); + #endif + #endif + #if getclk + if (inc_clk) { + ++cpu->clk; + } + #endif +} + +static inline uint64_t offset_addr(struct sux *cpu, union reg offset, uint8_t size, uint8_t inc_clk, uint8_t prefix) { + uint64_t of; + switch (prefix >> 6) { + case 1: of = ((cpu->stk_st << 16) | cpu->sp); break; + case 2: of = cpu->pc ; break; + } + #if getclk + if (inc_clk) { + ++cpu->clk; + } + #endif + switch (size) { + case 0: return of + (int8_t )offset.u8 [0]; + case 1: return of + (int16_t)offset.u16[0]; + case 2: + case 3: return of + (int32_t)offset.u32[0]; + case 4: + case 5: + case 6: + case 7: return of + (int64_t)offset.u64 ; + } +} + +static inline uint64_t imm_addr(struct sux *cpu) { + return cpu->pc; +} + +static inline uint64_t zm_addr(struct sux *cpu, uint8_t prefix, uint8_t inc_clk, uint8_t inc_pc) { + union reg address = read_value(cpu, cpu->pc, get_addrsize(prefix, ZM), inc_clk, 0); + if (prefix >> 6) { + address.u64 = offset_addr(cpu, address, get_addrsize(prefix, ZM), inc_clk, prefix); + } + if (inc_pc) { + cpu->pc += get_addrsize(prefix, ZM)+1; + } + return address.u64; +} + +static inline uint64_t zmx_addr(struct sux *cpu, uint8_t prefix, uint8_t inc_clk, uint8_t inc_pc) { + #if getclk + if (inc_clk) { + ++cpu->clk; + } + #endif + return zm_addr(cpu, prefix, inc_clk, inc_pc) + cpu->x; +} + +static inline uint64_t zmy_addr(struct sux *cpu, uint8_t prefix, uint8_t inc_clk, uint8_t inc_pc) { + #if getclk + if (inc_clk) { + ++cpu->clk; + } + #endif + return zm_addr(cpu, prefix, inc_clk, inc_pc) + cpu->y; +} + +static inline uint64_t abs_addr(struct sux *cpu, uint8_t prefix, uint8_t inc_clk, uint8_t inc_pc) { + union reg address = read_value(cpu, cpu->pc, get_addrsize(prefix, ABS), inc_clk, 0); + if (prefix >> 6) { + address.u64 = offset_addr(cpu, address, get_addrsize(prefix, ABS), inc_clk, prefix); + } + if (inc_pc) { + cpu->pc += get_addrsize(prefix, ABS)+1; + } + return address.u64; +} + +static inline uint64_t ind_addr(struct sux *cpu, uint8_t prefix, uint8_t inc_clk, uint8_t inc_pc) { + union reg address = read_value(cpu, zm_addr(cpu, prefix, inc_clk, inc_pc), 7, inc_clk, 0); + return address.u64; +} + +static inline uint64_t indx_addr(struct sux *cpu, uint8_t prefix, uint8_t inc_clk, uint8_t inc_pc) { + union reg address = read_value(cpu, zm_addr(cpu, prefix, inc_clk, inc_pc)+cpu->x, 7, inc_clk, 0); + #if getclk + if (inc_clk) { + ++cpu->clk; + } + #endif + return address.u64; +} + +static inline uint64_t indy_addr(struct sux *cpu, uint8_t prefix, uint8_t inc_clk, uint8_t inc_pc) { + #if getclk + if (inc_clk) { + ++cpu->clk; + } + #endif + return ind_addr(cpu, prefix, inc_clk, inc_pc) + cpu->y; +} + +static inline uint64_t rel_addr(struct sux *cpu, uint8_t prefix, uint8_t inc_clk, uint8_t inc_pc) { + uint8_t rs = (prefix >> 4) & 3; + uint8_t size = (1 << rs) - 1; + union reg offset = read_value(cpu, cpu->pc, size, inc_clk, 0); + uint64_t address; + if (inc_pc) { + cpu->pc += (size + 1); + } + switch (rs) { + default: address = cpu->pc + (int8_t )offset.u8 [0]; break; + case 1 : address = cpu->pc + (int16_t)offset.u16[0]; break; + case 2 : address = cpu->pc + (int32_t)offset.u32[0]; break; + case 3 : address = cpu->pc + (int64_t)offset.u64 ; break; + } + #if getclk + if (inc_clk) { + ++cpu->clk; + } + #endif + return address; +} + +static inline uint64_t get_addr(struct sux *cpu, uint8_t opcode, uint8_t prefix, uint8_t inc_pc, uint8_t inc_clk, uint8_t thread) { union reg address; union reg value; uint8_t tmp = 0; @@ -62,116 +236,33 @@ static inline uint64_t get_addr(struct sux *cpu, uint64_t *tmpaddr, uint8_t opco case IMPL: break; case IMM: - address.u64 = cpu->pc; + address.u64 = imm_addr(cpu); switch (opcode) { case LSL_IMM: case LSR_IMM: case ROL_IMM: case ROR_IMM: - case ASR_IMM: ++cpu->pc; break; - default : cpu->pc+=(1 << ((prefix >> 4) & 3)); /* Falls Through. */ - case TXS_IMM: break; - } - break; - case ZM: - case ZMX: - case ZMY: - case IND: - case INDX: - case INDY: - tmp = 0; - address.u8[0] = addr[cpu->pc]; - /* Unroll Loop by implementing Duff's Device. */ - tmp = get_addrsize(prefix, ZM)+1; - setreg_sw(address.u8, 0, addr, cpu->pc, prefix, ZM, AM); - - cpu->pc+=tmp; - #if debug && !bench - *tmpaddr = address.u64; - #endif - #if getclk - iclk++; - #endif - uint64_t reg = 0; - saveaddr.u64 = 0; - if (prefix >> 6) { - switch (prefix >> 6) { - case 1: tmp2 = ((cpu->stk_st << 16) | cpu->sp); break; - case 2: tmp2 = cpu->pc ; break; - } - saveaddr = address; - switch ((prefix & 0x0C) >> 2) { - case 0: saveaddr.u64 = tmp2 + (int8_t )address.u8[0] ; break; - case 2: saveaddr.u64 = tmp2 + (int64_t)address.u64 ; break; - case 1: - case 3: saveaddr.u64 = tmp2 + (int32_t)address.u32[0]; break; - } - address.u64 = saveaddr.u64; - } - switch (optype[opcode]) { - case ZMX: - address.u64 += cpu->x; - #if getclk - iclk++; - #endif - break; - case ZMY: - address.u64 += cpu->y; - #if getclk - iclk++; - #endif + case ASR_IMM: + if (inc_pc) { + ++cpu->pc; + } break; - case INDX: - case INDY: - if (optype[opcode] == INDX) { - address.u64 += cpu->x; - #if getclk - iclk++; - #endif - } else { - reg += cpu->y; - #if getclk - iclk++; - #endif + default: + if (inc_pc) { + cpu->pc+=(1 << ((prefix >> 4) & 3)); } /* Falls Through. */ - case IND: - setreg(value.u8, +, 0, addr, +, address.u64, 7); - #if getclk - iclk++; - #endif - value.u64 += reg; - address.u64 = value.u64; - break; - } - break; - case ABS: - tmp = get_addrsize(prefix, ABS)+1; - setreg_sw(address.u8, 0, addr, cpu->pc, prefix, ABS, AM); - cpu->pc+=tmp; - #if getclk - iclk++; - #endif - saveaddr.u64 = 0; - if (prefix >> 6) { - switch (prefix >> 6) { - case 1: tmp2 = ((cpu->stk_st << 16) | cpu->sp); break; - case 2: tmp2 = cpu->pc ; break; - } - saveaddr = address; - switch ((prefix & 0x0C) >> 2) { - case 0: saveaddr.u64 = tmp2 + (int16_t)address.u16[0]; break; - case 1: - case 2: - case 3: saveaddr.u64 = tmp2 + (int64_t)address.u64 ; break; - } - address.u64 = saveaddr.u64; + case TXS_IMM: break; } break; - case REL: - address.u64 = cpu->pc; - cpu->pc+=(1 << ((prefix >> 4) & 3)); - break; + case ZM : address.u64 = zm_addr(cpu, prefix, inc_clk, inc_pc); break; + case ZMX : address.u64 = zmx_addr(cpu, prefix, inc_clk, inc_pc); break; + case ZMY : address.u64 = zmy_addr(cpu, prefix, inc_clk, inc_pc); break; + case IND : address.u64 = ind_addr(cpu, prefix, inc_clk, inc_pc); break; + case INDX: address.u64 = indx_addr(cpu, prefix, inc_clk, inc_pc); break; + case INDY: address.u64 = indy_addr(cpu, prefix, inc_clk, inc_pc); break; + case ABS : address.u64 = abs_addr(cpu, prefix, inc_clk, inc_pc); break; + case REL : address.u64 = rel_addr(cpu, prefix, inc_clk, inc_pc); break; } return address.u64; @@ -222,16 +313,14 @@ static inline void push(struct sux *cpu, uint64_t value, uint8_t size, uint8_t t union reg reg; reg.u64 = value; uint64_t sbr = (cpu->stk_st << 16); - setreg(addr, -, (sbr+cpu->sp), reg.u8, -, size, size); + write_value(cpu, reg, (sbr+cpu->sp)-size, size, 1, 0); cpu->sp -= size+1; } static inline uint64_t pull(struct sux *cpu, uint8_t size, uint8_t thread) { - union reg reg; - reg.u64 = 0; uint64_t sbr = (cpu->stk_st << 16); + union reg reg = read_value(cpu, sbr+cpu->sp+1, size, 1, 0); cpu->sp += size+1; - setreg(reg.u8, -, size, addr, -, (sbr+cpu->sp), size); return reg.u64; } @@ -335,42 +424,34 @@ static inline uint64_t idr(struct sux *cpu, uint64_t reg, uint8_t inc, uint8_t t /* Increment, or Decrement memory. */ static inline void idm(struct sux *cpu, uint64_t address, uint8_t prefix, uint8_t inc, uint8_t thread) { - union reg value; - value.u64 = 0; - /* Unroll Loop by implementing Duff's Device. */ - setreg_sw(value.u8, 0, addr, address, prefix, 0, RS); + uint8_t size = (1 << ((prefix >> 4) & 3))-1; + union reg value = read_value(cpu, address, size, 1, 0); if (inc) { value.u64++; } else { value.u64--; } + uint8_t sign = 0; + switch ((prefix >> 4) & 3) { + default: sign = 7; break; + case 1: sign = 15; break; + case 2: sign = 31; break; + case 3: sign = 63; break; + } setflag(value.u64 == 0, Z); - setflag(value.u64 >> 7, N); - setreg_sw(addr, address, value.u8, 0, prefix, 0, RS); - io(address, 0); + setflag(value.u64 >> sign, N); + write_value(cpu, value, address, size, 1, 1); } -static inline uint64_t load(struct sux *cpu, uint64_t address, uint64_t reg, uint8_t prefix, uint8_t thread) { - io(address, 1); - union reg value; - value.u64 = reg; - setreg_sw(value.u8, 0, addr, address, prefix, 0, RS); - setflag(value.u64 == 0, Z); - setflag(value.u64 >> 63, N); - return value.u64; +static inline uint64_t load(struct sux *cpu, uint64_t value, uint8_t thread) { + setflag(value == 0, Z); + setflag(value >> 63, N); + return value; } static inline void store(struct sux *cpu, uint64_t address, uint64_t reg, uint8_t prefix, uint8_t thread) { + uint8_t size = (1 << ((prefix >> 4) & 3))-1; union reg value; value.u64 = reg; - setreg_sw(addr, address, value.u8, 0, prefix, 0, RS); - #if (IO || debug) && !branch - #if keypoll - pthread_mutex_lock(&mutex); - #endif - io(address, 0); - #if keypoll - pthread_mutex_unlock(&mutex); - #endif - #endif + write_value(cpu, value, address, size, 1, 1); } |