#include "sux.h"
#include <assert.h>
#include <ctype.h>
#include <string.h>
#if getclk
uint64_t clk[THREADS];
uint64_t tclk;
#endif
const uint16_t tv = 0xFF50;
#if !IO
uint64_t inst[THREADS];
#endif
#if bench
uint64_t inss;
#endif
#if debug
uint8_t subdbg;
#endif
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t main_mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
pthread_cond_t main_cond = PTHREAD_COND_INITIALIZER;
uint8_t threads_done = 0;
uint8_t step = 0;
uint8_t *addr;
uint8_t kbd_rdy;
WINDOW *scr;
struct suxthr {
struct sux sx;
uint8_t th;
};
#if bench
double ipc;
struct timeval str[THREADS], en[THREADS];
#endif
void *run(void *args) {
struct suxthr *thr = (void *)args;
struct sux *cpu = &thr->sx;
uint8_t thread = thr->th;
uint8_t prefix = 0;
uint8_t opcode = 0;
uint8_t esc = 0;
union reg address;
union reg value;
#if getclk
uint64_t iclk = 0;
#endif
#if !IO
uint64_t ins = 0;
#endif
#if !bench
uint8_t lines = (6*thread)+2;
#endif
#if debug && !bench
if (!subdbg) {
addr[STEP_ADDR] = 1;
step = 1;
}
#if keypoll
pthread_mutex_lock(&mutex);
#endif
werase(scr);
#if keypoll
pthread_mutex_unlock(&mutex);
#endif
#endif
uint64_t tmpaddr = 0;
#if bench
gettimeofday(&str[thread], 0);
#endif
for (;;) {
address.u64 = 0;
value.u64 = 0;
prefix = addr[cpu->pc[thread]];
if ((prefix & 0x03) != 0x03) {
prefix = 0;
}
cpu->pc[thread] += ((prefix & 0x03) == 0x03);
opcode = addr[cpu->pc[thread]];
#if debug && !bench
if (lines > 24*(thread+1)) {
lines = (24*thread)+2;
}
#if keypoll
pthread_mutex_lock(&mutex);
#endif
for (uint8_t i = (24*thread)+2; i <= 24*(thread+1); i++) {
wmove(scr, i, 0);
waddch(scr, (i == lines) ? '>' : ' ');
}
wmove(scr, lines, 1);
wclrtoeol(scr);
wprintw(scr,
"pc: $%04"PRIX64
", a: $%016"PRIX64
", b: $%016"PRIX64
", x: $%016"PRIX64
", y: $%016"PRIX64
, cpu->pc[thread]
, cpu->a[thread]
, cpu->b[thread]
, cpu->x[thread]
, cpu->y[thread]);
wprintw(scr,
", sp: $%04X"
", ps: $%02X"
", inst: "
, cpu->sp[thread]
, cpu->ps.u8[thread]);
#if keypoll
pthread_mutex_unlock(&mutex);
#endif
#endif
address.u64 = cpu->pc[thread];
++cpu->pc[thread];
#if getclk
++iclk;
#endif
if (optype[opcode] != IMPL) {
address.u64 = get_addr(cpu, &tmpaddr, opcode, prefix, thread);
value.u8[0] = addr[address.u64];
switch (1 << (prefix >> 4)) {
case 8:
value.u8[7] = addr[address.u64+7];
value.u8[6] = addr[address.u64+6];
value.u8[5] = addr[address.u64+5];
value.u8[4] = addr[address.u64+4];
case 4:
value.u8[3] = addr[address.u64+3];
value.u8[2] = addr[address.u64+2];
case 2:
value.u8[1] = addr[address.u64+1];
}
#if getclk
++iclk;
#endif
}
#if debug && !bench
#if keypoll
pthread_mutex_lock(&mutex);
#endif
uint64_t operands[3];
operands[0] = value.u64;
operands[1] = address.u64;
operands[2] = tmpaddr;
disasm(cpu, operands, lines, opcode, prefix, thread);
lines+=1;
#if keypoll
pthread_mutex_unlock(&mutex);
#endif
#endif
switch(opcode) {
case CPS:
cpu->ps.u64 = 0;
break;
case AAB:
value.u64 = cpu->b[thread];
case ADC:
case ADC_AB:
case ADC_Z:
adc(cpu, value.u64, thread);
break;
case PHB:
case PHP:
case PHA:
case PHY:
case PHX:
push(cpu, value.u64, opcode, thread);
break;
case TAY:
case TAX:
case TYX:
case TYA:
case TXA:
case TXY:
case TAB:
case TSX:
case TBA:
case TXS:
transfer(cpu, value.u64, opcode, prefix, thread);
break;
case JMP:
case JMP_Z:
case JMP_IN:
cpu->pc[thread] = address.u64;
break;
case SAB:
value.u64 = cpu->b[thread];
case SBC:
case SBC_AB:
case SBC_Z:
sbc(cpu, value.u64, thread);
break;
case PLB:
case PLP:
case PLA:
case PLY:
case PLX:
pull(cpu, value.u64, opcode, thread);
break;
case ABA:
value.u64 = cpu->b[thread];
case AND:
case AND_AB:
case AND_Z:
and(cpu, value.u64, thread);
break;
case STT:
break;
case BPO:
case BPO_Z:
if (!getflag(N)) {
cpu->pc[thread] = address.u64;
}
break;
case OAB:
value.u64 = cpu->b[thread];
case ORA:
case ORA_AB:
case ORA_Z:
or(cpu, value.u64, thread);
break;
case SEI:
setflag(1, I);
break;
case BNG:
case BNG_Z:
if (getflag(N)) {
cpu->pc[thread] = address.u64;
}
break;
case XAB:
value.u64 = cpu->b[thread];
case XOR:
case XOR_AB:
case XOR_Z:
xor(cpu, value.u64, thread);
break;
case CLI:
setflag(0, I);
break;
case BCS:
case BCS_Z:
if (getflag(C)) {
cpu->pc[thread] = address.u64;
}
break;
case LLB:
value.u64 = cpu->b[thread];
case LSL:
case LSL_AB:
case LSL_Z:
lsl(cpu, value.u64, thread);
break;
case SEC:
setflag(1, C);
break;
case STA:
case STY:
case STX:
case STB:
case STA_Z:
case STY_Z:
case STX_Z:
case STB_Z:
case STA_ZX:
case STY_ZX:
case STX_ZY:
case STB_ZX:
case STA_ZY:
case STB_ZY:
case STY_IN:
case STX_IN:
case STA_IN:
case STB_IN:
case STA_IX:
case STB_IX:
case STA_IY:
case STB_IY:
store(cpu, address.u64, &esc, opcode, prefix, thread);
step = addr[STEP_ADDR] || cpu->pc[thread] == CTRL_ADDR;
break;
case BCC:
case BCC_Z:
if (!getflag(C)) {
cpu->pc[thread] = address.u64;
}
break;
case LRB:
value.u64 = cpu->b[thread];
case LSR:
case LSR_AB:
case LSR_Z:
lsr(cpu, value.u64, thread);
break;
case ARB:
value.u64 = cpu->b[thread];
case ASR:
case ASR_AB:
case ASR_Z:
asr(cpu, value.u64, thread);
break;
case CLC:
setflag(0, C);
break;
case LDB:
case LDA:
case LDY:
case LDX:
case LDB_AB:
case LDA_AB:
case LDY_AB:
case LDX_AB:
case LDB_Z:
case LDA_Z:
case LDY_Z:
case LDX_Z:
case LDB_ZX:
case LDA_ZX:
case LDY_ZX:
case LDX_ZY:
case LDB_ZY:
case LDA_ZY:
case LDB_IN:
case LDA_IN:
case LDY_IN:
case LDX_IN:
case LDB_IX:
case LDA_IX:
case LDB_IY:
case LDA_IY:
load(cpu, address.u64, &esc, opcode, prefix, thread);
break;
case BEQ:
case BEQ_Z:
if (getflag(Z)) {
cpu->pc[thread] = address.u64;
}
break;
case RLB:
value.u64 = cpu->b[thread];
case ROL:
case ROL_AB:
case ROL_Z:
rol(cpu, value.u64, thread);
break;
case BNE:
case BNE_Z:
if (!getflag(Z)) {
cpu->pc[thread] = address.u64;
}
break;
case RRB:
value.u64 = cpu->b[thread];
case ROR:
case ROR_AB:
case ROR_Z:
ror(cpu, value.u64, thread);
break;
case BVS:
case BVS_Z:
if (getflag(V)) {
cpu->pc[thread] = address.u64;
}
break;
case MAB:
value.u64 = cpu->b[thread];
case MUL:
case MUL_AB:
case MUL_Z:
mul(cpu, value.u64, thread);
break;
case BVC:
case BVC_Z:
if (!getflag(V)) {
cpu->pc[thread] = address.u64;
}
break;
case DIV:
case DAB:
case DIV_AB:
case DIV_Z:
divd(cpu, value.u64, opcode, thread);
break;
case CLV:
setflag(0, V);
break;
case CAB:
value.u64 = cpu->b[thread];
case CPB:
case CMP:
case CPY:
case CPX:
case CPY_AB:
case CPX_AB:
case CMP_AB:
case CPB_AB:
case CPY_Z:
case CPX_Z:
case CMP_Z:
case CPB_Z:
case CPY_IN:
case CPX_IN:
case CMP_IN:
case CPB_IN:
case CMP_IX:
case CPB_IX:
case CMP_IY:
case CPB_IY:
cmp(cpu, value.u64, opcode, thread);
break;
case ENT:
break;
case INC:
case INB:
case INY:
case INX:
incr(cpu, opcode, thread);
break;
case DEC:
case DEB:
case DEY:
case DEX:
decr(cpu, opcode, thread);
break;
case JSR_IN:
case JSR:
case JSR_Z:
value.u64 = cpu->pc[thread];
addr[(cpu->stk_st[thread] << 16)+cpu->sp[thread]-0] = value.u8[7];
addr[(cpu->stk_st[thread] << 16)+cpu->sp[thread]-1] = value.u8[6];
addr[(cpu->stk_st[thread] << 16)+cpu->sp[thread]-2] = value.u8[5];
addr[(cpu->stk_st[thread] << 16)+cpu->sp[thread]-3] = value.u8[4];
addr[(cpu->stk_st[thread] << 16)+cpu->sp[thread]-4] = value.u8[3];
addr[(cpu->stk_st[thread] << 16)+cpu->sp[thread]-5] = value.u8[2];
addr[(cpu->stk_st[thread] << 16)+cpu->sp[thread]-6] = value.u8[1];
addr[(cpu->stk_st[thread] << 16)+cpu->sp[thread]-7] = value.u8[0];
cpu->sp[thread] -= 8;
cpu->pc[thread] = address.u64;
break;
case INC_AB:
case INC_Z:
incm(cpu, address.u64, thread);
step = addr[STEP_ADDR] || cpu->pc[thread] == CTRL_ADDR;
break;
case NOP:
break;
case RTI:
cpu->sp[thread] += 1;
cpu->ps.u8[thread] = addr[(cpu->stk_st[thread] << 16)+(cpu->sp[thread])];
case RTS:
cpu->sp[thread] += 8;
value.u8[0] = addr[(cpu->stk_st[thread] << 16)+(cpu->sp[thread]-7)];
value.u8[1] = addr[(cpu->stk_st[thread] << 16)+(cpu->sp[thread]-6)];
value.u8[2] = addr[(cpu->stk_st[thread] << 16)+(cpu->sp[thread]-5)];
value.u8[3] = addr[(cpu->stk_st[thread] << 16)+(cpu->sp[thread]-4)];
value.u8[4] = addr[(cpu->stk_st[thread] << 16)+(cpu->sp[thread]-3)];
value.u8[5] = addr[(cpu->stk_st[thread] << 16)+(cpu->sp[thread]-2)];
value.u8[6] = addr[(cpu->stk_st[thread] << 16)+(cpu->sp[thread]-1)];
value.u8[7] = addr[(cpu->stk_st[thread] << 16)+(cpu->sp[thread] )];
cpu->pc[thread] = value.u64;
break;
case DEC_AB:
case DEC_Z:
decm(cpu, address.u64, thread);
step = addr[STEP_ADDR] || cpu->pc[thread] == CTRL_ADDR;
break;
case BRK:
case WAI:
if (opcode == WAI) {
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);
}
value.u64 = cpu->pc[thread];
addr[(cpu->stk_st[thread] << 16)+cpu->sp[thread]-0] = value.u8[7];
addr[(cpu->stk_st[thread] << 16)+cpu->sp[thread]-1] = value.u8[6];
addr[(cpu->stk_st[thread] << 16)+cpu->sp[thread]-2] = value.u8[5];
addr[(cpu->stk_st[thread] << 16)+cpu->sp[thread]-3] = value.u8[4];
addr[(cpu->stk_st[thread] << 16)+cpu->sp[thread]-4] = value.u8[3];
addr[(cpu->stk_st[thread] << 16)+cpu->sp[thread]-5] = value.u8[2];
addr[(cpu->stk_st[thread] << 16)+cpu->sp[thread]-6] = value.u8[1];
addr[(cpu->stk_st[thread] << 16)+cpu->sp[thread]-7] = value.u8[0];
addr[(cpu->stk_st[thread] << 16)+cpu->sp[thread]-8] = cpu->ps.u8[thread];
cpu->sp[thread] -= 9;
setflag(1, I);
if (opcode == BRK) {
value.u8[0] = addr[0xFFE0];
value.u8[1] = addr[0xFFE1];
value.u8[2] = addr[0xFFE2];
value.u8[3] = addr[0xFFE3];
value.u8[4] = addr[0xFFE4];
value.u8[5] = addr[0xFFE5];
value.u8[6] = addr[0xFFE6];
value.u8[7] = addr[0xFFE7];
} else {
value.u8[0] = addr[0xFFA0];
value.u8[1] = addr[0xFFA1];
value.u8[2] = addr[0xFFA2];
value.u8[3] = addr[0xFFA3];
value.u8[4] = addr[0xFFA4];
value.u8[5] = addr[0xFFA5];
value.u8[6] = addr[0xFFA6];
value.u8[7] = addr[0xFFA7];
kbd_rdy &= (uint8_t)~(1 << thread);
}
cpu->pc[thread] = value.u64;
default:
break;
}
#if !IO
ins++;
#endif
#if !bench
if (step) {
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);
#if debug
wrefresh(scr);
#endif
}
#endif
#if debug && !bench
#if keypoll
pthread_mutex_lock(&mutex);
#endif
wmove(scr, (6*thread)+1, 0);
wprintw(scr, "Instructions executed: %"PRIu64, ins);
#if getclk
wprintw(scr, ", Clock cycles: %"PRIu64, iclk);
#endif
if (!step && !subdbg) {
wrefresh(scr);
}
#if keypoll
pthread_mutex_unlock(&mutex);
#endif
#elif bench
if (ins >= BENCH_INST) {
pthread_mutex_lock(&main_mutex);
threads_done++;
inst[thread] = ins;
#if getclk
clk[thread] = iclk;
#endif
pthread_cond_signal(&main_cond);
pthread_mutex_unlock(&main_mutex);
gettimeofday(&en[thread], 0);
break;
}
#endif
}
return NULL;
}
int main(int argc, char **argv) {
struct suxthr thr[THREADS];
char *tmp = malloc(2048);
addr = malloc(0x04000000);
#if bench
inss = 0;
#endif
int v = 0;
if (argc != 2) {
if (asmmon("stdin") == 2) {
return 0;
}
} else {
#if debug
subdbg = !strcmp(argv[1], "programs/subeditor.s");
#endif
if (asmmon(argv[1]) == 2) {
return 0;
}
}
sprintf(tmp, "\033[2J\033[H");
fwrite(tmp, sizeof(char), strlen(tmp), stdout);
fflush(stdout);
if(!scr) {
scr = initscr();
}
nodelay(stdscr, 0);
crmode();
noecho();
nl();
curs_set(1);
werase(scr);
scrollok(scr, 1);
start_color();
use_default_colors();
init_pair(1, COLOR_WHITE, -1);
attron(COLOR_PAIR(1) | A_BOLD);
wmove(scr, 0, 0);
wrefresh(scr);
pthread_t therads[THREADS];
int result;
uint16_t vec = 0xFFC0;
uint8_t offset;
for (int i = 0; i < THREADS; i++) {
thr[i].sx.sp[i] = 0xFFFF;
thr[i].sx.stk_st[i] = i+1;
offset = (i) ? ((i-1) << 3) : 0;
vec = (i) ? 0xFF50 : 0xFFC0;
thr[i].sx.a[i] = 0;
thr[i].sx.b[i] = 0;
thr[i].sx.x[i] = 0;
thr[i].sx.y[i] = 0;
thr[i].sx.pc[i] = (uint64_t)addr[vec+0+offset]
| (uint64_t)addr[vec+1+offset] << 8
| (uint64_t)addr[vec+2+offset] << 16
| (uint64_t)addr[vec+3+offset] << 24
| (uint64_t)addr[vec+4+offset] << 32
| (uint64_t)addr[vec+5+offset] << 40
| (uint64_t)addr[vec+6+offset] << 48
| (uint64_t)addr[vec+7+offset] << 56;
thr[i].th = i;
#if !IO
inst[i] = 0;
#endif
result = pthread_create(&therads[i], NULL, run, &thr[i]);
assert(!result);
}
int c = 0;
uint8_t step_key = 0;
uint8_t end = 0;
werase(scr);
while (threads_done < THREADS && !end) {
#if !bench
int x, y;
if ((step_key && step && !kbd_rdy) || !step || kbd_rdy) {
if ((c != EOF && c !=-1)) {
#if !keypoll
pthread_mutex_lock(&mutex);
pthread_cond_signal(&cond);
pthread_mutex_unlock(&mutex);
#endif
pthread_mutex_lock(&main_mutex);
curs_set(0);
pthread_cond_wait(&main_cond, &main_mutex);
pthread_mutex_unlock(&main_mutex);
curs_set(1);
c = 0;
step_key = 0;
addr[CTRL_ADDR] = 0;
wrefresh(scr);
}
}
#if keypoll
pthread_mutex_lock(&mutex);
#endif
c = wgetch(scr);
if (c == 19) {
if (kbd_rdy) {
c = wgetch(scr);
}
step = 1;
} else if (c == 0x11) {
end = 1;
continue;
}
if (kbd_rdy) {
switch (c) {
case ERR:
addr[CTRL_ADDR] = 0;
break;
default:
if (kbd_rdy && c < 0x100) {
addr[RX_ADDR] = (uint8_t)c;
addr[CTRL_ADDR] = 1;
#if debug && !bench
wmove(scr, getmaxy(scr)-1, 0);
wclrtoeol(scr);
wprintw(scr, "c: %i", c);
wmove(scr, y, x);
#endif
}
break;
}
} else {
if (step) {
step = !(c == 18);
step_key = (c == 19);
}
}
addr[STEP_ADDR] = step;
#if keypoll
pthread_mutex_unlock(&mutex);
#endif
#else
pthread_mutex_lock(&main_mutex);
pthread_cond_wait(&main_cond, &main_mutex);
pthread_mutex_unlock(&main_mutex);
#endif
}
endwin();
#if bench
if (threads_done == THREADS) {
double tm_sec, tm_usec, tm[THREADS], ttm;
#if getclk
double clkspd;
double mhz;
#endif
double ips[THREADS];
double ipst;
for (int i = 0; i < THREADS; i++) {
tm_sec = (en[i].tv_sec - str[i].tv_sec);
tm_usec = (en[i].tv_usec-str[i].tv_usec);
tm[i] = (tm_sec*1000000)+(tm_usec);
ips[i] = inst[i]/tm[i];
if (i) {
inss += inst[i];
ttm += tm[i];
ipst += ips[i];
#if getclk
tclk += clk[i];
#endif
} else {
inss = inst[i];
ttm = tm[i];
ipst = ips[i];
#if getclk
tclk = clk[i];
#endif
}
#if getclk
clkspd = (tm[i]/1000000)*1000000/clk[i];
mhz = 1000000.0/clkspd/1000000;
#endif
sprintf(tmp, "Instructions executed for thread %i: %"PRIu64", Instructions per Second for thread %i in MIPS: %f, tm: %f\n", i, inst[i], i, ips[i], tm[i]/1000000);
fwrite(tmp, sizeof(char), strlen(tmp), stdout);
}
sprintf(tmp, "Total Instructions executed: %"PRIu64", Total Instructions per Second in MIPS: %f", inss, ipst);
fwrite(tmp, sizeof(char), strlen(tmp), stdout);
#if getclk
clkspd = (ttm/1000000)*1000000/tclk;
mhz = 1000000.0/clkspd/1000000;
sprintf(tmp, ", Clock cycles: %"PRIu64", Clock Speed in MHz: %f", tclk, mhz);
fwrite(tmp, sizeof(char), strlen(tmp), stdout);
#endif
sprintf(tmp, ", tm: %f\n", ttm/1000000);
fwrite(tmp, sizeof(char), strlen(tmp), stdout);
fflush(stdout);
free(tmp);
}
#endif
free(addr);
return 0;
}