void do_mem_stage() { bool_t read = gen_mem_read(); bool_t mem_ok = TRUE; word_t valm = 0; mem_addr = gen_mem_addr(); mem_data = ex_mem_curr->vala; mem_write = gen_mem_write(); if (read) { mem_ok = get_word_val(mem, mem_addr, &valm); sim_log("Memory: Read 0x%x from 0x%x, instruction = %s\n", valm, mem_addr, iname(HPACK(ex_mem_curr->icode, ex_mem_curr->ifun))); } if (mem_write) { word_t sink; /* Do a read of address just to check validity */ mem_ok = get_word_val(mem, mem_addr, &sink); } mem_wb_next->icode = ex_mem_curr->icode; mem_wb_next->ifun = ex_mem_curr->ifun; mem_wb_next->vale = ex_mem_curr->vale; mem_wb_next->valm = valm; mem_wb_next->deste = ex_mem_curr->deste; mem_wb_next->destm = ex_mem_curr->destm; mem_wb_next->exception = mem_ok ? ex_mem_curr->exception : EXC_ADDR; mem_wb_next->stage_pc = ex_mem_curr->stage_pc; }
/* do a branch if necessary */ static void process_dobranch(int pnum, Process *q, Branch *b, Bcontext *c) { if (bcontext_decide(c)) { // must document where we branched from if (output) fprintf(output, "%ld,%d,%ld,%ld,%ld,branch_from\n", sysclock, pnum, q->pid, q->kind, q->pc); q->pc = b->whereto; // and where we branched to if (output) fprintf(output, "%ld,%d,%ld,%ld,%ld,branch_to\n", sysclock, pnum, q->pid, q->kind, q->pc); sim_log(LOG_BRANCH,"process %2d; pc %04d: branch\n",pnum, q->pc); } else { q->pc++; sim_log(LOG_BRANCH,"process %2d; pc %04d: no branch\n",pnum, q->pc); } if (q->pc<0 || q->pc>=q->program->size) q->pc=0; /* start over */ }
/* Implements both ID and WB */ void do_id_wb_stages() { /* Set up write backs. Don't occur until end of cycle */ wb_destE = gen_w_dstE(); wb_valE = gen_w_valE(); wb_destM = gen_w_dstM(); wb_valM = gen_w_valM(); id_ex_next->srca = gen_new_E_srcA(); id_ex_next->srcb = gen_new_E_srcB(); id_ex_next->deste = gen_new_E_dstE(); id_ex_next->destm = gen_new_E_dstM(); /* Read the registers */ d_regvala = get_reg_val(reg, id_ex_next->srca); d_regvalb = get_reg_val(reg, id_ex_next->srcb); /* Do forwarding and valA selection */ id_ex_next->vala = gen_new_E_valA(); id_ex_next->valb = gen_new_E_valB(); id_ex_next->icode = if_id_curr->icode; id_ex_next->ifun = if_id_curr->ifun; id_ex_next->valc = if_id_curr->valc; id_ex_next->stage_pc = if_id_curr->stage_pc; id_ex_next->exception = (if_id_curr->icode == I_HALT) ? EXC_HALT : if_id_curr->exception; sim_log("Decode: instr = %s, exc=%s\n", iname(HPACK(if_id_curr->icode, if_id_curr->ifun)), exc_name(if_id_curr->exception)); }
/* Max_instr indicates maximum number of instructions that want to complete during this simulation run. */ static exc_t sim_step_pipe(int max_instr) { exc_t wb_exc = mem_wb_curr->exception; exc_t mem_exc = mem_wb_next->exception; /* How many instructions are ahead of one in wb / ex? */ int ahead_mem = (wb_exc != EXC_BUBBLE); int ahead_ex = ahead_mem + (mem_exc != EXC_BUBBLE); bool_t wb_ok = (wb_exc == EXC_NONE) || (wb_exc == EXC_BUBBLE); bool_t mem_ok = (mem_exc == EXC_NONE) || (mem_exc == EXC_BUBBLE); bool_t update_mem = wb_ok && ahead_mem < max_instr; bool_t update_cc = update_mem && mem_ok && ahead_ex < max_instr; if (!update_mem) { sim_log("Disabling memory write. wb_exc = %s\n", exc_name(wb_exc)); } /* Update program-visible state */ update_state(update_mem, update_cc); /* Update pipe registers */ update_pipes(); if (pc_state->op == P_ERROR) pc_curr->exception = EXC_PIPE; if (if_id_state->op == P_ERROR) if_id_curr->exception = EXC_PIPE; if (id_ex_state->op == P_ERROR) id_ex_curr->exception = EXC_PIPE; if (ex_mem_state->op == P_ERROR) ex_mem_curr->exception = EXC_PIPE; if (mem_wb_state->op == P_ERROR) mem_wb_curr->exception = EXC_PIPE; /* Need to do decode after execute & memory stages, and memory stage before execute, in order to propagate forwarding values properly */ do_if_stage(); do_mem_stage(); do_ex_stage(); do_id_wb_stages(); do_stall_check(); if (id_ex_curr->exception != EXC_NONE && id_ex_curr->exception != EXC_BUBBLE) { if_id_state->op = P_BUBBLE; id_ex_state->op = P_BUBBLE; } /* Performance monitoring */ if (mem_wb_curr->exception != EXC_BUBBLE && mem_wb_curr->icode != I_POP2) { starting_up = 0; instructions++; cycles++; } else { if (!starting_up) cycles++; } sim_report(); return mem_wb_curr->exception; }
/* unload a process and release all resources */ static void process_unload(int pnum, Process *q) { long i; for (i=0; i<q->npages; i++) if (q->pages[i]>=-PAGEWAIT) { pagesavail++; q->pages[i]=-PAGEWAIT-1; q->blocked[i]=1; } q->active=FALSE; sim_log(LOG_LOAD,"process %2d; pc %04d: unloaded\n",pnum, q->pc); }
void do_ex_stage() { alu_t alufun = gen_alufun(); bool_t setcc = gen_set_cc(); word_t alua, alub; alua = gen_aluA(); alub = gen_aluB(); e_bcond = take_branch(cc, id_ex_curr->ifun); ex_mem_next->takebranch = id_ex_curr->icode == I_JMP && e_bcond; if (id_ex_curr->icode == I_JMP) sim_log("Execute: %s instruction, cc = %s, branch %staken\n", iname(HPACK(id_ex_curr->icode, id_ex_curr->ifun)), cc_name(cc), ex_mem_next->takebranch ? "" : "not "); /* Perform the ALU operation */ ex_mem_next->vale = compute_alu(alufun, alua, alub); { byte_t instr = HPACK(id_ex_curr->icode, id_ex_curr->ifun); sim_log("Execute: Instruction %s\n", iname(instr)); } if (setcc) { cc_in = compute_cc(alufun, alua, alub); sim_log("Execute: CC cc = %s\n", cc_name(cc_in)); } ex_mem_next->icode = id_ex_curr->icode; ex_mem_next->ifun = id_ex_curr->ifun; ex_mem_next->vala = gen_new_M_valA(); ex_mem_next->deste = id_ex_curr->deste; ex_mem_next->destm = id_ex_curr->destm; ex_mem_next->srca = id_ex_curr->srca; ex_mem_next->exception = id_ex_curr->exception; ex_mem_next->stage_pc = id_ex_curr->stage_pc; }
void do_mem_stage() { bool_t read = gen_mem_read(); word_t valm = 0; mem_addr = gen_mem_addr(); mem_data = ex_mem_curr->vala; mem_write = gen_mem_write(); mem_test = gen_mem_test(); dmem_error = FALSE; if (read && !mem_test) { dmem_error = dmem_error || !get_word_val(mem, mem_addr, &valm); if (!dmem_error) sim_log("\tMemory: Read 0x%x from 0x%x\n", valm, mem_addr); } if (mem_write && !mem_test) { word_t sink; /* Do a read of address just to check validity */ dmem_error = dmem_error || !get_word_val(mem, mem_addr, &sink); if (dmem_error) sim_log("\tMemory: Invalid address 0x%x\n", mem_addr); } if (mem_test && read){ mem_test_address = mem_addr; int ans = test_memory(mem, mem_test_address); valm = ans; } mem_wb_next->icode = ex_mem_curr->icode; mem_wb_next->ifun = ex_mem_curr->ifun; mem_wb_next->vale = ex_mem_curr->vale; mem_wb_next->valm = valm; mem_wb_next->deste = ex_mem_curr->deste; mem_wb_next->destm = ex_mem_curr->destm; mem_wb_next->status = gen_m_stat(); mem_wb_next->stage_pc = ex_mem_curr->stage_pc; }
/* Text representation of status */ void tty_report(int cyc) { sim_log("\nCycle %d. CC=%s, Stat=%s\n", cyc, cc_name(cc), stat_name(status)); sim_log("F: predPC = 0x%x\n", pc_curr->pc); sim_log("D: instr = %s, rA = %s, rB = %s, valC = 0x%x, valP = 0x%x, Stat = %s\n", iname(HPACK(if_id_curr->icode, if_id_curr->ifun)), reg_name(if_id_curr->ra), reg_name(if_id_curr->rb), if_id_curr->valc, if_id_curr->valp, stat_name(if_id_curr->status)); sim_log("E: instr = %s, valC = 0x%x, valA = 0x%x, valB = 0x%x\n srcA = %s, srcB = %s, dstE = %s, dstM = %s, Stat = %s\n", iname(HPACK(id_ex_curr->icode, id_ex_curr->ifun)), id_ex_curr->valc, id_ex_curr->vala, id_ex_curr->valb, reg_name(id_ex_curr->srca), reg_name(id_ex_curr->srcb), reg_name(id_ex_curr->deste), reg_name(id_ex_curr->destm), stat_name(id_ex_curr->status)); sim_log("M: instr = %s, Cnd = %d, valE = 0x%x, valA = 0x%x\n dstE = %s, dstM = %s, Stat = %s\n", iname(HPACK(ex_mem_curr->icode, ex_mem_curr->ifun)), ex_mem_curr->takebranch, ex_mem_curr->vale, ex_mem_curr->vala, reg_name(ex_mem_curr->deste), reg_name(ex_mem_curr->destm), stat_name(ex_mem_curr->status)); sim_log("W: instr = %s, valE = 0x%x, valM = 0x%x, dstE = %s, dstM = %s, Stat = %s\n", iname(HPACK(mem_wb_curr->icode, mem_wb_curr->ifun)), mem_wb_curr->vale, mem_wb_curr->valm, reg_name(mem_wb_curr->deste), reg_name(mem_wb_curr->destm), stat_name(mem_wb_curr->status)); }
void do_mem_stage() { bool_t read = gen_mem_read(); word_t valm = 0; mem_addr = gen_mem_addr(); if(ex_mem_curr->icode == I_MUTEXTEST || ex_mem_curr->icode == I_MUTEXCLEAR) mem_addr = MUTEX_BYTE; mem_data = ex_mem_curr->vala; if(ex_mem_curr->icode == I_MUTEXTEST) mem_data = 1; else if(ex_mem_curr->icode == I_MUTEXCLEAR) mem_data = 0; mem_write = gen_mem_write(); dmem_error = FALSE; if (read) { dmem_error = dmem_error || !get_word_val(mem, mem_addr, &valm); if (!dmem_error) sim_log("\tMemory: Read 0x%x from 0x%x\n", valm, mem_addr); } if (mem_write) { word_t sink; /* Do a read of address just to check validity */ dmem_error = dmem_error || !get_word_val(mem, mem_addr, &sink); if (dmem_error) sim_log("\tMemory: Invalid address 0x%x\n", mem_addr); } mem_wb_next->icode = ex_mem_curr->icode; mem_wb_next->ifun = ex_mem_curr->ifun; mem_wb_next->vale = ex_mem_curr->vale; mem_wb_next->valm = valm; mem_wb_next->deste = ex_mem_curr->deste; mem_wb_next->destm = ex_mem_curr->destm; mem_wb_next->status = gen_m_stat(); mem_wb_next->stage_pc = ex_mem_curr->stage_pc; }
void do_ex_stage() { alu_t alufun = gen_alufun(); bool_t setcc = gen_set_cc(); word_t alua, alub; alua = gen_aluA(); alub = gen_aluB(); e_bcond = cond_holds(cc, id_ex_curr->ifun); ex_mem_next->takebranch = e_bcond; if (id_ex_curr->icode == I_JMP) sim_log("\tExecute: instr = %s, cc = %s, branch %staken\n", iname(HPACK(id_ex_curr->icode, id_ex_curr->ifun)), cc_name(cc), ex_mem_next->takebranch ? "" : "not "); /* Perform the ALU operation */ word_t aluout = compute_alu(alufun, alua, alub); ex_mem_next->vale = aluout; sim_log("\tExecute: ALU: %c 0x%x 0x%x --> 0x%x\n", op_name(alufun), alua, alub, aluout); if (setcc) { cc_in = compute_cc(alufun, alua, alub); sim_log("\tExecute: New cc = %s\n", cc_name(cc_in)); } ex_mem_next->icode = id_ex_curr->icode; ex_mem_next->ifun = id_ex_curr->ifun; ex_mem_next->vala = gen_e_valA(); ex_mem_next->deste = gen_e_dstE(); ex_mem_next->destm = id_ex_curr->destm; ex_mem_next->srca = id_ex_curr->srca; ex_mem_next->status = id_ex_curr->status; ex_mem_next->stage_pc = id_ex_curr->stage_pc; }
p_status_t pipe_cntl(char *name, int stall, int bubble) { if (stall) { if (bubble) { sim_log("%s: Conflicting control signals for pipe register\n", name); return P_ERROR; } else return P_STALL; } else { return bubble ? P_BUBBLE : P_LOAD; } }
/* public routine: swap one page out */ int pageout(int process, int page) { if (process<0 || process>=procs || !processes[process] || !processes[process]->active || page<0 || page>=processes[process]->npages) return FALSE; if (processes[process]->pages[page]<0) return TRUE; /* on its way out */ if (processes[process]->pages[page]>0) return FALSE; /* not available to swap out */ sim_log(LOG_PAGE,"process=%2d page=%3d start pageout\n",process,page); if (pages) fprintf(pages,"%ld,%d,%d,%ld,%ld,going\n", sysclock,process,page,processes[process]->pid, processes[process]->kind); processes[process]->pages[page]=-1; return TRUE; }
/* Update the processor state */ static void update_state() { if (plusmode) { prev_icode = prev_icode_in; prev_ifun = prev_ifun_in; prev_valc = prev_valc_in; prev_valm = prev_valm_in; prev_valp = prev_valp_in; prev_bcond = prev_bcond_in; } else { pc = pc_in; } cc = cc_in; /* Writeback */ if (destE != REG_NONE) set_reg_val(reg, destE, vale); if (destM != REG_NONE) set_reg_val(reg, destM, valm); if (mem_write) { /* Should have already tested this address */ set_word_val(mem, mem_addr, mem_data); sim_log("Wrote 0x%x to address 0x%x\n", mem_data, mem_addr); #ifdef HAS_GUI if (gui_mode) { if (mem_addr % 4 != 0) { /* Just did a misaligned write. Need to display both words */ word_t align_addr = mem_addr & ~0x3; word_t val; get_word_val(mem, align_addr, &val); set_memory(align_addr, val); align_addr+=4; get_word_val(mem, align_addr, &val); set_memory(align_addr, val); } else { set_memory(mem_addr, mem_data); } } #endif /* HAS_GUI */ } }
static void allinit () { long i; initqueue(); for (i=0; i<MAXPROCESSES; i++) processes[i]=NULL; for (i=0; i<procs; i++) { // zero out pages from processes if (!empty()) { processes[i]=dequeue(); sim_log(LOG_LOAD,"process %2d; pc %04d: loaded\n",i, processes[i]->pc); if (output) fprintf(output, "%ld,%ld,%ld,%ld,%ld,load\n", sysclock, i, processes[i]->pid, processes[i]->kind, processes[i]->pc); if (pages) { long j; for (j=0; j<MAXPROCPAGES; j++) fprintf(pages,"%ld,%ld,%ld,%ld,%ld,out\n", sysclock,i,j,processes[i]->pid,processes[i]->kind); } } } }
/* Return resulting exception status */ static exc_t sim_step() { word_t aluA; word_t aluB; word_t alufun; exc_t status = update_state(); /* Update state from last cycle */ if (plusmode) { pc = gen_pc(); } valp = pc; if (get_byte_val(mem, valp, &instr)) { icode = HI4(instr); ifun = LO4(instr); } else { instr = HPACK(I_NOP,0); icode = I_NOP; ifun = 0; status = EXC_ADDR; sim_log("Couldn't fetch at address 0x%x\n", valp); } valp++; if (gen_need_regids()) { byte_t regids; if (get_byte_val(mem, valp, ®ids)) { ra = GET_RA(regids); rb = GET_RB(regids); } else { ra = REG_NONE; rb = REG_NONE; status = EXC_ADDR; sim_log("Couldn't fetch at address 0x%x\n", valp); } valp++; } else { ra = REG_NONE; rb = REG_NONE; } if (gen_need_valC()) { if (get_word_val(mem, valp, &valc)) { } else { valc = 0; status = EXC_ADDR; sim_log("Couldn't fetch at address 0x%x\n", valp); } valp+=4; } else { valc = 0; } if (status == EXC_NONE && !gen_instr_valid()) { status = EXC_INSTR; } sim_log("IF: Fetched %s at 0x%x. ra=%s, rb=%s, valC = 0x%x\n", iname(HPACK(icode,ifun)), pc, reg_name(ra), reg_name(rb), valc); if (status == EXC_NONE && icode == I_HALT) { status = EXC_HALT; } srcA = gen_srcA(); if (srcA != REG_NONE) { vala = get_reg_val(reg, srcA); } else { vala = 0; } srcB = gen_srcB(); if (srcB != REG_NONE) { valb = get_reg_val(reg, srcB); } else { valb = 0; } destE = gen_dstE(); destM = gen_dstM(); aluA = gen_aluA(); aluB = gen_aluB(); alufun = gen_alufun(); vale = compute_alu(alufun, aluA, aluB); cc_in = cc; if (gen_set_cc()) cc_in = compute_cc(alufun, aluA, aluB); bcond = (icode == I_JMP) && take_branch(cc, ifun); mem_addr = gen_mem_addr(); mem_data = gen_mem_data(); if (status == EXC_NONE && gen_mem_read()) { if (!get_word_val(mem, mem_addr, &valm)) { sim_log("Couldn't read at address 0x%x\n", mem_addr); return EXC_ADDR; } } else valm = 0; mem_write = status == EXC_NONE && gen_mem_write(); if (plusmode) { prev_icode_in = icode; prev_ifun_in = ifun; prev_valc_in = valc; prev_valm_in = valm; prev_valp_in = valp; prev_bcond_in = bcond; } else { /* Update PC */ pc_in = gen_new_pc(); } sim_report(); return status; }
/* Return resulting status */ static byte_t sim_step() { word_t aluA; word_t aluB; word_t alufun; status = STAT_AOK; imem_error = dmem_error = FALSE; update_state(); /* Update state from last cycle */ if (plusmode) { pc = gen_pc(); } valp = pc; instr = HPACK(I_NOP, F_NONE); imem_error = !get_byte_val(mem, valp, &instr); if (imem_error) { sim_log("Couldn't fetch at address 0x%x\n", valp); } imem_icode = HI4(instr); imem_ifun = LO4(instr); icode = gen_icode(); ifun = gen_ifun(); instr_valid = gen_instr_valid(); valp++; if (gen_need_regids()) { byte_t regids; if (get_byte_val(mem, valp, ®ids)) { ra = GET_RA(regids); rb = GET_RB(regids); } else { ra = REG_NONE; rb = REG_NONE; status = STAT_ADR; sim_log("Couldn't fetch at address 0x%x\n", valp); } valp++; } else { ra = REG_NONE; rb = REG_NONE; } if (gen_need_valC()) { if (get_word_val(mem, valp, &valc)) { } else { valc = 0; status = STAT_ADR; sim_log("Couldn't fetch at address 0x%x\n", valp); } valp+=4; } else { valc = 0; } sim_log("IF: Fetched %s at 0x%x. ra=%s, rb=%s, valC = 0x%x\n", iname(HPACK(icode,ifun)), pc, reg_name(ra), reg_name(rb), valc); if (status == STAT_AOK && icode == I_HALT) { status = STAT_HLT; } srcA = gen_srcA(); if (srcA != REG_NONE) { vala = get_reg_val(reg, srcA); } else { vala = 0; } srcB = gen_srcB(); if (srcB != REG_NONE) { valb = get_reg_val(reg, srcB); } else { valb = 0; } cond = cond_holds(cc, ifun); destE = gen_dstE(); destM = gen_dstM(); aluA = gen_aluA(); aluB = gen_aluB(); alufun = gen_alufun(); vale = compute_alu(alufun, aluA, aluB); cc_in = cc; if (gen_set_cc()) cc_in = compute_cc(alufun, aluA, aluB); bcond = cond && (icode == I_JMP); mem_addr = gen_mem_addr(); mem_data = gen_mem_data(); if (gen_mem_read()) { dmem_error = dmem_error || !get_word_val(mem, mem_addr, &valm); if (dmem_error) { sim_log("Couldn't read at address 0x%x\n", mem_addr); } } else valm = 0; mem_write = gen_mem_write(); if (mem_write) { /* Do a test read of the data memory to make sure address is OK */ word_t junk; dmem_error = dmem_error || !get_word_val(mem, mem_addr, &junk); } status = gen_Stat(); if (plusmode) { prev_icode_in = icode; prev_ifun_in = ifun; prev_valc_in = valc; prev_valm_in = valm; prev_valp_in = valp; prev_bcond_in = bcond; } else { /* Update PC */ pc_in = gen_new_pc(); } sim_report(); return status; }
void do_if_stage() { exc_t nstatus = EXC_NONE; word_t fetchpc = gen_f_pc(); word_t valp = fetchpc; bool_t fetch_ok; byte_t instr; byte_t regids = HPACK(REG_NONE, REG_NONE); word_t valc = 0; f_pc = fetchpc; if (fetchpc == 0) { sim_log("Fetch: Fetch pc = 0, nominal pc = 0x%x\n", pc_curr->pc); } /* Ready to fetch instruction. Speculatively fetch register byte and immediate word */ fetch_ok = get_byte_val(mem, valp, &instr); if (fetch_ok) { if_id_next->icode = GET_ICODE(instr); if_id_next->ifun = GET_FUN(instr); } else { if_id_next->icode = I_NOP; if_id_next->ifun = 0; nstatus = EXC_ADDR; } valp++; if (fetch_ok && gen_need_regids()) { fetch_ok = get_byte_val(mem, valp, ®ids); valp ++; } if_id_next->ra = HI4(regids); if_id_next->rb = LO4(regids); if (fetch_ok && gen_need_valC()) { fetch_ok = get_word_val(mem, valp, &valc); valp+= 4; } if_id_next->valp = valp; if_id_next->valc = valc; pc_next->pc = gen_new_F_predPC(); if (!gen_instr_valid()) { byte_t instr = HPACK(if_id_next->icode, if_id_next->ifun); sim_log("Fetch: Instruction code %s (0x%x) invalid\n", iname(instr), instr); nstatus = EXC_INSTR; } pc_next->exception = (nstatus == EXC_NONE) ? EXC_NONE : EXC_BUBBLE; if_id_next->stage_pc = fetchpc; if_id_next->exception = nstatus; /* Recompute icode for one-write implementation of popl */ if_id_next->icode = gen_new_D_icode(); sim_log("Fetch: Fetched %s at 0x%x, ra = %s, rb = %s, valp = 0x%x, status = %s\n", iname(HPACK(if_id_next->icode, if_id_next->ifun)), if_id_next->stage_pc, reg_name(if_id_next->ra), reg_name(if_id_next->rb), if_id_next->valp, exc_name(nstatus)); }
int main(int argc, char **argv) { long i,errors=0,help=0; signal(SIGINT, endit); log_port=LOG_ALWAYS; for (i=1; i<argc; i++) { if (strcmp(argv[i],"-help")==0) { help++; } else if (strcmp(argv[i],"-all")==0) { log_port |= LOG_LOAD|LOG_BLOCK|LOG_PAGE|LOG_BRANCH; } else if (strcmp(argv[i],"-load")==0) { log_port |= LOG_LOAD; } else if (strcmp(argv[i],"-block")==0) { log_port |= LOG_BLOCK; } else if (strcmp(argv[i],"-page")==0) { log_port |= LOG_PAGE; } else if (strcmp(argv[i],"-branch")==0) { log_port |= LOG_BRANCH; } else if (strcmp(argv[i],"-dead")==0) { log_port |= LOG_DEAD; } else if (strcmp(argv[i],"-seed")==0) { if (sscanf(argv[++i],"%ld",&seed)!=1) { fprintf(stderr, "%s: could not read random seed from command line\n", argv[0]); errors++; } else if (seed<1 || seed>((1<<30)-1)) { fprintf(stderr, "%s: random seed must be between 1 and %d\n", argv[0], (1<<30)-1); errors++; } } else if (strcmp(argv[i],"-csv")==0) { output = fopen("output.csv", "w"); if (!output) { fprintf(stderr, "%s: could not open output.csv for writing\n", argv[0]); errors++; } pages = fopen("pages.csv", "w"); if (!pages) { fprintf(stderr, "%s: could not open pages.csv for writing\n", argv[0]); errors++; } } else if (strcmp(argv[i],"-procs")==0) { if (sscanf(argv[++i],"%ld",&procs)!=1) { fprintf(stderr, "%s: could not read number of processors from command line\n", argv[0]); errors++; } else if (procs<1 || procs>MAXPROCESSES) { fprintf(stderr, "%s: number of processors must be between 1 and %d\n", argv[0], MAXPROCESSES); errors++; } } else { fprintf(stderr, "t4: unrecognized argument %s\n", argv[i]); errors++; } } if (errors || help) { fprintf(stderr, "%s usage: %s \n", argv[0], argv[0]); fprintf(stderr, " -all log everything\n"); fprintf(stderr, " -load log loading of processes\n"); fprintf(stderr, " -unload log unloading of processes\n"); fprintf(stderr, " -branch log program branches\n"); fprintf(stderr, " -page log page in and out\n"); fprintf(stderr, " -seed 512 set random seed to 512\n"); fprintf(stderr, " -procs 4 run only four processors\n"); fprintf(stderr, " -dead detect deadlocks\n"); fprintf(stderr, " -csv generate output.csv and pages.csv for graphing\n"); if(errors) { return EXIT_FAILURE; } else { return EXIT_SUCCESS; } } if (seed==0) { seed = (time(NULL)*38491+71831+time(NULL)*time(NULL))&((1<<30)-1); } srand48(seed); sim_log(LOG_ALWAYS,"random seed %d\n", seed); sim_log(LOG_ALWAYS,"using %d processors\n", procs); allinit(); while (!alldone()) { // all processes inactive allstep(); // advance time one tick; if process done, reload allage(); // advance time for page wait variables. callyou(); // call your program sysclock++; // remember new time. allblocked(); // deadlock detection } allscore(); return EXIT_SUCCESS; }
/* compute one step of a process */ static long process_step(int pnum, Process *q) { long pc; long page; long max, min; Branch *b; Bcontext *c; if (!q) return FALSE; pc = q->pc; page = q->pc / PAGESIZE; if (!q->active) { return FALSE; } /* if page swapped out, don't allow to run */ if (q->pages[page]!=0) { if (!q->blocked[page]) { sim_log(LOG_BLOCK,"process=%2d page=%3d blocked\n",pnum,page); if (output) fprintf(output, "%ld,%d,%ld,%ld,%ld,blocked\n", sysclock, pnum, q->pid, q->kind, q->pc); q->blocked[page]=TRUE; } q->block++; return TRUE; } else { if (q->blocked[page]) { sim_log(LOG_BLOCK,"process=%2d page=%3d unblocked\n",pnum,page); if (output) fprintf(output, "%ld,%d,%ld,%ld,%ld,unblocked\n", sysclock,pnum, q->pid, q->kind, q->pc); q->blocked[page]=FALSE; } q->compute++; } /* should I exit */ ASSERT(q->program->nexits>=0 && q->program->nexits<=MAXEXITS); min=0; max=q->program->nexits-1; while (min+1<max) { long mid=(min+max)/2; if (pc==q->program->exits[mid]) { if (output) fprintf(output, "%ld,%d,%ld,%ld,%ld,exit\n", sysclock, pnum, q->pid, q->kind, q->pc); return FALSE; } else if (pc<q->program->exits[mid]) max=mid; else min=mid; } if (pc==q->program->exits[min] || pc==q->program->exits[max]) { if (output) fprintf(output, "%ld,%d,%ld,%ld,%ld,exit\n", sysclock, pnum, q->pid, q->kind, q->pc); return FALSE; } b = q->program->branches; c = q->bcontexts; ASSERT(q->program->nbranches>=0 && q->program->nbranches<=MAXBRANCHES); min=0; max=q->program->nbranches-1; while (min+1<max) { long mid=(min+max)/2; if (pc==b[mid].wherefrom) { process_dobranch(pnum,q,b+mid,c+mid); return TRUE; } else if (pc<b[mid].wherefrom) max=mid; else min=mid; } if (pc==b[min].wherefrom) { process_dobranch(pnum,q,b+min,c+min); return TRUE; } if (pc==b[max].wherefrom) { process_dobranch(pnum,q,b+max,c+max); return TRUE; } q->pc++; /* default action */ if (q->pc<0 || q->pc>q->program->size) { if (output) fprintf(output, "%ld,%d,%ld,%ld,%ld,out_of_range\n", sysclock, pnum, q->pid, q->kind, q->pc); q->pc=0; /* start over */ if (output) fprintf(output, "%ld,%d,%ld,%ld,%ld,restart\n", sysclock, pnum, q->pid, q->kind, q->pc); } return TRUE; }