#include "sux.h" /*#include "microcode.h"*/ #include #if getclk uint64_t clk[THREADS]; /* Per Thread Clock cycles. */ uint64_t tclk; /* Total Clock cycles. */ #endif const uint16_t tv = 0xFF50; /* Starting address of the Thread Vectors. */ #if !IO uint64_t inst[THREADS]; #endif #if bench uint64_t inss; uint8_t time_done = 0; #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; uint8_t dbg_print_per_inst = 0; uint8_t end = 0; WINDOW *scr; WINDOW *regs; WINDOW *inst_win; WINDOW *dbg_win; struct suxthr { struct sux sx; uint8_t th; }; #if bench double ipc; void stop_timer() { time_done = 1; } void start_timer(int sec, int usec) { struct itimerval it_val; for (; usec > 1000000; sec++, usec -= 1000000); it_val.it_value.tv_sec = sec; it_val.it_value.tv_usec = usec; it_val.it_interval.tv_sec = 0; it_val.it_interval.tv_usec = 0; if (signal(SIGALRM, stop_timer) == SIG_ERR) { perror("Unable to catch SIGALRM."); exit(1); } if (setitimer(ITIMER_REAL, &it_val, NULL) == -1) { perror("Error calling setitimer()."); exit(1); } } #endif uint8_t is_extop(uint8_t opcode, uint8_t dbg) { switch (opcode) { case ADC_E: case SBC_E: case AND_E: case ORA_E: case XOR_E: case LSL_E: case LSR_E: case ROL_E: case ROR_E: case MUL_E: case DIV_E: case ASR_E: case CMP_E: case LDY_E: case LDA_E: case LDB_E: case CPB_E: case CPX_E: case CPY_E: case LDX_E: case DEC_E: case INC_E: case STY_E: case STA_E: case STB_E: case STX_E: case JMP_E: case JSR_E: return 0; } return 1; } int is_wait_kbd(struct sux *cpu, uint8_t opcode, uint8_t prefix, uint8_t ext_prefix, uint8_t prefix2, uint8_t *op_type, uint8_t *op_id, uint8_t op_len, uint8_t thread) { uint64_t address = 0; operand ortho_op[2]; uint64_t ortho_addr[2] = {0, 0}; uint64_t tmp_pc = cpu->pc; cpu->pc += op_len; if (ext_prefix != 0x1D) { address = get_addr(cpu, opcode, prefix, ext_prefix, 0, 0, thread); } else { get_ortho_addr(cpu, opcode, prefix, cpu->pc, ortho_op, ortho_addr, op_type, op_id, 0, 0, thread); } cpu->pc = tmp_pc; return (address == CTRL_ADDR || ortho_addr[0] == CTRL_ADDR || ortho_addr[1] == CTRL_ADDR); } 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 ext_prefix = 0; uint8_t prefix2 = 0; uint8_t op_id = 0; uint8_t opcode = 0; union reg address; union reg value; cpu->clk = 0; uint64_t *rem = NULL; #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 start_timer(1, 0); #endif /*ucode uc; uc.upc = 0; uc.usp = 0xFF; uc.alu_a = 0; uc.alu_b = 0; uc.dbus = 0; for (int i = 0; i < AGU_IDX_CNT; uc.agu_idx[i++] = 0); uc.agu_dben = 0; uc.agu_oplen = 0; uc.mdr = 0; uc.mar = 0; uc.ir = 0; uc.itr = 0; uc.clk = 0; struct sux uc_test;*/ for (;;) { #if !bench if (end) { pthread_mutex_lock(&main_mutex); pthread_cond_signal(&main_cond); pthread_mutex_unlock(&main_mutex); return NULL; } #endif address.u64 = 0; value.u64 = 0; uint32_t inst = read_value(cpu, 0, cpu->pc, 4, 1, 0); uint8_t *tmp_inst = (uint8_t *)&inst; uint8_t inst_len = 0; prefix = ((inst & 3) == 3) ? tmp_inst[inst_len++] : 0; ext_prefix = ((tmp_inst[inst_len] & 0xF) == 0xD) ? tmp_inst[inst_len++] : 0; opcode = tmp_inst[inst_len++]; op_id = (ext_prefix == 0x1D) ? tmp_inst[inst_len++] : 0; uint8_t operand_type[2]; uint8_t am; uint8_t ortho_id[2]; uint8_t ext_id = 0; uint8_t tmp_opcode = opcode; uint8_t tmp_ext_prefix = ext_prefix; int is_ortho = 0; if (ext_prefix) { ext_id = (ext_prefix >> 4); switch (ext_id) { case 0x0: am = ext_optype[opcode]; if (!is_extop(opcode, 0)) { tmp_ext_prefix = 0; switch (opcode) { case ADC_E: tmp_opcode = ADC_IMM; break; case SBC_E: tmp_opcode = SBC_IMM; break; case AND_E: tmp_opcode = AND_IMM; break; case ORA_E: tmp_opcode = ORA_IMM; break; case XOR_E: tmp_opcode = XOR_IMM; break; case LSL_E: tmp_opcode = LSL_IMM; break; case LSR_E: tmp_opcode = LSR_IMM; break; case ROL_E: tmp_opcode = ROL_IMM; break; case ROR_E: tmp_opcode = ROR_IMM; break; case MUL_E: tmp_opcode = MUL_IMM; break; case DIV_E: tmp_opcode = DIV_IMM; break; case ASR_E: tmp_opcode = ASR_IMM; break; case CMP_E: tmp_opcode = CMP_IMM; break; case LDY_E: tmp_opcode = LDY_IMM; break; case LDA_E: tmp_opcode = LDA_IMM; break; case LDB_E: tmp_opcode = LDB_IMM; break; case CPB_E: tmp_opcode = CPB_IMM; break; case CPX_E: tmp_opcode = CPX_IMM; break; case CPY_E: tmp_opcode = CPY_IMM; break; case LDX_E: tmp_opcode = LDX_IMM; break; case DEC_E: tmp_opcode = DEC_Z; break; case INC_E: tmp_opcode = INC_Z; break; case STY_E: tmp_opcode = STY_Z; break; case STA_E: tmp_opcode = STA_Z; break; case STB_E: tmp_opcode = STB_Z; break; case STX_E: tmp_opcode = STX_Z; break; case JMP_E: tmp_opcode = JMP_Z; break; case JSR_E: tmp_opcode = JSR_Z; break; } } break; case 0x1: operand_type[0] = ((opcode & 0x10) >> 4); operand_type[1] = ((opcode & 0x08) >> 3); ortho_id[0] = op_id >> 4; ortho_id[1] = op_id & 0x0F; am = IMPL; is_ortho = 1; break; } } else { am = optype[opcode]; } uint8_t rs = (prefix >> 4) & 3; uint8_t size = (/***/1 << rs) - 1; uint8_t check_io = (am != IMM); cpu->pc += inst_len; address.u64 = cpu->pc; #if debug && !bench cpu->pc -= inst_len; if (!dbg_print_per_inst) { kbd_rdy = is_wait_kbd(cpu, opcode, prefix, ext_prefix, prefix2, operand_type, ortho_id, inst_len, thread); } else { kbd_rdy = 0; } if (lines > 24*(thread+1)) { lines = (24*thread)+2; } if (step | kbd_rdy | dbg_print_per_inst) { #if keypoll pthread_mutex_lock(&mutex); #endif print_info(cpu, inst_win, lines, thread); print_regs(cpu, regs); cpu->pc = address.u64; disasm(cpu, inst_win, lines, opcode, prefix, ext_prefix, prefix2, operand_type, ortho_id, thread); lines+=1; #if keypoll pthread_mutex_unlock(&mutex); #endif } else { cpu->pc = address.u64; } #endif if (am != IMPL && am != BREG) { address.u64 = get_addr(cpu, opcode, prefix, ext_prefix, 1, 1, thread); /*if (address.u64 > mem_size-1) { addr[STEP_ADDR] = 1; step = 1; }*/ if (isrw(opcode, ext_prefix) && am != REL && isread(opcode, ext_prefix)) { value.u64 = read_value(cpu, 0, address.u64, size, 1, check_io); } } /*decode_microinst(&uc, &uc_test, prefix, 0);*/ ext_prefix = tmp_ext_prefix; opcode = tmp_opcode; if (ext_prefix) { uint8_t tmp = 0; switch (ext_id) { case 0x0: exec_ext_inst(cpu, opcode, prefix, value.u64, address.u64, size, thread); break; case 0x1: exec_ortho_inst(cpu, opcode, prefix, size, operand_type, ortho_id, thread); break; } } else { exec_base_inst(cpu, opcode, prefix, value.u64, address.u64, size, thread); } /*usleep(1);*/ #if !IO ins++; #endif #if !bench if (step) { int c = 0; #if debug wrefresh(scr); wrefresh(regs); wrefresh(inst_win); #endif for (; step && c != 19 && !end; c = get_key(scr)); #if debug wrefresh(scr); wrefresh(regs); wrefresh(inst_win); #endif } #endif #if debug && !bench #if keypoll pthread_mutex_lock(&mutex); #endif wmove(inst_win, (6*thread)+1, 0); wprintw(inst_win, "Instructions executed: %"PRIu64, ins); #if getclk wprintw(inst_win, ", Clock cycles: %"PRIu64, cpu->clk); #endif if (step || !subdbg) { wrefresh(scr); wrefresh(regs); wrefresh(inst_win); wrefresh(dbg_win); } #if keypoll pthread_mutex_unlock(&mutex); #endif #elif bench if (time_done) { pthread_mutex_lock(&main_mutex); threads_done++; inst[thread] = ins; #if getclk clk[thread] = cpu->clk; #endif pthread_cond_signal(&main_cond); pthread_mutex_unlock(&main_mutex); break; } #endif } return NULL; } void init_scr() { if (!scr) { scr = initscr(); } nodelay(scr, 0); keypad(scr, 1); crmode(); noecho(); nl(); curs_set(1); scrollok(scr, 1); start_color(); use_default_colors(); init_pair(1, COLOR_WHITE, -1); wattron(scr, COLOR_PAIR(1) | A_BOLD); #if debug int x; int y; getmaxyx(scr, y, x); if (!regs) { regs = newwin(24, 80, 1, (x/2)); } nodelay(regs, 0); keypad(regs, 1); scrollok(regs, 1); wattron(regs, COLOR_PAIR(1) | A_BOLD); if (!inst_win) { inst_win = newwin(28, (x/2)-20, 0, 0); } nodelay(inst_win, 0); keypad(inst_win, 1); scrollok(inst_win, 1); wattron(inst_win, COLOR_PAIR(1) | A_BOLD); if (!dbg_win) { dbg_win = newwin(33, x, y-33, 0); } nodelay(dbg_win, 0); keypad(dbg_win, 1); scrollok(dbg_win, 1); wattron(dbg_win, COLOR_PAIR(1) | A_BOLD); #endif } int main(int argc, char **argv) { struct suxthr thr[THREADS]; char *tmp = malloc(2048); addr = malloc(mem_size); #if bench inss = 0; struct timeval str, en; #endif int v = 0; if (argc != 2) { if (asmmon("stdin") == 2) { return 0; } } else { #if debug subdbg = !strcmp(argv[1], "programs/sub-suite/subsuite.s"); #endif if (asmmon(argv[1]) == 2) { return 0; } } /*sprintf(tmp, "\033[2J\033[H"); fwrite(tmp, sizeof(char), strlen(tmp), stdout); fflush(stdout);*/ init_scr(); werase(scr); wmove(scr, 0, 0); wrefresh(scr); #if debug werase(regs); wmove(regs, 0, 0); wrefresh(regs); werase(inst_win); wmove(inst_win, 0, 0); wrefresh(inst_win); werase(dbg_win); wmove(dbg_win, 0, 0); wrefresh(dbg_win); #endif pthread_t therads[THREADS]; int result; uint16_t vec = 0xFFC0; uint8_t offset; /*for (int i = 0; i < 4096; i++) { for (int j = 0; j < RW_UNITS; j++) { mucode[i].ui.ru[j].type = rand(); mucode[i].ui.wu[j].type = rand(); } mucode[i].ui.imm = rand(); mucode[i].ui.agu_sig.prefix = rand(); mucode[i].ui.agu_sig.ind = rand(); mucode[i].ui.agu_sig.ind_type = rand(); mucode[i].ui.agu_sig.zm = rand(); mucode[i].ui.agu_sig.idx_sub = rand(); mucode[i].ui.sig.mread = rand(); mucode[i].ui.sig.mwrite = rand(); mucode[i].ui.sig.inv_b = rand(); mucode[i].ui.sig.c_in = rand(); mucode[i].ui.sig.fetch = rand(); mucode[i].ui.sig.set_nvzc = rand(); mucode[i].ui.sig.rw_en = rand(); mucode[i].ui.is_jmp = rand(); mucode[i].ui.jmp_type = rand(); mucode[i].ui.cond_type = rand(); mucode[i].ui.cond_reg = rand(); mucode[i].ui.jmp_addr = rand(); for (int j = 0; j < sizeof(uinst); mucode[i].u8[j++] = (uint8_t)rand()); }*/ for (int i = 0; i < THREADS; i++) { thr[i].sx.sp = (i << 16) | 0xFFFF; offset = (i) ? ((i-1) << 3) : 0; vec = (i) ? 0xFF50 : 0xFFC0; thr[i].sx.a = 0, thr[i].sx.b = 0; thr[i].sx.x = 0, thr[i].sx.y = 0; thr[i].sx.e = 0, thr[i].sx.c = 0; thr[i].sx.d = 0, thr[i].sx.s = 0; thr[i].sx.f = 0, thr[i].sx.bp = 0; thr[i].sx.r11 = 0, thr[i].sx.r12 = 0; thr[i].sx.r12 = 0, thr[i].sx.r13 = 0; thr[i].sx.r14 = 0, thr[i].sx.r15 = 0; thr[i].sx.pc = read_value(&thr[i].sx, 0, vec+offset, 7, 0, 0); thr[i].th = i; #if !IO inst[i] = 0; #endif result = pthread_create(&therads[i], NULL, run, &thr[i]); assert(!result); } werase(scr); #if bench endwin(); gettimeofday(&str, 0); double t = 0; double dt = 0; double t2 = 0; #endif while (threads_done < THREADS && !end) { #if !bench pthread_mutex_lock(&main_mutex); pthread_cond_wait(&main_cond, &main_mutex); pthread_mutex_unlock(&main_mutex); /*#if keypoll pthread_mutex_lock(&mutex); #endif #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 endwin(); #endif #if bench gettimeofday(&en, 0); if (threads_done == THREADS) { double tm_sec, tm_usec, tm; #if getclk double clkspd; double mhz; #endif double ips[THREADS]; double ipst; tm_sec = (en.tv_sec - str.tv_sec); tm_usec = (en.tv_usec-str.tv_usec); tm = (tm_sec*1000000)+(tm_usec); for (int i = 0; i < THREADS; i++) { ips[i] = inst[i]/tm; if (i) { inss += inst[i]; ipst += ips[i]; #if getclk tclk += clk[i]; #endif } else { inss = inst[i]; ipst = ips[i]; #if getclk tclk = clk[i]; #endif } #if getclk clkspd = (tm/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\n", i, inst[i], i, ips[i]); 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 = (tm/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", tm/1000000); fwrite(tmp, sizeof(char), strlen(tmp), stdout); fflush(stdout); free(tmp); } #endif free(addr); return 0; }