#include "opcode.h"
#include <assert.h>
#include <ctype.h>
#include <string.h>
#include <pthread.h>
#define bench 0
#define debug 0
#define IO 1
#define getclk 0
#define keypoll 0
#if bench
#include <sys/time.h>
#else
#include <curses.h>
#endif
#define THREADS 1
#define BENCH_INST 100000000 << (THREADS-1)
#define CTRL_ADDR 0xC000
#define TX_ADDR 0xC001
#define RX_ADDR 0xC002
#define STEP_ADDR 0xC010
#define CURSES_BACKSPACE 0x7F
#define setflag(flag, bit) ((flag)) ? (cpu->ps |= (bit << (thread << 3))) : (cpu->ps &= ~(bit << (thread << 3)))
#define getflag(bit) (cpu->ps & (bit << (thread << 3)))
#if getclk
uint64_t clk[THREADS];
uint64_t tclk;
#endif
const uint16_t tv = 0xFF50;
uint64_t inst[THREADS];
uint64_t inss;
uint8_t threads_done = 0;
uint8_t kbd_rdy = 0;
uint8_t step = 0;
#if !bench
WINDOW *scr;
#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;
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;
uint64_t address = 0;
uint8_t prefix = 0;
uint8_t opcode = 0;
uint64_t sum = 0;
uint64_t value = 0;
uint64_t reg = 0;
#if getclk
uint64_t iclk = 0;
#endif
uint64_t ins = 0;
uint8_t sign = 0;
uint8_t tmp;
uint8_t tmp2;
#if !bench
uint8_t lines = (6*thread)+2;
uint8_t bcd[4];
uint8_t idx = 3, iscol = 0;
int x = 0, y = 0;
uint8_t esc = 0;
#endif
#if bench
gettimeofday(&str[thread], 0);
#endif
#if debug && !bench
uint8_t scr_row = 0xFF, scr_col = 0xFF;
uint8_t updt = 0;
uint64_t tmpaddr = 0;
addr[STEP_ADDR] = 1;
step = 1;
#if keypoll
pthread_mutex_lock(&mutex);
#endif
werase(scr);
#if keypoll
pthread_mutex_unlock(&mutex);
#endif
#endif
for (;;) {
address = 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
wmove(scr, lines, 0);
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: $%02"PRIX64
", inst: "
, cpu->sp[thread]
, cpu->ps);
#if keypoll
pthread_mutex_unlock(&mutex);
#endif
#endif
address = cpu->pc[thread];
++cpu->pc[thread];
#if getclk
++iclk;
#endif
switch (optype[opcode]) {
case IMPL:
break;
case IMM:
switch (opcode) {
case TXS:
break;
case PHB:
case PHP:
case PHA:
case PHY:
case PHX:
case PLB:
case PLP:
case PLA:
case PLY:
case PLX:
case STT:
case LSL:
case LSR:
case ROL:
case ROR:
case ASR:
case ENT:
address = cpu->pc[thread];
++cpu->pc[thread];
break;
default:
address = cpu->pc[thread];
cpu->pc[thread]+=(1 << (prefix >> 4));
break;
}
break;
case ZM:
case ZMX:
case ZMY:
case IND:
case INDX:
case INDY:
tmp = 0;
address = addr[cpu->pc[thread]];
switch ((prefix & 0x0C) >> 2) {
case 2:
address |= (uint64_t)addr[cpu->pc[thread]+5] << 40;++tmp;
address |= (uint64_t)addr[cpu->pc[thread]+4] << 32;++tmp;
case 3:
address |= (uint64_t)addr[cpu->pc[thread]+3] << 24;++tmp;
case 1:
address |= (uint64_t)addr[cpu->pc[thread]+2] << 16;++tmp;
address |= (uint64_t)addr[cpu->pc[thread]+1] << 8;++tmp;
case 0:
++tmp;
}
cpu->pc[thread]+=tmp;
#if debug && !bench
tmpaddr = address;
#endif
#if getclk
iclk++;
#endif
reg = 0;
switch (optype[opcode]) {
case ZMX:
address += cpu->x[thread];
#if getclk
iclk++;
#endif
break;
case ZMY:
address += cpu->y[thread];
#if getclk
iclk++;
#endif
break;
case INDX:
address += cpu->x[thread];
#if getclk
iclk++;
#endif
case INDY:
if (optype[opcode] == INDX) {
reg = 0;
} else {
reg = cpu->y[thread];
#if getclk
iclk++;
#endif
}
case IND:
value = (uint64_t)addr[address];
value += (uint64_t)addr[address+1] << 8;
value += (uint64_t)addr[address+2] << 16;
value += (uint64_t)addr[address+3] << 24;
value += (uint64_t)addr[address+4] << 32;
value += (uint64_t)addr[address+5] << 40;
value += (uint64_t)addr[address+6] << 48;
value += (uint64_t)addr[address+7] << 56;
#if getclk
iclk++;
#endif
value += reg;
address = value;
value = 0;
reg = 0;
break;
}
break;
case ABS:
tmp = 0;
address = addr[cpu->pc[thread]];++tmp;
switch ((prefix & 0x0C) >> 2) {
case 3:
address |= (uint64_t)addr[cpu->pc[thread]+7] << 56;++tmp;
case 2:
address |= (uint64_t)addr[cpu->pc[thread]+6] << 48;++tmp;
address |= (uint64_t)addr[cpu->pc[thread]+5] << 40;++tmp;
#if getclk
iclk++;
#endif
case 1:
address |= (uint64_t)addr[cpu->pc[thread]+4] << 32;++tmp;
address |= (uint64_t)addr[cpu->pc[thread]+3] << 24;++tmp;
address |= (uint64_t)addr[cpu->pc[thread]+2] << 16;++tmp;
case 0:
address |= (uint64_t)addr[cpu->pc[thread]+1] << 8;++tmp;
}
cpu->pc[thread]+=tmp;
break;
}
value = addr[address];
switch (1 << (prefix >> 4)) {
case 8:
value |= (uint64_t)addr[address+7] << 56;
value |= (uint64_t)addr[address+6] << 48;
value |= (uint64_t)addr[address+5] << 40;
value |= (uint64_t)addr[address+4] << 32;
case 4:
value |= (uint64_t)addr[address+3] << 24;
value |= (uint64_t)addr[address+2] << 16;
case 2:
value |= (uint64_t)addr[address+1] << 8;
}
#if debug && !bench
#if keypoll
pthread_mutex_lock(&mutex);
#endif
char postfix[3];
char op[4];
op[0] = opname[opcode][0];
op[1] = opname[opcode][1];
op[2] = opname[opcode][2];
op[3] = '\0';
switch(1 << (prefix >> 4)) {
case 1: postfix[0] = 0; postfix[1] = 0; postfix[2] = 0; break;
case 2: postfix[0] = '.'; postfix[1] = 'W'; postfix[2] = 0; break;
case 4: postfix[0] = '.'; postfix[1] = 'D'; postfix[2] = 0; break;
case 8: postfix[0] = '.'; postfix[1] = 'Q'; postfix[2] = 0; break;
}
switch (optype[opcode]) {
case IMPL: wprintw(scr, "%s\r" , opname[opcode]); break;
case IMM:
switch(1 << (prefix >> 4)) {
case 1: wprintw(scr, "%s #$%02X\r" , op, value); break;
case 2: wprintw(scr, "%s%s #$%04X\r" , op, postfix, value); break;
case 4: wprintw(scr, "%s%s #$%08X\r" , op, postfix, value); break;
case 8: wprintw(scr, "%s%s #$%016"PRIX64"\r" , op, postfix, value); break;
}
break;
case ZM:
case ZMX:
case ZMY:
switch (optype[opcode]) {
case ZMX: tmpaddr = address - cpu->x[thread]; break;
case ZMY: tmpaddr = address - cpu->y[thread]; break;
}
switch ((prefix & 0x0C) >> 2) {
case 3: wprintw(scr, "%s%s $%08X%s\r" , op, postfix, tmpaddr, (optype[opcode] == ZM) ? "" : ((optype[opcode] == ZMX) ? ", x" : ", y")); break;
case 2: wprintw(scr, "%s%s $%014"PRIX64"%s\r" , op, postfix, tmpaddr, (optype[opcode] == ZM) ? "" : ((optype[opcode] == ZMX) ? ", x" : ", y")); break;
case 1: wprintw(scr, "%s%s $%06X%s\r" , op, postfix, tmpaddr, (optype[opcode] == ZM) ? "" : ((optype[opcode] == ZMX) ? ", x" : ", y")); break;
case 0: wprintw(scr, "%s%s $%02X%s\r" , op, postfix, tmpaddr, (optype[opcode] == ZM) ? "" : ((optype[opcode] == ZMX) ? ", x" : ", y")); break;
}
break;
case IND:
case INDX:
case INDY:
switch ((prefix & 0x0C) >> 2) {
case 3: wprintw(scr, "%s%s ($%08X%s\r" , op, postfix, tmpaddr, (optype[opcode] == IND) ? ")" : ((optype[opcode] == INDX) ? ", x)" : "), y")); break;
case 2: wprintw(scr, "%s%s ($%012"PRIX64"%s\r" , op, postfix, tmpaddr, (optype[opcode] == IND) ? ")" : ((optype[opcode] == INDX) ? ", x)" : "), y")); break;
case 1: wprintw(scr, "%s%s ($%06X%s\r" , op, postfix, tmpaddr, (optype[opcode] == IND) ? ")" : ((optype[opcode] == INDX) ? ", x)" : "), y")); break;
case 0: wprintw(scr, "%s%s ($%02X%s\r" , op, postfix, tmpaddr, (optype[opcode] == IND) ? ")" : ((optype[opcode] == INDX) ? ", x)" : "), y")); break;
}
break;
case ABS:
tmpaddr = address;
switch ((prefix & 0x0C) >> 2) {
case 3: wprintw(scr, "%s%s $%016"PRIX64"\r" , op, postfix, tmpaddr); break;
case 2: wprintw(scr, "%s%s $%014"PRIX64"\r" , op, postfix, tmpaddr); break;
case 1: wprintw(scr, "%s%s $%010"PRIX64"\r" , op, postfix, tmpaddr); break;
case 0: wprintw(scr, "%s%s $%04" PRIX64"\r" , op, postfix, tmpaddr); break;
}
break;
}
if (updt) {
mvwprintw(scr, 27, 0, "TX_ADDR: $%02X, RX_ADDR: $%02X\r", addr[TX_ADDR], addr[RX_ADDR]);
mvwprintw(scr, 28, 0, "scr_ptr3: $%04X", (addr[0x5C] << 8) | addr[0x5B]);
mvwprintw(scr, 29, 0, "address: $%04"PRIX64", scr_row: %02u, scr_col: %02u, scr_str: %02u, scr_end: %02u\r", address, addr[0], addr[1], addr[0x28], addr[0x29]);
mvwprintw(scr, 32, 0, "bitabl: %02X %02X %02X %02X %02X %02X %02X %02X "
"%02x %02x %02x %02x %02x %02x %02x %02x\r"
, addr[0x18], addr[0x19], addr[0x1A], addr[0x1B], addr[0x1C], addr[0x1D], addr[0x1E], addr[0x1F]
, addr[0x20], addr[0x21], addr[0x22], addr[0x23], addr[0x24], addr[0x25], addr[0x26], addr[0x27]);
}
uint8_t ln = 33;
uint16_t line_idx = 0;
uint16_t tmpad = 0x2000;
int row, col;
uint8_t iscursor = 0;
mvwprintw(scr, ln++, 0, "buffer:\r");
if (updt) {
scr_row = addr[0];
scr_col = addr[1];
wmove(scr, ln++, 0);
for (uint8_t i = 0; i < 10; i++) {
line_idx = (i << 6) + (i << 4);
for (uint8_t j = 0; j < 0x50; j++) {
wprintw(scr, "%02X", addr[tmpad+j+line_idx]);
if ((addr[0]+addr[0x28]) == i && addr[1] == j) {
iscursor=1;
getyx(scr,row, col);
wmove(scr, ln++, 0);
wclrtoeol(scr);
wmove(scr, row+1, col-2);
wprintw(scr, "/\\\r");
wmove(scr, row, col);
}
}
wprintw(scr, ", i: %02X\r", i);
if (!iscursor) {
wmove(scr, ln, 0);
wclrtoeol(scr);
}
iscursor = 0;
wmove(scr, ln++, 0);
}
updt = 0;
}
#if keypoll
pthread_mutex_unlock(&mutex);
#endif
lines+=1;
#endif
switch(opcode) {
case CPS:
cpu->ps = 0;
break;
case AAB:
value = cpu->b[thread];
case ADC:
case ADC_AB:
case ADC_Z:
sum = cpu->a[thread]+value+getflag(C);
cpu->a[thread] = sum;
setflag(sum == 0, Z);
setflag((sum >> 63), N);
setflag(((cpu->a[thread]^value) >> 63) && ((cpu->a[thread]^sum) >> 63), V);
setflag((sum < value), C);
break;
case PHB:
case PHP:
case PHA:
case PHY:
case PHX:
tmp = (value <= 7) ? value : 7;
switch (opcode) {
case PHA: reg = cpu->a[thread]; break;
case PHB: reg = cpu->b[thread]; break;
case PHX: reg = cpu->x[thread]; break;
case PHY: reg = cpu->y[thread]; break;
case PHP: reg = cpu->ps; break;
}
switch (tmp) {
case 7: addr[(cpu->stk_st[thread] << 16)+cpu->sp[thread]] = reg >> (7<<3);cpu->sp[thread]--;
case 6: addr[(cpu->stk_st[thread] << 16)+cpu->sp[thread]] = reg >> (6<<3);cpu->sp[thread]--;
case 5: addr[(cpu->stk_st[thread] << 16)+cpu->sp[thread]] = reg >> (5<<3);cpu->sp[thread]--;
case 4: addr[(cpu->stk_st[thread] << 16)+cpu->sp[thread]] = reg >> (4<<3);cpu->sp[thread]--;
case 3: addr[(cpu->stk_st[thread] << 16)+cpu->sp[thread]] = reg >> (3<<3);cpu->sp[thread]--;
case 2: addr[(cpu->stk_st[thread] << 16)+cpu->sp[thread]] = reg >> (2<<3);cpu->sp[thread]--;
case 1: addr[(cpu->stk_st[thread] << 16)+cpu->sp[thread]] = reg >> (1<<3);cpu->sp[thread]--;
case 0: addr[(cpu->stk_st[thread] << 16)+cpu->sp[thread]] = reg & (0xFF);cpu->sp[thread]--;
}
break;
case TAY:
case TAX:
case TYX:
case TYA:
case TXA:
case TXY:
case TAB:
case TSX:
case TBA:
case TXS:
switch (opcode) {
case TBA: cpu->a[thread] = cpu->b[thread]; reg = cpu->a[thread]; break;
case TXA: cpu->a[thread] = cpu->x[thread]; reg = cpu->a[thread]; break;
case TYA: cpu->a[thread] = cpu->y[thread]; reg = cpu->a[thread]; break;
case TAB: cpu->b[thread] = cpu->a[thread]; reg = cpu->b[thread]; break;
case TAY: cpu->y[thread] = cpu->a[thread]; reg = cpu->y[thread]; break;
case TXY: cpu->y[thread] = cpu->x[thread]; reg = cpu->y[thread]; break;
case TAX: cpu->x[thread] = cpu->a[thread]; reg = cpu->x[thread]; break;
case TYX: cpu->x[thread] = cpu->y[thread]; reg = cpu->x[thread]; break;
case TSX: cpu->x[thread] = cpu->sp[thread] & 0xFFFF; cpu->x[thread] = cpu->stk_st[thread] << 16; break;
case TXS: cpu->sp[thread] = cpu->x[thread];
if (prefix == 0x13 && (value == thread+1 || value > 8)) {
cpu->stk_st[thread] = value & 0xFF;
cpu->stk_st[thread] += value << 16;
cpu->pc[thread]+=2;
}
break;
}
setflag(reg == 0, Z);
setflag(reg >> 63, N);
break;
case JMP:
case JMP_Z:
case JMP_IN:
cpu->pc[thread] = address;
break;
case SAB:
value = cpu->b[thread];
case SBC:
case SBC_AB:
case SBC_Z:
sum = cpu->a[thread]-value-!getflag(C);
setflag(sum == 0, Z);
setflag(sum >> 63, N);
setflag(((cpu->a[thread]^value) >> 63) && ((cpu->a[thread]^sum) >> 63), V);
setflag((sum > value), C);
cpu->a[thread] = sum;
break;
case PLB:
case PLP:
case PLA:
case PLY:
case PLX:
tmp = (value <= 7) ? value : 7;
reg = 0;
tmp2 = 0;
cpu->sp[thread]++;reg = addr[(cpu->stk_st[thread] << 16)+cpu->sp[thread]] & 0xFF;
switch (tmp) {
case 7: cpu->sp[thread]++;tmp2++;reg += (uint64_t)addr[(cpu->stk_st[thread] << 16)+cpu->sp[thread]] << (tmp2<<3);
case 6: cpu->sp[thread]++;tmp2++;reg += (uint64_t)addr[(cpu->stk_st[thread] << 16)+cpu->sp[thread]] << (tmp2<<3);
case 5: cpu->sp[thread]++;tmp2++;reg += (uint64_t)addr[(cpu->stk_st[thread] << 16)+cpu->sp[thread]] << (tmp2<<3);
case 4: cpu->sp[thread]++;tmp2++;reg += (uint64_t)addr[(cpu->stk_st[thread] << 16)+cpu->sp[thread]] << (tmp2<<3);
case 3: cpu->sp[thread]++;tmp2++;reg += (uint64_t)addr[(cpu->stk_st[thread] << 16)+cpu->sp[thread]] << (tmp2<<3);
case 2: cpu->sp[thread]++;tmp2++;reg += (uint64_t)addr[(cpu->stk_st[thread] << 16)+cpu->sp[thread]] << (tmp2<<3);
case 1: cpu->sp[thread]++;tmp2++;reg += (uint64_t)addr[(cpu->stk_st[thread] << 16)+cpu->sp[thread]] << (tmp2<<3);
}
switch (opcode) {
case PLA: cpu->a[thread] = reg; break;
case PLB: cpu->b[thread] = reg; break;
case PLX: cpu->x[thread] = reg; break;
case PLY: cpu->y[thread] = reg; break;
case PLP: cpu->ps = reg; break;
}
break;
case ABA:
value = cpu->b[thread];
case AND:
case AND_AB:
case AND_Z:
cpu->a[thread] &= value;
setflag(cpu->a[thread] == 0, Z);
setflag(cpu->a[thread] >> 63, N);
break;
case STT:
cpu->crt |= value;
for (uint8_t i = 0; i < 7; i++) {
if ((value >> i) & 1) {
address = (uint64_t)addr[tv+(i<<3)]
| (uint64_t)addr[tv+1+(i<<3)] << 8
| (uint64_t)addr[tv+2+(i<<3)] << 16
| (uint64_t)addr[tv+3+(i<<3)] << 24
| (uint64_t)addr[tv+4+(i<<3)] << 32
| (uint64_t)addr[tv+5+(i<<3)] << 40
| (uint64_t)addr[tv+6+(i<<3)] << 48
| (uint64_t)addr[tv+7+(i<<3)] << 56;
cpu->pc[i+1] = address;
}
}
break;
case BPO:
case BPO_Z:
if (!getflag(N)) {
cpu->pc[thread] = address;
}
break;
case OAB:
value = cpu->b[thread];
case ORA:
case ORA_AB:
case ORA_Z:
cpu->a[thread] |= value;
setflag(cpu->a[thread] == 0, Z);
setflag(cpu->a[thread] >> 63, N);
break;
case SEI:
setflag(1, I);
break;
case BNG:
case BNG_Z:
if (getflag(N)) {
cpu->pc[thread] = address;
}
break;
case XAB:
value = cpu->b[thread];
case XOR:
case XOR_AB:
case XOR_Z:
cpu->a[thread] ^= value;
setflag(cpu->a[thread] == 0, Z);
setflag(cpu->a[thread] >> 63, N);
break;
case CLI:
setflag(0, I);
break;
case BCS:
case BCS_Z:
if (getflag(C)) {
cpu->pc[thread] = address;
}
break;
case LLB:
value = cpu->b[thread];
case LSL:
case LSL_AB:
case LSL_Z:
sum = (value < 64) ? cpu->a[thread] << value : 0;
setflag(sum == 0, Z);
setflag(sum >> 63, N);
setflag(cpu->a[thread] >> (64-value), C);
cpu->a[thread] = sum;
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:
switch (opcode) {
case STB:
case STB_Z:
case STB_ZX:
case STB_ZY:
case STB_IN:
case STB_IX:
case STB_IY:
value = cpu->b[thread];
break;
case STA:
case STA_Z:
case STA_ZX:
case STA_ZY:
case STA_IN:
case STA_IX:
case STA_IY:
value = cpu->a[thread];
break;
case STY:
case STY_Z:
case STY_ZX:
case STY_IN:
value = cpu->y[thread];
break;
case STX:
case STX_Z:
case STX_ZY:
case STX_IN:
value = cpu->x[thread];
break;
}
addr[address] = value & 0xFF;
#if (IO || debug) && !branch
if (address == TX_ADDR) {
#if keypoll
pthread_mutex_lock(&mutex);
#endif
if (esc) {
switch(addr[TX_ADDR]) {
case 'A':
if (y > 0)
y--;
#if !debug
wmove(scr, y, x);
#endif
esc = 0;
break;
case 'B':
if (y < getmaxy(scr))
y++;
#if !debug
wmove(scr, y, x);
#endif
esc = 0;
break;
case 'C':
if (x < getmaxx(scr))
x++;
#if !debug
wmove(scr, y, x);
#endif
esc = 0;
break;
case 'D':
if (x > 0)
x--;
#if !debug
wmove(scr, y, x);
#endif
esc = 0;
break;
case 'H':
if (!bcd[2] && !bcd[3]) {
y = 0;
} else {
y = ((bcd[3]*10) + bcd[2]);
}
if (!bcd[0] && !bcd[1]) {
x = 0;
} else {
x = ((bcd[1]*10) + bcd[0]);
}
#if !debug
wmove(scr, y, x);
#else
updt = 1;
mvwprintw(scr, 30, 0, "x: %i, y: %i ", x, y);
mvwprintw(scr, 31, 0, "bcd[3-2]: {%u, %u}, bcd[1-0]: {%u, %u}", bcd[3], bcd[2], bcd[1], bcd[0]);
#endif
idx = 3;
bcd[0] = 0;
bcd[1] = 0;
bcd[2] = 0;
bcd[3] = 0;
esc = 0;
break;
case 'S':
#if !debug
wscrl(scr, -1);
#else
updt = (!addr[0x16]);
#endif
esc = 0;
break;
case 'T':
#if !debug
wscrl(scr, 1);
#else
updt = (!addr[0x16]);
#endif
esc = 0;
break;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
bcd[idx--] = (addr[address] - '0');
break;
default:
iscol = (addr[address] == ';');
break;
}
} else {
switch (addr[TX_ADDR]) {
case 0xC:
x=0,y=0;
#if !debug
wclear(scr);
wmove(scr, y, x);
#endif
break;
case CURSES_BACKSPACE:
case '\b':
if (x > 0) {
x--;
#if !debug
wmove(scr, y, x);
#endif
}
#if !debug
wdelch(scr);
#else
updt = 1;
#endif
break;
case '\033':
esc = 1;
break;
case '\n':
#if !debug
wmove(scr, y, x);
waddch(scr, addr[address]);
#else
updt = (!addr[0x16]);
#endif
x = 0;
y+=1;
break;
default:
#if !debug
wmove(scr, y, x);
waddch(scr, addr[address]);
#else
updt = (!addr[0x16]);
#endif
x+=1;
break;
}
}
#if keypoll
pthread_mutex_unlock(&mutex);
#endif
}
#endif
switch (1 << (prefix >> 4)) {
case 8:
addr[address+7] = value >> 56;
addr[address+6] = value >> 48;
addr[address+5] = value >> 40;
addr[address+4] = value >> 32;
case 4:
addr[address+3] = value >> 24;
addr[address+2] = value >> 16;
case 2:
addr[address+1] = value >> 8;
}
step = addr[STEP_ADDR] || cpu->pc[thread] == CTRL_ADDR;
break;
case BCC:
case BCC_Z:
if (!getflag(C)) {
cpu->pc[thread] = address;
}
break;
case LRB:
value = cpu->b[thread];
case LSR:
case LSR_AB:
case LSR_Z:
sum = (value < 64) ? cpu->a[thread] >> value : 0;
setflag(sum == 0, Z);
setflag(sum >> 63, N);
setflag(cpu->a[thread] & 1, C);
cpu->a[thread] = sum;
break;
case ARB:
value = cpu->b[thread];
case ASR:
case ASR_AB:
case ASR_Z:
sign = cpu->a[thread] >> 63;
sum = (value < 64) ? (cpu->a[thread] >> value) | ((uint64_t)sign << 63) : 0;
setflag(sum == 0, Z);
setflag(sum >> 63, N);
setflag(cpu->a[thread] & 1, C);
cpu->a[thread] = sum;
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:
if (address == CTRL_ADDR) {
kbd_rdy = 1;
pthread_mutex_lock(&main_mutex);
pthread_cond_signal(&main_cond);
pthread_mutex_unlock(&main_mutex);
#if !keypoll
pthread_mutex_lock(&mutex);
pthread_cond_wait(&cond, &mutex);
pthread_mutex_unlock(&mutex);
#endif
kbd_rdy = 0;
}
value = addr[address];
switch (1 << (prefix >> 4)) {
case 8:
value |= (uint64_t)addr[address+7] << 56;
value |= (uint64_t)addr[address+6] << 48;
value |= (uint64_t)addr[address+5] << 40;
value |= (uint64_t)addr[address+4] << 32;
case 4:
value |= (uint64_t)addr[address+3] << 24;
value |= (uint64_t)addr[address+2] << 16;
case 2:
value |= (uint64_t)addr[address+1] << 8;
}
switch (opcode) {
case LDB:
case LDB_AB:
case LDB_Z:
case LDB_ZX:
case LDB_ZY:
case LDB_IN:
case LDB_IX:
case LDB_IY:
cpu->b[thread] = value;
break;
case LDA:
case LDA_AB:
case LDA_Z:
case LDA_ZX:
case LDA_ZY:
case LDA_IN:
case LDA_IX:
case LDA_IY:
cpu->a[thread] = value;
break;
case LDY:
case LDY_AB:
case LDY_Z:
case LDY_ZX:
case LDY_IN:
cpu->y[thread] = value;
break;
case LDX:
case LDX_AB:
case LDX_Z:
case LDX_ZY:
case LDX_IN:
cpu->x[thread] = value;
break;
}
setflag(value == 0, Z);
setflag(value >> 63, N);
break;
case BEQ:
case BEQ_Z:
if (getflag(Z)) {
cpu->pc[thread] = address;
}
break;
case RLB:
value = cpu->b[thread];
case ROL:
case ROL_AB:
case ROL_Z:
sum = cpu->a[thread] << value;
sum |= getflag(C);
setflag(sum == 0, Z);
setflag(sum >> 63, N);
setflag(cpu->a[thread] >> (uint64_t)(64-value), C);
cpu->a[thread] = sum;
break;
case BNE:
case BNE_Z:
if (!getflag(Z)) {
cpu->pc[thread] = address;
}
break;
case RRB:
value = cpu->b[thread];
case ROR:
case ROR_AB:
case ROR_Z:
sum = cpu->a[thread] >> value;
sum |= (uint64_t)getflag(C) << (uint64_t)(64-value);
setflag(sum == 0, Z);
setflag(sum >> 63, N);
setflag(cpu->a[thread] & 1, C);
cpu->a[thread] = sum;
break;
case BVS:
case BVS_Z:
if (getflag(V)) {
cpu->pc[thread] = address;
}
break;
case MAB:
value = cpu->b[thread];
case MUL:
case MUL_AB:
case MUL_Z:
sum = cpu->a[thread]*value;
cpu->a[thread] = sum;
setflag(sum == 0, Z);
setflag(sum >> 63, N);
setflag(!((cpu->a[thread]^value) >> 63) && ((cpu->a[thread]^sum) >> 63), V);
break;
case BVC:
case BVC_Z:
if (!getflag(V)) {
cpu->pc[thread] = address;
}
break;
case DIV:
case DAB:
case DIV_AB:
case DIV_Z:
sum = cpu->a[thread]/value;
if (opcode != DAB) {
cpu->b[thread] = cpu->a[thread] % value;
} else {
value = cpu->b[thread];
cpu->x[thread] = cpu->a[thread] % value;
}
cpu->a[thread] = sum;
setflag(sum == 0, Z);
setflag((sum >> 63), N);
break;
case CLV:
setflag(0, V);
break;
case CAB:
value = 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:
switch (opcode) {
case CPB:
case CPB_AB:
case CPB_Z:
case CPB_IN:
case CPB_IX:
case CPB_IY:
reg = cpu->b[thread];
break;
case CMP:
case CAB:
case CMP_AB:
case CMP_Z:
case CMP_IN:
case CMP_IX:
case CMP_IY:
reg = cpu->a[thread];
break;
case CPY:
case CPY_AB:
case CPY_Z:
case CPY_IN:
reg = cpu->y[thread];
break;
case CPX:
case CPX_AB:
case CPX_Z:
case CPX_IN:
reg = cpu->x[thread];
break;
}
sum = reg-value;
setflag(sum >> 63, N);
setflag(((reg^value) >> 63) && ((reg^sum) >> 63), V);
setflag(sum == 0, Z);
setflag(reg >= value, C);
break;
case ENT:
cpu->crt &= ~value;
for (uint8_t i = 0; i < 7; i++)
if ((value >> i) & 1)
cpu->pc[i+1] = cpu->pc[0]+(i+1);
break;
case RTI:
cpu->sp[thread] += 9;
cpu->ps = addr[(cpu->stk_st[thread] << 16)+(cpu->sp[thread]-8)] << (thread << 3);
cpu->pc[thread] = (uint64_t)addr[(cpu->stk_st[thread] << 16)+(cpu->sp[thread]-7)];
cpu->pc[thread] += (uint64_t)addr[(cpu->stk_st[thread] << 16)+(cpu->sp[thread]-6)] << 8;
cpu->pc[thread] += (uint64_t)addr[(cpu->stk_st[thread] << 16)+(cpu->sp[thread]-5)] << 16;
cpu->pc[thread] += (uint64_t)addr[(cpu->stk_st[thread] << 16)+(cpu->sp[thread]-4)] << 24;
cpu->pc[thread] += (uint64_t)addr[(cpu->stk_st[thread] << 16)+(cpu->sp[thread]-3)] << 32;
cpu->pc[thread] += (uint64_t)addr[(cpu->stk_st[thread] << 16)+(cpu->sp[thread]-2)] << 40;
cpu->pc[thread] += (uint64_t)addr[(cpu->stk_st[thread] << 16)+(cpu->sp[thread]-1)] << 48;
cpu->pc[thread] += (uint64_t)addr[(cpu->stk_st[thread] << 16)+cpu->sp[thread]] << 56;
break;
case INC:
case INB:
case INY:
case INX:
switch (opcode) {
case INC: cpu->a[thread]+=1; reg = cpu->a[thread]; break;
case INB: cpu->b[thread]+=1; reg = cpu->b[thread]; break;
case INY: cpu->y[thread]+=1; reg = cpu->y[thread]; break;
case INX: cpu->x[thread]+=1; reg = cpu->x[thread]; break;
}
setflag(reg == 0, Z);
setflag(reg >> 63, N);
break;
case DEC:
case DEB:
case DEY:
case DEX:
switch (opcode) {
case DEC: cpu->a[thread]-=1; reg = cpu->a[thread]; break;
case DEB: cpu->b[thread]-=1; reg = cpu->b[thread]; break;
case DEY: cpu->y[thread]-=1; reg = cpu->y[thread]; break;
case DEX: cpu->x[thread]-=1; reg = cpu->x[thread]; break;
}
setflag(reg == 0, Z);
setflag(reg >> 63, N);
break;
case JSR_IN:
case JSR:
case JSL:
addr[(cpu->stk_st[thread] << 16)+cpu->sp[thread]-0] = (uint64_t)cpu->pc[thread] >> (7<<3);
addr[(cpu->stk_st[thread] << 16)+cpu->sp[thread]-1] = (uint64_t)cpu->pc[thread] >> (6<<3);
addr[(cpu->stk_st[thread] << 16)+cpu->sp[thread]-2] = (uint64_t)cpu->pc[thread] >> (5<<3);
addr[(cpu->stk_st[thread] << 16)+cpu->sp[thread]-3] = (uint64_t)cpu->pc[thread] >> (4<<3);
addr[(cpu->stk_st[thread] << 16)+cpu->sp[thread]-4] = (uint64_t)cpu->pc[thread] >> (3<<3);
addr[(cpu->stk_st[thread] << 16)+cpu->sp[thread]-5] = (uint64_t)cpu->pc[thread] >> (2<<3);
addr[(cpu->stk_st[thread] << 16)+cpu->sp[thread]-6] = (uint64_t)cpu->pc[thread] >> (1<<3);
addr[(cpu->stk_st[thread] << 16)+cpu->sp[thread]-7] = (uint64_t)cpu->pc[thread] & (0xFF);
cpu->sp[thread] -= 8;
cpu->pc[thread] = address;
break;
case INC_AB:
case INC_Z:
addr[address]++;
setflag(addr[address] == 0, Z);
setflag(addr[address] >> 7, N);
step = addr[STEP_ADDR] || cpu->pc[thread] == CTRL_ADDR;
break;
case NOP:
break;
case RTS:
case RTL:
cpu->sp[thread] += 8;
cpu->pc[thread] = (uint64_t)addr[(cpu->stk_st[thread] << 16)+(cpu->sp[thread]-7)] & (0xFF);
cpu->pc[thread] += (uint64_t)addr[(cpu->stk_st[thread] << 16)+(cpu->sp[thread]-6)] << (1<<3);
cpu->pc[thread] += (uint64_t)addr[(cpu->stk_st[thread] << 16)+(cpu->sp[thread]-5)] << (2<<3);
cpu->pc[thread] += (uint64_t)addr[(cpu->stk_st[thread] << 16)+(cpu->sp[thread]-4)] << (3<<3);
cpu->pc[thread] += (uint64_t)addr[(cpu->stk_st[thread] << 16)+(cpu->sp[thread]-3)] << (4<<3);
cpu->pc[thread] += (uint64_t)addr[(cpu->stk_st[thread] << 16)+(cpu->sp[thread]-2)] << (5<<3);
cpu->pc[thread] += (uint64_t)addr[(cpu->stk_st[thread] << 16)+(cpu->sp[thread]-1)] << (6<<3);
cpu->pc[thread] += (uint64_t)addr[(cpu->stk_st[thread] << 16)+(cpu->sp[thread]-0)] << (7<<3);
break;
case DEC_AB:
case DEC_Z:
addr[address]--;
setflag(addr[address] == 0, Z);
setflag(addr[address] >> 7, N);
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);
}
addr[(cpu->stk_st[thread] << 16)+cpu->sp[thread]] = (uint64_t)cpu->pc[thread] >> 56;
addr[(cpu->stk_st[thread] << 16)+(cpu->sp[thread]-1)] = (uint64_t)cpu->pc[thread] >> 48;
addr[(cpu->stk_st[thread] << 16)+(cpu->sp[thread]-2)] = (uint64_t)cpu->pc[thread] >> 40;
addr[(cpu->stk_st[thread] << 16)+(cpu->sp[thread]-3)] = (uint64_t)cpu->pc[thread] >> 32;
addr[(cpu->stk_st[thread] << 16)+(cpu->sp[thread]-4)] = (uint64_t)cpu->pc[thread] >> 24;
addr[(cpu->stk_st[thread] << 16)+(cpu->sp[thread]-5)] = (uint64_t)cpu->pc[thread] >> 16;
addr[(cpu->stk_st[thread] << 16)+(cpu->sp[thread]-6)] = (uint64_t)cpu->pc[thread] >> 8;
addr[(cpu->stk_st[thread] << 16)+(cpu->sp[thread]-7)] = (uint64_t)cpu->pc[thread] & 0xFF;
addr[(cpu->stk_st[thread] << 16)+(cpu->sp[thread]-8)] = (uint64_t)cpu->ps >> (thread << 3);
cpu->sp[thread] -= 9;
setflag(1, I);
if (opcode == BRK) {
cpu->pc[thread] = (uint64_t)addr[0xFFE0];
cpu->pc[thread] += (uint64_t)addr[0xFFE1] << 8;
cpu->pc[thread] += (uint64_t)addr[0xFFE2] << 16;
cpu->pc[thread] += (uint64_t)addr[0xFFE3] << 24;
cpu->pc[thread] += (uint64_t)addr[0xFFE4] << 32;
cpu->pc[thread] += (uint64_t)addr[0xFFE5] << 40;
cpu->pc[thread] += (uint64_t)addr[0xFFE6] << 48;
cpu->pc[thread] += (uint64_t)addr[0xFFE7] << 56;
} else {
cpu->pc[thread] = (uint64_t)addr[0xFFA0]
| (uint64_t)addr[0xFFA1] << 8
| (uint64_t)addr[0xFFA2] << 16
| (uint64_t)addr[0xFFA3] << 24
| (uint64_t)addr[0xFFA4] << 32
| (uint64_t)addr[0xFFA5] << 40
| (uint64_t)addr[0xFFA6] << 48
| (uint64_t)addr[0xFFA7] << 56;
kbd_rdy &= (uint8_t)~(1 << thread);
}
break;
default:
break;
}
ins++;
#if !bench
#if debug
updt = (!addr[0x16]);
#endif
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) {
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);
inss = 0;
int v = 0;
if (argc != 2) {
if (asmmon("stdin") == 2) {
return 0;
}
} else {
if (asmmon(argv[1]) == 2) {
return 0;
}
}
sprintf(tmp, "\033[2J\033[H");
fwrite(tmp, sizeof(char), strlen(tmp), stdout);
fflush(stdout);
#if !bench
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);
#endif
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;
inst[i] = 0;
result = pthread_create(&therads[i], NULL, run, &thr[i]);
assert(!result);
}
int c = 0;
uint8_t step_key = 0;
#if !bench
werase(scr);
#endif
while (threads_done < THREADS) {
#if !bench
int x, y;
if ((step_key && step && !kbd_rdy) || !step || kbd_rdy) {
if ((c != EOF && c !=-1)) {
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;
#if !debug
wrefresh(scr);
#endif
}
}
#if keypoll
pthread_mutex_lock(&mutex);
#endif
getyx(scr, y, x);
c = wgetch(scr);
if (c == 19) {
step = 1;
if (kbd_rdy) {
c = wgetch(scr);
}
}
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);
wprintw(scr, "c: %i, x: %i, y: %i", c, x, y);
wmove(scr, y, x);
wrefresh(scr);
#endif
}
#if !keypoll
pthread_mutex_lock(&mutex);
pthread_cond_signal(&cond);
pthread_mutex_unlock(&mutex);
#endif
break;
}
} else {
if (step) {
step = !(c == 18);
step_key = (c == 19);
#if !keypoll
pthread_mutex_lock(&mutex);
pthread_cond_signal(&cond);
pthread_mutex_unlock(&mutex);
#endif
}
}
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
}
#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;
}