Line 196... |
Line 196... |
int delay_slot; /**< !=0 if prev. instruction was a branch */
|
int delay_slot; /**< !=0 if prev. instruction was a branch */
|
|
|
int r[32];
|
int r[32];
|
int opcode;
|
int opcode;
|
int pc, pc_next, epc;
|
int pc, pc_next, epc;
|
|
uint32_t op_addr; /**< address of opcode being simulated */
|
unsigned int hi;
|
unsigned int hi;
|
unsigned int lo;
|
unsigned int lo;
|
int status;
|
int status;
|
unsigned cp0_cause;
|
unsigned cp0_cause;
|
int userMode;
|
int userMode;
|
Line 262... |
Line 263... |
void reset_cpu(t_state *s);
|
void reset_cpu(t_state *s);
|
|
|
/* Hardware simulation */
|
/* Hardware simulation */
|
int mem_read(t_state *s, int size, unsigned int address, int log);
|
int mem_read(t_state *s, int size, unsigned int address, int log);
|
void mem_write(t_state *s, int size, unsigned address, unsigned value, int log);
|
void mem_write(t_state *s, int size, unsigned address, unsigned value, int log);
|
void start_load(t_state *s, int rt, int data);
|
void start_load(t_state *s, uint32_t addr, int rt, int data);
|
|
|
|
|
/*---- Local functions -------------------------------------------------------*/
|
/*---- Local functions -------------------------------------------------------*/
|
|
|
/** Log to file a memory read operation (not including target reg change) */
|
/** Log to file a memory read operation (not including target reg change) */
|
void log_read(t_state *s, int full_address, int word_value, int size, int log){
|
void log_read(t_state *s, int full_address, int word_value, int size, int log){
|
if(s->t.log!=NULL && log!=0){
|
if(s->t.log!=NULL && log!=0){
|
if(size==4){ size=0x04; }
|
|
else if(size==2){ size=0x02; }
|
|
else { size=0x01; }
|
|
fprintf(s->t.log, "(%08X) [%08X] <**>=%08X RD\n",
|
fprintf(s->t.log, "(%08X) [%08X] <**>=%08X RD\n",
|
s->pc, full_address, /*size,*/ word_value);
|
s->op_addr, full_address, word_value);
|
}
|
}
|
}
|
}
|
|
|
/** Read memory, optionally logging */
|
/** Read memory, optionally logging */
|
int mem_read(t_state *s, int size, unsigned int address, int log){
|
int mem_read(t_state *s, int size, unsigned int address, int log){
|
Line 287... |
Line 285... |
|
|
s->irqStatus |= IRQ_UART_WRITE_AVAILABLE;
|
s->irqStatus |= IRQ_UART_WRITE_AVAILABLE;
|
switch(address){
|
switch(address){
|
case UART_READ:
|
case UART_READ:
|
word_value = 0x00000001;
|
word_value = 0x00000001;
|
log_read(s, full_address, word_value, size, log);
|
//log_read(s, full_address, word_value, size, log);
|
return word_value;
|
return word_value;
|
/* FIXME Take input from text file */
|
/* FIXME Take input from text file */
|
/*
|
/*
|
if(kbhit()){
|
if(kbhit()){
|
HWMemory[0] = getch();
|
HWMemory[0] = getch();
|
Line 309... |
Line 307... |
s->irqStatus |= IRQ_UART_READ_AVAILABLE;
|
s->irqStatus |= IRQ_UART_READ_AVAILABLE;
|
return s->irqStatus;
|
return s->irqStatus;
|
*/
|
*/
|
/* FIXME Optionally simulate UART TX delay */
|
/* FIXME Optionally simulate UART TX delay */
|
word_value = 0x00000003; /* Ready to TX and RX */
|
word_value = 0x00000003; /* Ready to TX and RX */
|
log_read(s, full_address, word_value, size, log);
|
//log_read(s, full_address, word_value, size, log);
|
return word_value;
|
return word_value;
|
case MMU_PROCESS_ID:
|
case MMU_PROCESS_ID:
|
return s->processId;
|
return s->processId;
|
case MMU_FAULT_ADDR:
|
case MMU_FAULT_ADDR:
|
return s->faultAddr;
|
return s->faultAddr;
|
Line 378... |
Line 376... |
default:
|
default:
|
/* FIXME this is a bug, should quit */
|
/* FIXME this is a bug, should quit */
|
printf("ERROR");
|
printf("ERROR");
|
}
|
}
|
|
|
log_read(s, full_address, word_value, size, log);
|
//log_read(s, full_address, value, size, log);
|
return(value);
|
return(value);
|
}
|
}
|
|
|
/** Write memory */
|
/** Write memory */
|
void mem_write(t_state *s, int size, unsigned address, unsigned value, int log){
|
void mem_write(t_state *s, int size, unsigned address, unsigned value, int log){
|
Line 428... |
Line 426... |
printf("BUG: mem write size invalid (%08x)\n", s->pc);
|
printf("BUG: mem write size invalid (%08x)\n", s->pc);
|
exit(2);
|
exit(2);
|
}
|
}
|
|
|
fprintf(s->t.log, "(%08X) [%08X] |%02X|=%08X WR\n",
|
fprintf(s->t.log, "(%08X) [%08X] |%02X|=%08X WR\n",
|
s->pc, address, mask, dvalue);
|
s->op_addr, address, mask, dvalue);
|
}
|
}
|
|
|
switch(address){
|
switch(address){
|
case UART_WRITE:
|
case UART_WRITE:
|
putch(value);
|
putch(value);
|
Line 466... |
Line 464... |
}
|
}
|
if(!ptr){
|
if(!ptr){
|
/* address out of mapped blocks: log and return zero */
|
/* address out of mapped blocks: log and return zero */
|
if(s->t.log!=NULL && log!=0){
|
if(s->t.log!=NULL && log!=0){
|
fprintf(s->t.log, "(%08X) [%08X] |%02X|=%08X WR UNMAPPED\n",
|
fprintf(s->t.log, "(%08X) [%08X] |%02X|=%08X WR UNMAPPED\n",
|
s->pc, address, mask, dvalue);
|
s->op_addr, address, mask, dvalue);
|
}
|
}
|
return;
|
return;
|
}
|
}
|
|
|
switch(size){
|
switch(size){
|
Line 564... |
Line 562... |
*hi = rh;
|
*hi = rh;
|
*lo = rl;
|
*lo = rl;
|
}
|
}
|
|
|
/** Load data from memory (used to simulate load delay slots) */
|
/** Load data from memory (used to simulate load delay slots) */
|
void start_load(t_state *s, int rt, int data){
|
void start_load(t_state *s, uint32_t addr, int rt, int data){
|
/* load delay slot not simulated */
|
/* load delay slot not simulated */
|
|
log_read(s, addr, data, 1, 1);
|
s->r[rt] = data;
|
s->r[rt] = data;
|
}
|
}
|
|
|
/** Execute one cycle of the CPU (including any interlock stall cycles) */
|
/** Execute one cycle of the CPU (including any interlock stall cycles) */
|
void cycle(t_state *s, int show_mode){
|
void cycle(t_state *s, int show_mode){
|
Line 580... |
Line 579... |
int imm_shift, branch=0, lbranch=2, skip2=0;
|
int imm_shift, branch=0, lbranch=2, skip2=0;
|
int *r=s->r;
|
int *r=s->r;
|
unsigned int *u=(unsigned int*)s->r;
|
unsigned int *u=(unsigned int*)s->r;
|
unsigned int ptr, epc, rSave;
|
unsigned int ptr, epc, rSave;
|
|
|
if(!show_mode){
|
|
/* if we're NOT showing output to console, log state of CPU to file */
|
|
log_cycle(s);
|
|
}
|
|
|
|
opcode = mem_read(s, 4, s->pc, 0);
|
opcode = mem_read(s, 4, s->pc, 0);
|
op = (opcode >> 26) & 0x3f;
|
op = (opcode >> 26) & 0x3f;
|
rs = (opcode >> 21) & 0x1f;
|
rs = (opcode >> 21) & 0x1f;
|
rt = (opcode >> 16) & 0x1f;
|
rt = (opcode >> 16) & 0x1f;
|
rd = (opcode >> 11) & 0x1f;
|
rd = (opcode >> 11) & 0x1f;
|
Line 633... |
Line 627... |
and of the program and quit. */
|
and of the program and quit. */
|
if(s->pc == s->pc_next+4){
|
if(s->pc == s->pc_next+4){
|
printf("\n\nEndless loop at 0x%08x\n\n", s->pc-4);
|
printf("\n\nEndless loop at 0x%08x\n\n", s->pc-4);
|
s->wakeup = 1;
|
s->wakeup = 1;
|
}
|
}
|
|
s->op_addr = s->pc;
|
s->pc = s->pc_next;
|
s->pc = s->pc_next;
|
s->pc_next = s->pc_next + 4;
|
s->pc_next = s->pc_next + 4;
|
if(s->skip){
|
if(s->skip){
|
s->skip = 0;
|
s->skip = 0;
|
return;
|
return;
|
Line 749... |
Line 744... |
case 0x15:/*BNEL*/ lbranch=r[rs]!=r[rt]; break;
|
case 0x15:/*BNEL*/ lbranch=r[rs]!=r[rt]; break;
|
case 0x16:/*BLEZL*/ lbranch=r[rs]<=0; break;
|
case 0x16:/*BLEZL*/ lbranch=r[rs]<=0; break;
|
case 0x17:/*BGTZL*/ lbranch=r[rs]>0; break;
|
case 0x17:/*BGTZL*/ lbranch=r[rs]>0; break;
|
// case 0x1c:/*MAD*/ break; /*IV*/
|
// case 0x1c:/*MAD*/ break; /*IV*/
|
case 0x20:/*LB*/ //r[rt]=(signed char)mem_read(s,1,ptr,1); break;
|
case 0x20:/*LB*/ //r[rt]=(signed char)mem_read(s,1,ptr,1); break;
|
start_load(s, rt,(signed char)mem_read(s,1,ptr,1));
|
start_load(s, ptr, rt,(signed char)mem_read(s,1,ptr,1));
|
break;
|
break;
|
|
|
case 0x21:/*LH*/ //r[rt]=(signed short)mem_read(s,2,ptr,1); break;
|
case 0x21:/*LH*/ //r[rt]=(signed short)mem_read(s,2,ptr,1); break;
|
start_load(s, rt, (signed short)mem_read(s,2,ptr,1));
|
start_load(s, ptr, rt, (signed short)mem_read(s,2,ptr,1));
|
break;
|
break;
|
case 0x22:/*LWL*/ //target=8*(ptr&3);
|
case 0x22:/*LWL*/ //target=8*(ptr&3);
|
//r[rt]=(r[rt]&~(0xffffffff<<target))|
|
//r[rt]=(r[rt]&~(0xffffffff<<target))|
|
// (mem_read(s,4,ptr&~3)<<target); break;
|
// (mem_read(s,4,ptr&~3)<<target); break;
|
break;
|
break;
|
case 0x23:/*LW*/ //r[rt]=mem_read(s,4,ptr,1); break;
|
case 0x23:/*LW*/ //r[rt]=mem_read(s,4,ptr,1); break;
|
start_load(s, rt, mem_read(s,4,ptr,1));
|
start_load(s, ptr, rt, mem_read(s,4,ptr,1));
|
break;
|
break;
|
case 0x24:/*LBU*/ //r[rt]=(unsigned char)mem_read(s,1,ptr,1); break;
|
case 0x24:/*LBU*/ //r[rt]=(unsigned char)mem_read(s,1,ptr,1); break;
|
start_load(s, rt, (unsigned char)mem_read(s,1,ptr,1));
|
start_load(s, ptr, rt, (unsigned char)mem_read(s,1,ptr,1));
|
break;
|
break;
|
case 0x25:/*LHU*/ //r[rt]= (unsigned short)mem_read(s,2,ptr,1);
|
case 0x25:/*LHU*/ //r[rt]= (unsigned short)mem_read(s,2,ptr,1);
|
start_load(s, rt, (unsigned short)mem_read(s,2,ptr,1));
|
start_load(s, ptr, rt, (unsigned short)mem_read(s,2,ptr,1));
|
break;
|
break;
|
case 0x26:/*LWR*/ //target=32-8*(ptr&3);
|
case 0x26:/*LWR*/ //target=32-8*(ptr&3);
|
//r[rt]=(r[rt]&~((unsigned int)0xffffffff>>target))|
|
//r[rt]=(r[rt]&~((unsigned int)0xffffffff>>target))|
|
//((unsigned int)mem_read(s,4,ptr&~3)>>target);
|
//((unsigned int)mem_read(s,4,ptr&~3)>>target);
|
break;
|
break;
|
Line 782... |
Line 777... |
//mem_write(s,1,ptr+3,r[rt]); break;
|
//mem_write(s,1,ptr+3,r[rt]); break;
|
case 0x2b:/*SW*/ mem_write(s,4,ptr,r[rt],1); break;
|
case 0x2b:/*SW*/ mem_write(s,4,ptr,r[rt],1); break;
|
case 0x2e:/*SWR*/ break; //FIXME
|
case 0x2e:/*SWR*/ break; //FIXME
|
case 0x2f:/*CACHE*/ break;
|
case 0x2f:/*CACHE*/ break;
|
case 0x30:/*LL*/ //r[rt]=mem_read(s,4,ptr); break;
|
case 0x30:/*LL*/ //r[rt]=mem_read(s,4,ptr); break;
|
start_load(s, rt, mem_read(s,4,ptr,1));
|
start_load(s, ptr, rt, mem_read(s,4,ptr,1));
|
break;
|
break;
|
// case 0x31:/*LWC1*/ break;
|
// case 0x31:/*LWC1*/ break;
|
// case 0x32:/*LWC2*/ break;
|
// case 0x32:/*LWC2*/ break;
|
// case 0x33:/*LWC3*/ break;
|
// case 0x33:/*LWC3*/ break;
|
// case 0x35:/*LDC1*/ break;
|
// case 0x35:/*LDC1*/ break;
|
Line 803... |
Line 798... |
default:
|
default:
|
/* FIXME should trap unimplemented opcodes */
|
/* FIXME should trap unimplemented opcodes */
|
printf("ERROR2 address=0x%x opcode=0x%x\n", s->pc, opcode);
|
printf("ERROR2 address=0x%x opcode=0x%x\n", s->pc, opcode);
|
s->wakeup=1;
|
s->wakeup=1;
|
}
|
}
|
|
|
|
/* adjust next PC if this was a ajump instruction */
|
s->pc_next += (branch || lbranch == 1) ? imm_shift : 0;
|
s->pc_next += (branch || lbranch == 1) ? imm_shift : 0;
|
s->pc_next &= ~3;
|
s->pc_next &= ~3;
|
s->skip = (lbranch == 0) | skip2;
|
s->skip = (lbranch == 0) | skip2;
|
|
|
/* If there was trouble (failed assertions), log it */
|
/* If there was trouble (failed assertions), log it */
|
Line 832... |
Line 829... |
s->exceptionId = 0;
|
s->exceptionId = 0;
|
s->userMode = 0;
|
s->userMode = 0;
|
//s->wakeup = 1;
|
//s->wakeup = 1;
|
}
|
}
|
|
|
|
/* if we're NOT showing output to console, log state of CPU to file */
|
|
if(!show_mode){
|
|
log_cycle(s);
|
|
}
|
|
|
|
|
|
|
/* if this instruction was any kind of branch that actually jumped, then
|
/* if this instruction was any kind of branch that actually jumped, then
|
the next instruction will be in a delay slot. Remember it. */
|
the next instruction will be in a delay slot. Remember it. */
|
delay_slot = ((lbranch==1) || branch || delay_slot);
|
delay_slot = ((lbranch==1) || branch || delay_slot);
|
s->delay_slot = delay_slot;
|
s->delay_slot = delay_slot;
|
}
|
}
|
Line 1077... |
Line 1081... |
|
|
/** Logs last cycle's activity (changes in state and/or loads/stores) */
|
/** Logs last cycle's activity (changes in state and/or loads/stores) */
|
void log_cycle(t_state *s){
|
void log_cycle(t_state *s){
|
static unsigned int last_pc = 0;
|
static unsigned int last_pc = 0;
|
int i;
|
int i;
|
|
uint32_t log_pc;
|
|
|
/* store PC in trace buffer only if there was a jump */
|
/* store PC in trace buffer only if there was a jump */
|
if(s->pc != (last_pc+4)){
|
if(s->pc != (last_pc+4)){
|
s->t.buf[s->t.next] = s->pc;
|
s->t.buf[s->t.next] = s->pc;
|
s->t.next = (s->t.next + 1) % TRACE_BUFFER_SIZE;
|
s->t.next = (s->t.next + 1) % TRACE_BUFFER_SIZE;
|
}
|
}
|
last_pc = s->pc;
|
last_pc = s->pc;
|
|
|
/* if file logging is enabled, dump a trace log to file */
|
/* if file logging is enabled, dump a trace log to file */
|
if(s->t.log!=NULL){
|
if(s->t.log!=NULL){
|
|
log_pc = s->op_addr;
|
|
|
for(i=0;i<32;i++){
|
for(i=0;i<32;i++){
|
if(s->t.pr[i] != s->r[i]){
|
if(s->t.pr[i] != s->r[i]){
|
fprintf(s->t.log, "(%08X) [%02X]=%08X\n", s->pc, i, s->r[i]);
|
fprintf(s->t.log, "(%08X) [%02X]=%08X\n", log_pc, i, s->r[i]);
|
}
|
}
|
s->t.pr[i] = s->r[i];
|
s->t.pr[i] = s->r[i];
|
}
|
}
|
if(s->lo != s->t.lo){
|
if(s->lo != s->t.lo){
|
fprintf(s->t.log, "(%08X) [LO]=%08X\n", s->pc, s->lo);
|
fprintf(s->t.log, "(%08X) [LO]=%08X\n", log_pc, s->lo);
|
}
|
}
|
s->t.lo = s->lo;
|
s->t.lo = s->lo;
|
|
|
if(s->hi != s->t.hi){
|
if(s->hi != s->t.hi){
|
fprintf(s->t.log, "(%08X) [HI]=%08X\n", s->pc, s->hi);
|
fprintf(s->t.log, "(%08X) [HI]=%08X\n", log_pc, s->hi);
|
}
|
}
|
s->t.hi = s->hi;
|
s->t.hi = s->hi;
|
|
|
|
/* */
|
|
/* FIXME epc may change by direct write too, handle case */
|
if(s->epc != s->t.epc){
|
if(s->epc != s->t.epc){
|
fprintf(s->t.log, "(%08X) [EP]=%08X\n", s->pc, s->epc);
|
fprintf(s->t.log, "(%08X) [EP]=%08X\n", log_pc, s->epc);
|
}
|
}
|
s->t.epc = s->epc;
|
s->t.epc = s->epc;
|
}
|
}
|
}
|
}
|
|
|