Line 41... |
Line 41... |
#include <stdint.h>
|
#include <stdint.h>
|
#include <string.h>
|
#include <string.h>
|
#include <ctype.h>
|
#include <ctype.h>
|
#include <assert.h>
|
#include <assert.h>
|
|
|
|
#define R3000_ID (0x00000200)
|
|
|
/** Set to !=0 to disable file logging (much faster simulation) */
|
/** Set to !=0 to disable file logging (much faster simulation) */
|
#define FILE_LOGGING_DISABLED (0)
|
#define FILE_LOGGING_DISABLED (0)
|
/** Define to enable cache simulation (unimplemented) */
|
/** Define to enable cache simulation (unimplemented) */
|
//#define ENABLE_CACHE
|
//#define ENABLE_CACHE
|
|
|
Line 63... |
Line 65... |
uint8_t *mem;
|
uint8_t *mem;
|
char *area_name;
|
char *area_name;
|
} t_block;
|
} t_block;
|
|
|
#define NUM_MEM_BLOCKS (4)
|
#define NUM_MEM_BLOCKS (4)
|
#define NUM_MEM_MAPS (3)
|
#define NUM_MEM_MAPS (4)
|
|
|
/** Definition of a memory map */
|
/** Definition of a memory map */
|
/* FIXME i/o addresses missing, hardcoded */
|
/* FIXME i/o addresses missing, hardcoded */
|
typedef struct s_map {
|
typedef struct s_map {
|
t_block blocks[NUM_MEM_BLOCKS];
|
t_block blocks[NUM_MEM_BLOCKS];
|
Line 94... |
Line 96... |
a 'mirror' effect. All of this simulates how the actual hardware works.
|
a 'mirror' effect. All of this simulates how the actual hardware works.
|
Make sure the blocks don't overlap or the scheme will fail.
|
Make sure the blocks don't overlap or the scheme will fail.
|
*/
|
*/
|
|
|
#define MAP_DEFAULT (0)
|
#define MAP_DEFAULT (0)
|
#define MAP_UCLINUX (1)
|
#define MAP_UCLINUX_BRAM (1) /* debug only */
|
#define MAP_SMALL (2)
|
#define MAP_SMALL (2)
|
|
#define MAP_UCLINUX (3)
|
|
|
t_map memory_maps[NUM_MEM_MAPS] = {
|
t_map memory_maps[NUM_MEM_MAPS] = {
|
{/* Experimental memory map (default) */
|
{/* Experimental memory map (default) */
|
{/* Bootstrap BRAM, read only */
|
{/* Bootstrap BRAM, read only */
|
{VECTOR_RESET, 0x00004800, 0xf8000000, 1, NULL, "Boot BRAM"},
|
{VECTOR_RESET, 0x00004800, 0xf8000000, 1, NULL, "Boot BRAM"},
|
Line 110... |
Line 113... |
/* external flash block */
|
/* external flash block */
|
{0xb0000000, 0x00040000, 0xf8000000, 0, NULL, "Flash"},
|
{0xb0000000, 0x00040000, 0xf8000000, 0, NULL, "Flash"},
|
}
|
}
|
},
|
},
|
|
|
{/* uClinux memory map */
|
{/* uClinux memory map with bootstrap BRAM, debug only, to be removed */
|
{/* Bootstrap BRAM, read only */
|
{/* Bootstrap BRAM, read only */
|
{VECTOR_RESET, 0x00001000, 0xf8000000, 1, NULL, "Boot BRAM"},
|
{VECTOR_RESET, 0x00001000, 0xf8000000, 1, NULL, "Boot BRAM"},
|
/* main external ram block */
|
/* main external ram block */
|
{0x80000000, 0x00200000, 0xf8000000, 0, NULL, "XRAM0"},
|
{0x80000000, 0x00200000, 0xf8000000, 0, NULL, "XRAM0"},
|
{0x00000000, 0x00400000, 0xf8000000, 0, NULL, "XRAM1"},
|
{0x00000000, 0x00400000, 0xf8000000, 0, NULL, "XRAM1"},
|
Line 132... |
Line 135... |
{0x80000000, 0x00001000, 0xf8000000, 0, NULL, "XRAM1"},
|
{0x80000000, 0x00001000, 0xf8000000, 0, NULL, "XRAM1"},
|
/* external flash block */
|
/* external flash block */
|
{0xb0000000, 0x00040000, 0xf8000000, 0, NULL, "Flash"},
|
{0xb0000000, 0x00040000, 0xf8000000, 0, NULL, "Flash"},
|
}
|
}
|
},
|
},
|
|
|
|
{/* uClinux memory map with FLASH and XRAM */
|
|
{/* Flash mapped at two different addresses is actually meant to be
|
|
a single chip (note they have the same size). */
|
|
/* E.g. put the bootloader at 0xbfc00000 and the romfs at 0xb0020000;
|
|
chip offsets will be 0x0 and 0x20000. */
|
|
/* Don't forget there's no address translation here. */
|
|
{0xbfc00000, 0x00400000, 0xf8000000, 1, NULL, "Flash (bootloader)"},
|
|
{0xb0000000, 0x00400000, 0xf8000000, 1, NULL, "Flash (romfs)"},
|
|
/* main external ram block (kernal & user areas ) */
|
|
{0x80000000, 0x00200000, 0xf8000000, 0, NULL, "XRAM (kernel)"},
|
|
{0x00000000, 0x00400000, 0xf8000000, 0, NULL, "XRAM (user)"},
|
|
}
|
|
},
|
};
|
};
|
|
|
|
|
/*---- end of system parameters ----------------------------------------------*/
|
/*---- end of system parameters ----------------------------------------------*/
|
|
|
Line 272... |
Line 289... |
unsigned int next; /**< internal queue head pointer */
|
unsigned int next; /**< internal queue head pointer */
|
FILE *log; /**< text log file or NULL */
|
FILE *log; /**< text log file or NULL */
|
int log_triggered; /**< !=0 if log has been triggered */
|
int log_triggered; /**< !=0 if log has been triggered */
|
uint32_t log_trigger_address; /**< */
|
uint32_t log_trigger_address; /**< */
|
int pr[32]; /**< last value of register bank */
|
int pr[32]; /**< last value of register bank */
|
int hi, lo, epc; /**< last value of internal regs */
|
int hi, lo, epc, status; /**< last value of internal regs */
|
} t_trace;
|
} t_trace;
|
|
|
typedef struct s_state {
|
typedef struct s_state {
|
unsigned failed_assertions; /**< assertion bitmap */
|
unsigned failed_assertions; /**< assertion bitmap */
|
unsigned faulty_address; /**< addr that failed assertion */
|
unsigned faulty_address; /**< addr that failed assertion */
|
Line 346... |
Line 363... |
void log_cycle(t_state *s);
|
void log_cycle(t_state *s);
|
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);
|
void log_failed_assertions(t_state *s);
|
void log_failed_assertions(t_state *s);
|
uint32_t log_enabled(t_state *s);
|
uint32_t log_enabled(t_state *s);
|
void trigger_log(t_state *s);
|
void trigger_log(t_state *s);
|
|
void print_opcode_fields(uint32_t opcode);
|
|
|
int32_t parse_cmd_line(uint32_t argc, char **argv, t_args *args);
|
int32_t parse_cmd_line(uint32_t argc, char **argv, t_args *args);
|
void usage(void);
|
void usage(void);
|
|
|
/* CPU model */
|
/* CPU model */
|
Line 876... |
Line 894... |
case 0x32:/*TLT*/ break;
|
case 0x32:/*TLT*/ break;
|
case 0x33:/*TLTU*/ break;
|
case 0x33:/*TLTU*/ break;
|
case 0x34:/*TEQ*/ break;
|
case 0x34:/*TEQ*/ break;
|
case 0x36:/*TNE*/ break;
|
case 0x36:/*TNE*/ break;
|
default: printf("ERROR0(*0x%x~0x%x)\n", s->pc, opcode);
|
default: printf("ERROR0(*0x%x~0x%x)\n", s->pc, opcode);
|
|
/* FIXME should trap unknown opcode */
|
s->wakeup=1;
|
s->wakeup=1;
|
}
|
}
|
break;
|
break;
|
case 0x01:/*REGIMM*/
|
case 0x01:/*REGIMM*/
|
switch(rt){
|
switch(rt){
|
Line 908... |
Line 927... |
case 0x0c:/*ANDI*/ r[rt]=r[rs]&imm; break;
|
case 0x0c:/*ANDI*/ r[rt]=r[rs]&imm; break;
|
case 0x0d:/*ORI*/ r[rt]=r[rs]|imm; break;
|
case 0x0d:/*ORI*/ r[rt]=r[rs]|imm; break;
|
case 0x0e:/*XORI*/ r[rt]=r[rs]^imm; break;
|
case 0x0e:/*XORI*/ r[rt]=r[rs]^imm; break;
|
case 0x0f:/*LUI*/ r[rt]=(imm<<16); break;
|
case 0x0f:/*LUI*/ r[rt]=(imm<<16); break;
|
case 0x10:/*COP0*/
|
case 0x10:/*COP0*/
|
|
if(s->status & 0x02){ /* kernel mode? */
|
if((opcode & (1<<23)) == 0){ //move from CP0 (mfc0)
|
if((opcode & (1<<23)) == 0){ //move from CP0 (mfc0)
|
switch(rd){
|
switch(rd){
|
case 12: r[rt]=s->status & 0xffff; break;
|
case 12: r[rt]=s->status & 0x0000003f; break;
|
case 13: r[rt]=s->cp0_cause; break;
|
case 13: r[rt]=s->cp0_cause; break;
|
case 14: r[rt]=s->epc; break;
|
case 14: r[rt]=s->epc; break;
|
case 15: r[rt]=0x00000200; break;
|
case 15: r[rt]=R3000_ID; break;
|
default:
|
default:
|
//printf("mfco [%02d]\n", rd);
|
//printf("mfco [%02d]\n", rd);
|
break;
|
break;
|
}
|
}
|
}
|
}
|
else{ //move to CP0 (mtc0)
|
else{ //move to CP0 (mtc0)
|
/* FIXME check CF= reg address */
|
/* FIXME check CF= reg address */
|
s->status=r[rt];
|
s->status=r[rt] & 0x0003003f; /* mask W/O bits */
|
if(s->processId && (r[rt]&2)){
|
if(s->processId && (r[rt]&2)){
|
s->userMode|=r[rt]&2;
|
s->userMode|=r[rt]&2;
|
//printf("CpuStatus=%d %d %d\n", r[rt], s->status, s->userMode);
|
//printf("CpuStatus=%d %d %d\n", r[rt], s->status, s->userMode);
|
//s->wakeup = 1;
|
//s->wakeup = 1;
|
//printf("pc=0x%x\n", epc);
|
//printf("pc=0x%x\n", epc);
|
}
|
}
|
}
|
}
|
|
}
|
|
else{
|
|
/* tried to execute mtc* or mfc* in user mode: trap */
|
|
trap_cause = 11; /* unavailable coprocessor */
|
|
s->exceptionId=1;
|
|
}
|
break;
|
break;
|
case 0x11:/*COP1*/ unimplemented(s,"COP1");
|
case 0x11:/*COP1*/ unimplemented(s,"COP1");
|
break;
|
break;
|
// case 0x12:/*COP2*/ break;
|
// case 0x12:/*COP2*/ break;
|
// case 0x13:/*COP3*/ break;
|
// case 0x13:/*COP3*/ break;
|
Line 993... |
Line 1019... |
// case 0x3f:/*SDC3*/ break;
|
// case 0x3f:/*SDC3*/ break;
|
default:
|
default:
|
;
|
;
|
/* FIXME should trap unimplemented opcodes */
|
/* FIXME should trap unimplemented opcodes */
|
/* FIXME newlib */
|
/* FIXME newlib */
|
printf("ERROR2 address=0x%x opcode=0x%x\n", s->pc, opcode);
|
printf("ERROR2 address=0x%x opcode=0x%x -- ", epc, opcode);
|
|
print_opcode_fields(opcode);
|
|
printf("\n");
|
s->wakeup=1;
|
s->wakeup=1;
|
}
|
}
|
|
|
/* adjust next PC if this was a ajump instruction */
|
/* 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;
|
Line 1014... |
Line 1042... |
/* load delay slots not simulated */
|
/* load delay slots not simulated */
|
|
|
/* Handle exceptions */
|
/* Handle exceptions */
|
if(s->exceptionId){
|
if(s->exceptionId){
|
r[rt] = rSave;
|
r[rt] = rSave;
|
s->cp0_cause = (s->delay_slot & 0x1) << 31 | (trap_cause & 0x1f);
|
/* set cause field ... */
|
|
s->cp0_cause = (s->delay_slot & 0x1) << 31 | (trap_cause & 0x1f) << 2;
|
|
/* ...save previous KU/IE flags in SR... */
|
|
s->status = (s->status & 0xffffffc3) | ((s->status & 0x0f) << 2);
|
|
/* ...and raise KU(EXL) kernel mode flag */
|
|
s->status |= 0x02;
|
/* adjust epc if we (i.e. the victim instruction) are in a delay slot */
|
/* adjust epc if we (i.e. the victim instruction) are in a delay slot */
|
if(s->delay_slot){
|
if(s->delay_slot){
|
epc = epc - 4;
|
epc = epc - 4;
|
}
|
}
|
s->epc = epc;
|
s->epc = epc;
|
Line 1040... |
Line 1073... |
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;
|
}
|
}
|
|
|
|
/** Print opcode fields for easier debugging */
|
|
void print_opcode_fields(uint32_t opcode){
|
|
uint32_t field;
|
|
|
|
field = (opcode >> 26)&0x3f;
|
|
printf("%02x:", field);
|
|
field = (opcode >> 21)&0x1f;
|
|
printf("%02x:", field);
|
|
field = (opcode >> 16)&0x1f;
|
|
printf("%02x:", field);
|
|
field = (opcode >> 11)&0x1f;
|
|
printf("%02x:", field);
|
|
field = (opcode >> 6)&0x1f;
|
|
printf("%02x:", field);
|
|
field = (opcode >> 0)&0x3f;
|
|
printf("%02x", field);
|
|
}
|
|
|
|
|
/** Dump CPU state to console */
|
/** Dump CPU state to console */
|
void show_state(t_state *s){
|
void show_state(t_state *s){
|
int i,j;
|
int i,j;
|
printf("pid=%d userMode=%d, epc=0x%x\n", s->processId, s->userMode, s->epc);
|
printf("pid=%d userMode=%d, epc=0x%x\n", s->processId, s->userMode, s->epc);
|
printf("hi=0x%08x lo=0x%08x\n", s->hi, s->lo);
|
printf("hi=0x%08x lo=0x%08x\n", s->hi, s->lo);
|
Line 1370... |
Line 1422... |
if(s->hi != s->t.hi){
|
if(s->hi != s->t.hi){
|
//fprintf(s->t.log, "(%08X) [HI]=%08X\n", log_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;
|
|
|
/* */
|
/* Catch changes in EPC by direct write (mtc0) and by exception */
|
/* 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", log_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;
|
|
|
|
if(s->status != s->t. status){
|
|
fprintf(s->t.log, "(%08X) [SR]=%08X\n", log_pc, s->status);
|
|
}
|
|
s->t.status = s->status;
|
}
|
}
|
}
|
}
|
|
|
/** Frees debug buffers and closes log file */
|
/** Frees debug buffers and closes log file */
|
void close_trace_buffer(t_state *s){
|
void close_trace_buffer(t_state *s){
|
Line 1435... |
Line 1491... |
|
|
void reset_cpu(t_state *s){
|
void reset_cpu(t_state *s){
|
s->pc = VECTOR_RESET; /* reset start vector */
|
s->pc = VECTOR_RESET; /* reset start vector */
|
s->delay_slot = 0;
|
s->delay_slot = 0;
|
s->failed_assertions = 0; /* no failed assertions pending */
|
s->failed_assertions = 0; /* no failed assertions pending */
|
|
s->status = 0x02; /* kernel mode, interrupts disabled */
|
|
/* init trace struct to prevent spurious logs */
|
|
s->t.status = s->status;
|
}
|
}
|
|
|
void unimplemented(t_state *s, const char *txt){
|
void unimplemented(t_state *s, const char *txt){
|
/* FIXME unimplemented opcode trap */
|
/* FIXME unimplemented opcode trap */
|
printf("UNIMPLEMENTED: %s\n", txt);
|
printf("UNIMPLEMENTED: %s\n", txt);
|