Line 49... |
Line 49... |
//#define ENABLE_CACHE
|
//#define ENABLE_CACHE
|
|
|
|
|
/*---- Definition of simulated system parameters -----------------------------*/
|
/*---- Definition of simulated system parameters -----------------------------*/
|
|
|
|
/* Uncomment to simulate Plasma behavior (vectors & memory mapping) */
|
|
//#define SIMULATE_PLASMA (1)
|
|
|
|
#ifdef SIMULATE_PLASMA
|
|
|
#define VECTOR_RESET (0x00000000)
|
#define VECTOR_RESET (0x00000000)
|
#define VECTOR_TRAP (0x0000003c)
|
#define VECTOR_TRAP (0x0000003c)
|
|
|
|
#else
|
|
|
|
#define VECTOR_RESET (0xbfc00000)
|
|
#define VECTOR_TRAP (0xbfc00180)
|
|
|
|
#endif
|
|
|
|
/** Definition of a memory block */
|
typedef struct s_block {
|
typedef struct s_block {
|
uint32_t start;
|
uint32_t start;
|
uint32_t size;
|
uint32_t size;
|
uint32_t mask;
|
uint32_t mask;
|
|
uint32_t read_only;
|
uint8_t *mem;
|
uint8_t *mem;
|
char *name;
|
char *area_name;
|
} t_block;
|
} t_block;
|
|
|
|
|
/* Here's where we define the memory areas (blocks) of the system.
|
/* Here's where we define the memory areas (blocks) of the system.
|
|
|
|
The blocks should be defined in this order: BRAM, XRAM, FLASH
|
|
|
|
BRAM is FPGA block ram initialized with bootstrap code
|
|
XRAM is external SRAM
|
|
FLASH is external flash
|
|
|
|
Give any area a size of 0x0 to leave it unused.
|
|
|
|
When a binary file is specified in the cmd line for one of these areas, it
|
|
will be used to initialize it, checking bounds.
|
|
|
|
|
Memory decoding is done in the order the blocks are defined; the address
|
Memory decoding is done in the order the blocks are defined; the address
|
is anded with field .mask and then compared to field .start. If they match
|
is anded with field .mask and then compared to field .start. If they match
|
the address modulo the field .size is used to index the memory block, giving
|
the address modulo the field .size is used to index the memory block, giving
|
a 'mirror' effect. All of this simulates the behavior of the actual hardware.
|
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 NUM_MEM_BLOCKS (2)
|
#define NUM_MEM_BLOCKS (3)
|
|
|
|
#ifdef SIMULATE_PLASMA
|
|
|
t_block default_blocks[NUM_MEM_BLOCKS] = {
|
t_block memory_map_default[NUM_MEM_BLOCKS] = {
|
/* meant as bootstrap block, though it's read/write */
|
/* meant as bootstrap block, though it's read/write */
|
{VECTOR_RESET, 0x00010000, 0xf0000000, NULL, "Boot"},
|
{VECTOR_RESET, 0x00000800, 0xf0000000, 1, NULL, "Boot BRAM"},
|
/* main ram block */
|
/* main external ram block */
|
{0x80000000, 0x00001000, 0xf0000000, NULL, "Data"}
|
{0x80000000, 0x00001000, 0xf0000000, 0, NULL, "XRAM"},
|
|
/* external flash block -- not used in plasma simulation */
|
|
{0xb0000000, 0x00000000, 0xf0000000, 0, NULL, "Flash"},
|
};
|
};
|
|
|
|
#else
|
|
|
|
t_block memory_map_default[NUM_MEM_BLOCKS] = {
|
|
/* Bootstrap BRAM, read only */
|
|
{VECTOR_RESET, 0x00004800, 0xf8000000, 1, NULL, "Boot BRAM"},
|
|
/* main external ram block */
|
|
{0x00000000, 0x00008000, 0xf8000000, 0, NULL, "XRAM"},
|
|
/* external flash block */
|
|
{0xb0000000, 0x00010000, 0xf8000000, 0, NULL, "Flash"},
|
|
};
|
|
|
|
#endif
|
|
|
|
/*---- end of system parameters ----------------------------------------------*/
|
|
|
|
|
|
/** Values for the command line arguments */
|
|
typedef struct s_args {
|
|
char *bin_filename[NUM_MEM_BLOCKS]; /**< bin file to load to area or null */
|
|
} t_args;
|
|
/** Parse cmd line args globally accessible */
|
|
t_args cmd_line_args;
|
|
|
|
|
|
/*---- Endianess conversion macros -------------------------------------------*/
|
|
|
#define ntohs(A) ( ((A)>>8) | (((A)&0xff)<<8) )
|
#define ntohs(A) ( ((A)>>8) | (((A)&0xff)<<8) )
|
#define htons(A) ntohs(A)
|
#define htons(A) ntohs(A)
|
#define ntohl(A) ( ((A)>>24) | (((A)&0xff0000)>>8) | (((A)&0xff00)<<8) | ((A)<<24) )
|
#define ntohl(A) ( ((A)>>24) | (((A)&0xff0000)>>8) | (((A)&0xff00)<<8) | ((A)<<24) )
|
#define htonl(A) ntohl(A)
|
#define htonl(A) ntohl(A)
|
Line 255... |
Line 310... |
void dump_trace_buffer(t_state *s);
|
void dump_trace_buffer(t_state *s);
|
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);
|
|
|
|
int32_t parse_cmd_line(uint32_t argc, char **argv, t_args *args);
|
|
void usage(void);
|
|
|
/* CPU model */
|
/* CPU model */
|
void free_cpu(t_state *s);
|
void free_cpu(t_state *s);
|
int init_cpu(t_state *s);
|
int init_cpu(t_state *s);
|
void reset_cpu(t_state *s);
|
void reset_cpu(t_state *s);
|
|
|
Line 318... |
Line 376... |
}
|
}
|
|
|
/* point ptr to the byte in the block, or NULL is the address is unmapped */
|
/* point ptr to the byte in the block, or NULL is the address is unmapped */
|
ptr = 0;
|
ptr = 0;
|
for(i=0;i<NUM_MEM_BLOCKS;i++){
|
for(i=0;i<NUM_MEM_BLOCKS;i++){
|
if((address & s->blocks[i].mask) == s->blocks[i].start){
|
if((address & s->blocks[i].mask) ==
|
|
(s->blocks[i].start & s->blocks[i].mask)){
|
ptr = (unsigned)(s->blocks[i].mem) +
|
ptr = (unsigned)(s->blocks[i].mem) +
|
((address - s->blocks[i].start) % s->blocks[i].size);
|
((address - s->blocks[i].start) % s->blocks[i].size);
|
break;
|
break;
|
}
|
}
|
}
|
}
|
Line 448... |
Line 507... |
//printf("processId=%d\n", value);
|
//printf("processId=%d\n", value);
|
s->processId = value;
|
s->processId = value;
|
return;
|
return;
|
}
|
}
|
|
|
//ptr = (unsigned int)s->mem + (address % MEM_SIZE);
|
|
if(address >= 0x80000000){
|
|
ptr = 1;
|
|
}
|
|
ptr = 0;
|
ptr = 0;
|
for(i=0;i<NUM_MEM_BLOCKS;i++){
|
for(i=0;i<NUM_MEM_BLOCKS;i++){
|
if((address & s->blocks[i].mask) == s->blocks[i].start){
|
if((address & s->blocks[i].mask) ==
|
|
(s->blocks[i].start & s->blocks[i].mask)){
|
ptr = (unsigned)(s->blocks[i].mem) +
|
ptr = (unsigned)(s->blocks[i].mem) +
|
((address - s->blocks[i].start) % s->blocks[i].size);
|
((address - s->blocks[i].start) % s->blocks[i].size);
|
|
|
|
if(s->blocks[i].read_only){
|
|
if(s->t.log!=NULL && log!=0){
|
|
fprintf(s->t.log, "(%08X) [%08X] |%02X|=%08X WR READ ONLY\n",
|
|
s->op_addr, address, mask, dvalue);
|
|
return;
|
|
}
|
|
}
|
break;
|
break;
|
}
|
}
|
}
|
}
|
if(!ptr){
|
if(!ptr){
|
/* address out of mapped blocks: log and return zero */
|
/* address out of mapped blocks: log and return zero */
|
Line 822... |
Line 886... |
/* 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;
|
s->pc_next = 0x3c;
|
s->pc_next = VECTOR_TRAP;
|
s->skip = 1;
|
s->skip = 1;
|
s->exceptionId = 0;
|
s->exceptionId = 0;
|
s->userMode = 0;
|
s->userMode = 0;
|
//s->wakeup = 1;
|
//s->wakeup = 1;
|
}
|
}
|
Line 956... |
Line 1020... |
}
|
}
|
}
|
}
|
}
|
}
|
|
|
/** Read binary code and data files */
|
/** Read binary code and data files */
|
int read_program(t_state *s, uint32_t num_files, char **file_names){
|
int read_binary_files(t_state *s, t_args *args){
|
FILE *in;
|
FILE *in;
|
uint32_t bytes, i, files_read=0;
|
uint32_t bytes, i, files_read=0;
|
|
|
for(i=0;i<NUM_MEM_BLOCKS;i++){
|
for(i=0;i<NUM_MEM_BLOCKS;i++){
|
if(i<num_files){
|
if(args->bin_filename[i]!=NULL){
|
in = fopen(file_names[i], "rb");
|
|
|
in = fopen(args->bin_filename[i], "rb");
|
if(in == NULL){
|
if(in == NULL){
|
free_cpu(s);
|
free_cpu(s);
|
printf("Can't open file %s, quitting!\n",file_names[i]);
|
printf("Can't open file %s, quitting!\n",args->bin_filename[i]);
|
getch();
|
return(0);
|
return(2);
|
|
}
|
}
|
|
|
bytes = fread(s->blocks[i].mem, 1, s->blocks[i].size, in);
|
bytes = fread(s->blocks[i].mem, 1, s->blocks[i].size, in);
|
fclose(in);
|
fclose(in);
|
printf("%-16s [size= %6d, start= 0x%08x]\n",
|
printf("%-16s [size= %6dKB, start= 0x%08x] loaded %d bytes.\n",
|
s->blocks[i].name,
|
s->blocks[i].area_name,
|
bytes,
|
s->blocks[i].size/1024,
|
s->blocks[i].start);
|
s->blocks[i].start,
|
|
bytes);
|
files_read++;
|
files_read++;
|
}
|
}
|
else{
|
|
break;
|
|
}
|
|
}
|
}
|
|
|
if(!files_read){
|
if(!files_read){
|
free_cpu(s);
|
free_cpu(s);
|
printf("No binary object files read, quitting\n");
|
printf("No binary object files read, quitting\n");
|
Line 997... |
Line 1059... |
/*----------------------------------------------------------------------------*/
|
/*----------------------------------------------------------------------------*/
|
|
|
int main(int argc,char *argv[]){
|
int main(int argc,char *argv[]){
|
t_state state, *s=&state;
|
t_state state, *s=&state;
|
|
|
printf("MIPS-I emulator\n");
|
printf("MIPS-I emulator (" __DATE__ ")\n\n");
|
if(!init_cpu(s)){
|
if(!init_cpu(s)){
|
printf("Trouble allocating memory, quitting!\n");
|
printf("Trouble allocating memory, quitting!\n");
|
getch();
|
|
return 1;
|
return 1;
|
};
|
};
|
|
|
/* do a minimal check on args */
|
if(parse_cmd_line(argc,argv, &cmd_line_args)==0){
|
if(argc==3 || argc==2){
|
|
/* */
|
|
}
|
|
else{
|
|
printf("Usage:");
|
|
printf(" slite file.exe <bin code file> [<bin data file>]\n");
|
|
return 0;
|
return 0;
|
}
|
}
|
|
|
if(!read_program(s, argc-1, &(argv[1]))){
|
if(!read_binary_files(s, &cmd_line_args)){
|
return 2;
|
return 2;
|
}
|
}
|
|
printf("\n\n");
|
|
|
init_trace_buffer(s, "sw_sim_log.txt");
|
init_trace_buffer(s, "sw_sim_log.txt");
|
|
|
/* NOTE: Original mlite supported loading little-endian code, which this
|
/* NOTE: Original mlite supported loading little-endian code, which this
|
program doesn't. The endianess-conversion code has been removed.
|
program doesn't. The endianess-conversion code has been removed.
|
Line 1150... |
Line 1206... |
int i;
|
int i;
|
|
|
for(i=0;i<NUM_MEM_BLOCKS;i++){
|
for(i=0;i<NUM_MEM_BLOCKS;i++){
|
free(s->blocks[i].mem);
|
free(s->blocks[i].mem);
|
s->blocks[i].mem = NULL;
|
s->blocks[i].mem = NULL;
|
|
|
}
|
}
|
}
|
}
|
|
|
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 */
|
Line 1165... |
Line 1220... |
int init_cpu(t_state *s){
|
int init_cpu(t_state *s){
|
int i, j;
|
int i, j;
|
|
|
memset(s, 0, sizeof(t_state));
|
memset(s, 0, sizeof(t_state));
|
s->big_endian = 1;
|
s->big_endian = 1;
|
|
|
|
/* Initialize memory map */
|
for(i=0;i<NUM_MEM_BLOCKS;i++){
|
for(i=0;i<NUM_MEM_BLOCKS;i++){
|
s->blocks[i].start = default_blocks[i].start;
|
s->blocks[i].start = memory_map_default[i].start;
|
s->blocks[i].size = default_blocks[i].size;
|
s->blocks[i].size = memory_map_default[i].size;
|
s->blocks[i].name = default_blocks[i].name;
|
s->blocks[i].area_name = memory_map_default[i].area_name;
|
s->blocks[i].mask = default_blocks[i].mask;
|
s->blocks[i].mask = memory_map_default[i].mask;
|
|
s->blocks[i].read_only = memory_map_default[i].read_only;
|
|
|
s->blocks[i].mem = (unsigned char*)malloc(s->blocks[i].size);
|
s->blocks[i].mem = (unsigned char*)malloc(s->blocks[i].size);
|
|
|
if(s->blocks[i].mem == NULL){
|
if(s->blocks[i].mem == NULL){
|
for(j=0;j<i;j++){
|
for(j=0;j<i;j++){
|
Line 1184... |
Line 1242... |
memset(s->blocks[i].mem, 0, s->blocks[i].size);
|
memset(s->blocks[i].mem, 0, s->blocks[i].size);
|
}
|
}
|
return NUM_MEM_BLOCKS;
|
return NUM_MEM_BLOCKS;
|
}
|
}
|
|
|
No newline at end of file
|
No newline at end of file
|
|
int32_t parse_cmd_line(uint32_t argc, char **argv, t_args *args){
|
|
uint32_t i;
|
|
|
|
/* fill cmd line args with default values */
|
|
for(i=0;i<NUM_MEM_BLOCKS;i++){
|
|
args->bin_filename[i] = NULL;
|
|
}
|
|
|
|
/* parse actual cmd line args */
|
|
for(i=1;i<argc;i++){
|
|
if(strcmp(argv[i],"--plasma")==0){
|
|
#ifdef SIMULATE_PLASMA
|
|
/* program compiled for plasma compatibility, no problem */
|
|
#else
|
|
/* program compiled for mips-1 compatibility, error*/
|
|
printf("Error: program compiled for compatibility to MIPS-I\n");
|
|
return 0;
|
|
#endif
|
|
}
|
|
else if(strncmp(argv[i],"--bram=", strlen("--bram="))==0){
|
|
args->bin_filename[0] = &(argv[i][strlen("--bram=")]);
|
|
}
|
|
else if(strncmp(argv[i],"--flash=", strlen("--flash="))==0){
|
|
args->bin_filename[2] = &(argv[i][strlen("--flash=")]);
|
|
}
|
|
else if(strncmp(argv[i],"--xram=", strlen("--xram="))==0){
|
|
args->bin_filename[1] = &(argv[i][strlen("--xram=")]);
|
|
}
|
|
else if((strcmp(argv[i],"--help")==0)||(strcmp(argv[i],"-h")==0)){
|
|
usage();
|
|
return 0;
|
|
}
|
|
else{
|
|
printf("unknown argument '%s'\n\n",argv[i]);
|
|
usage();
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
void usage(void){
|
|
printf("Usage:");
|
|
printf(" slite file.exe [arguments]\n");
|
|
printf("Arguments:\n");
|
|
printf("--bram=<file name> : BRAM initialization file\n");
|
|
printf("--xram=<file name> : XRAM initialization file\n");
|
|
printf("--flash=<file name> : FLASH initialization file\n");
|
|
printf("--plasma : Simulate Plasma instead of MIPS-I\n");
|
|
printf("--help, -h : Show this usage text\n");
|
|
}
|
|
|
No newline at end of file
|
No newline at end of file
|