Line 38... |
Line 38... |
* Software 'as is' without warranty. Author liable for nothing.
|
* Software 'as is' without warranty. Author liable for nothing.
|
*
|
*
|
* IMPORTANT: Assumes host is little endian and target is big endian.
|
* IMPORTANT: Assumes host is little endian and target is big endian.
|
*-----------------------------------------------------------------------------*/
|
*-----------------------------------------------------------------------------*/
|
|
|
|
#include <errno.h>
|
#include <stdio.h>
|
#include <stdio.h>
|
#include <stdlib.h>
|
#include <stdlib.h>
|
#include <stdint.h>
|
#include <stdint.h>
|
#include <string.h>
|
#include <string.h>
|
#include <ctype.h>
|
#include <ctype.h>
|
Line 125... |
Line 126... |
|
|
{/* uClinux memory map with bootstrap BRAM, debug only, to be removed */
|
{/* 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, 0x00800000, 0xf8000000, 0, NULL, "XRAM0"},
|
{0x00000000, 0x00400000, 0xf8000000, 0, NULL, "XRAM1"},
|
{0x00000000, 0x00800000, 0xf8000000, 0, NULL, "XRAM1"},
|
/* external flash block */
|
/* external flash block */
|
{0xb0000000, 0x00100000, 0xf8000000, 0, NULL, "Flash"},
|
{0xb0000000, 0x00100000, 0xf8000000, 0, NULL, "Flash"},
|
}
|
}
|
},
|
},
|
|
|
Line 167... |
Line 168... |
|
|
/** Values for the command line arguments */
|
/** Values for the command line arguments */
|
typedef struct s_args {
|
typedef struct s_args {
|
/** !=0 to trap on unimplemented opcodes, 0 to print warning and NOP */
|
/** !=0 to trap on unimplemented opcodes, 0 to print warning and NOP */
|
uint32_t trap_on_reserved;
|
uint32_t trap_on_reserved;
|
|
/** !=0 to emulate some common mips32 opcodes */
|
|
uint32_t emulate_some_mips32;
|
/** address to start execution from (by default, reset vector) */
|
/** address to start execution from (by default, reset vector) */
|
uint32_t start_addr;
|
uint32_t start_addr;
|
/** memory map to be used */
|
/** memory map to be used */
|
uint32_t memory_map;
|
uint32_t memory_map;
|
/** implement unaligned load/stores (don't just trap them) */
|
/** implement unaligned load/stores (don't just trap them) */
|
Line 184... |
Line 187... |
uint32_t log_trigger_address;
|
uint32_t log_trigger_address;
|
/** full name of log file */
|
/** full name of log file */
|
char *log_file_name;
|
char *log_file_name;
|
/** bin file to load to each area or null */
|
/** bin file to load to each area or null */
|
char *bin_filename[NUM_MEM_BLOCKS];
|
char *bin_filename[NUM_MEM_BLOCKS];
|
|
/** map file to be used for function call tracing, if any */
|
|
char *map_filename;
|
/** offset into area (in bytes) where bin wile will be loaded */
|
/** offset into area (in bytes) where bin wile will be loaded */
|
uint32_t offset[NUM_MEM_BLOCKS];
|
uint32_t offset[NUM_MEM_BLOCKS];
|
} t_args;
|
} t_args;
|
/** Parse cmd line args globally accessible */
|
/** Parse cmd line args globally accessible */
|
t_args cmd_line_args;
|
t_args cmd_line_args;
|
Line 262... |
Line 267... |
|
|
/* Much of this is a remnant from Plasma's mlite and is no longer used. */
|
/* Much of this is a remnant from Plasma's mlite and is no longer used. */
|
/* FIXME Refactor HW system params */
|
/* FIXME Refactor HW system params */
|
|
|
#define DBG_REGS (0x20010000)
|
#define DBG_REGS (0x20010000)
|
|
#define UART_WRITE (0x20000000)
|
|
#define UART_READ (0x20000000)
|
|
|
#define UART_WRITE 0x20000000
|
/* FIXME The following addresses are remnants of Plasma to be removed */
|
#define UART_READ 0x20000000
|
|
#define IRQ_MASK 0x20000010
|
#define IRQ_MASK 0x20000010
|
#define IRQ_STATUS 0x20000020
|
#define IRQ_STATUS 0x20000020
|
#define CONFIG_REG 0x20000070
|
#define CONFIG_REG 0x20000070
|
#define MMU_PROCESS_ID 0x20000080
|
#define MMU_PROCESS_ID 0x20000080
|
#define MMU_FAULT_ADDR 0x20000090
|
#define MMU_FAULT_ADDR 0x20000090
|
Line 320... |
Line 326... |
int pc, pc_next, epc;
|
int pc, pc_next, epc;
|
uint32_t op_addr; /**< address of opcode being simulated */
|
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;
|
|
int32_t trap_cause; /**< temporary trap code or <0 if no trap */
|
unsigned cp0_cause;
|
unsigned cp0_cause;
|
int userMode; /**< DEPRECATED, to be removed */
|
int userMode; /**< DEPRECATED, to be removed */
|
int processId; /**< DEPRECATED, to be removed */
|
int processId; /**< DEPRECATED, to be removed */
|
int exceptionId; /**< DEPRECATED, to be removed */
|
|
int faultAddr; /**< DEPRECATED, to be removed */
|
int faultAddr; /**< DEPRECATED, to be removed */
|
int irqStatus; /**< DEPRECATED, to be removed */
|
int irqStatus; /**< DEPRECATED, to be removed */
|
int skip;
|
int skip;
|
t_trace t;
|
t_trace t;
|
t_block blocks[NUM_MEM_BLOCKS];
|
t_block blocks[NUM_MEM_BLOCKS];
|
Line 344... |
Line 350... |
|
|
static char *opcode_string[]={
|
static char *opcode_string[]={
|
"0SPECIAL","0REGIMM","1J","1JAL","2BEQ","2BNE","3BLEZ","3BGTZ",
|
"0SPECIAL","0REGIMM","1J","1JAL","2BEQ","2BNE","3BLEZ","3BGTZ",
|
"5ADDI","5ADDIU","5SLTI","5SLTIU","5ANDI","5ORI","5XORI","6LUI",
|
"5ADDI","5ADDIU","5SLTI","5SLTIU","5ANDI","5ORI","5XORI","6LUI",
|
"cCOP0","cCOP1","cCOP2","cCOP3","2BEQL","2BNEL","3BLEZL","3BGTZL",
|
"cCOP0","cCOP1","cCOP2","cCOP3","2BEQL","2BNEL","3BLEZL","3BGTZL",
|
"0?","0?","0?","0?","0?","0?","0?","0?",
|
"0?","0?","0?","0?","0SPECIAL2","0?","0?","0SPECIAL3",
|
"8LB","8LH","8LWL","8LW","8LBU","8LHU","8LWR","0?",
|
"8LB","8LH","8LWL","8LW","8LBU","8LHU","8LWR","0?",
|
"8SB","8SH","8SWL","8SW","0?","0?","8SWR","0CACHE",
|
"8SB","8SH","8SWL","8SW","0?","0?","8SWR","0CACHE",
|
"0LL","0LWC1","0LWC2","0LWC3","?","0LDC1","0LDC2","0LDC3"
|
"0LL","0LWC1","0LWC2","0LWC3","?","0LDC1","0LDC2","0LDC3"
|
"0SC","0SWC1","0SWC2","0SWC3","?","0SDC1","0SDC2","0SDC3"
|
"0SC","0SWC1","0SWC2","0SWC3","?","0SDC1","0SDC2","0SDC3"
|
};
|
};
|
Line 368... |
Line 374... |
"9BLTZ","9BGEZ","9BLTZL","9BGEZL","0?","0?","0?","0?",
|
"9BLTZ","9BGEZ","9BLTZL","9BGEZL","0?","0?","0?","0?",
|
"0TGEI","0TGEIU","0TLTI","0TLTIU","0TEQI","0?","0TNEI","0?",
|
"0TGEI","0TGEIU","0TLTI","0TLTIU","0TEQI","0?","0TNEI","0?",
|
"9BLTZAL","9BEQZAL","9BLTZALL","9BGEZALL","0?","0?","0?","0?",
|
"9BLTZAL","9BEQZAL","9BLTZALL","9BGEZALL","0?","0?","0?","0?",
|
"0?","0?","0?","0?","0?","0?","0?","0?"
|
"0?","0?","0?","0?","0?","0?","0?","0?"
|
};
|
};
|
|
/*
|
|
static char *special2_string[]={
|
|
"0MADD","0MADDU","0MUL","0?", "0?","0?","0?","0?",
|
|
"0?","0?","0?","0?", "0?","0?","0?","0?",
|
|
"0?","0?","0?","0?", "0?","0?","0?","0?",
|
|
"0?","0?","0?","0?", "0?","0?","0?","0?",
|
|
|
|
"0CLZ","0CLO","0?","0?", "0?","0?","0?","0?",
|
|
"0?","0?","0?","0?", "0?","0?","0?","0?",
|
|
"0?","0?","0?","0?", "0?","0?","0?","0?",
|
|
"0?","0?","0?","0?", "0?","0?","0?","0?",
|
|
};
|
|
*/
|
|
|
|
/** local memory used by the console simulation code */
|
static unsigned int HWMemory[8];
|
static unsigned int HWMemory[8];
|
|
|
|
#define MAP_MAX_FUNCTIONS (400)
|
|
#define MAP_MAX_NAME_LEN (80)
|
|
|
|
/** Information extracted from the map file, if any */
|
|
typedef struct {
|
|
uint32_t num_functions; /**< number of functions in the table */
|
|
FILE *log; /**< text log file or stdout */
|
|
char *log_filename; /**< name of log file or NULL */
|
|
uint32_t fn_address[MAP_MAX_FUNCTIONS];
|
|
char fn_name[MAP_MAX_FUNCTIONS][MAP_MAX_NAME_LEN];
|
|
} t_map_info;
|
|
|
|
t_map_info map_info;
|
|
|
/*---- Local function prototypes ---------------------------------------------*/
|
/*---- Local function prototypes ---------------------------------------------*/
|
|
|
/* Debug and logging */
|
/* Debug and logging */
|
void init_trace_buffer(t_state *s, t_args *args);
|
void init_trace_buffer(t_state *s, t_args *args);
|
void close_trace_buffer(t_state *s);
|
void close_trace_buffer(t_state *s);
|
void dump_trace_buffer(t_state *s);
|
void dump_trace_buffer(t_state *s);
|
void log_cycle(t_state *s);
|
uint32_t 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);
|
void print_opcode_fields(uint32_t opcode);
|
|
void reserved_opcode(uint32_t pc, uint32_t opcode, t_state* s);
|
|
int32_t read_map_file(char *filename, t_map_info* map);
|
|
void log_call(uint32_t to, uint32_t from);
|
|
void log_ret(uint32_t to, uint32_t from);
|
|
int32_t function_index(uint32_t address);
|
|
|
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 402... |
Line 441... |
void start_load(t_state *s, uint32_t addr, int rt, int data);
|
void start_load(t_state *s, uint32_t addr, int rt, int data);
|
|
|
|
|
/*---- Local functions -------------------------------------------------------*/
|
/*---- Local functions -------------------------------------------------------*/
|
|
|
|
/*---- Call & ret tracing (EARLY DRAFT) --------------------------------------*/
|
|
|
|
static uint32_t call_depth = 0;
|
|
|
|
void log_ret(uint32_t to, uint32_t from){
|
|
int32_t i,j;
|
|
|
|
/* If no map file has been loaded, skip trace */
|
|
if((!map_info.num_functions) || (!map_info.log)) return;
|
|
|
|
if(call_depth>0){
|
|
fprintf(map_info.log, "[%08x] ", from);
|
|
for(j=0;j<call_depth;j++){
|
|
fprintf(map_info.log, ". ");
|
|
}
|
|
fprintf(map_info.log, "}\n");
|
|
call_depth--;
|
|
}
|
|
else{
|
|
i = function_index(to);
|
|
if(i>=0){
|
|
fprintf(map_info.log, "[%08x] %s\n", from, map_info.fn_name[i]);
|
|
}
|
|
else{
|
|
fprintf(map_info.log, "[%08x] %08x\n", from, to);
|
|
}
|
|
}
|
|
}
|
|
|
|
/** */
|
|
void log_call(uint32_t to, uint32_t from){
|
|
int32_t i,j;
|
|
|
|
/* If no map file has been loaded, skip trace */
|
|
if((!map_info.num_functions) || (!map_info.log)) return;
|
|
|
|
i = function_index(to);
|
|
if(i>=0){
|
|
call_depth++;
|
|
fprintf(map_info.log, "[%08x] ", from);
|
|
for(j=0;j<call_depth;j++){
|
|
fprintf(map_info.log, ". ");
|
|
}
|
|
fprintf(map_info.log, "%s{\n", map_info.fn_name[i]);
|
|
}
|
|
}
|
|
|
|
int32_t function_index(uint32_t address){
|
|
uint32_t i;
|
|
|
|
for(i=0;i<map_info.num_functions;i++){
|
|
if(address==map_info.fn_address[i]){
|
|
return i;
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
/*---- Execution log ---------------------------------------------------------*/
|
|
|
/** 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 bit CP0.16==1, this is a D-Cache line invalidation access and
|
/* if bit CP0.16==1, this is a D-Cache line invalidation access and
|
the HW will not read any actual data, so skip the log (@note1) */
|
the HW will not read any actual data, so skip the log (@note1) */
|
if(log_enabled(s) && log!=0 && !(s->status & 0x00010000)){
|
if(log_enabled(s) && log!=0 && !(s->status & 0x00010000)){
|
Line 460... |
Line 559... |
}
|
}
|
if(!ptr){
|
if(!ptr){
|
/* address out of mapped blocks: log and return zero */
|
/* address out of mapped blocks: log and return zero */
|
/* if bit CP0.16==1, this is a D-Cache line invalidation access and
|
/* if bit CP0.16==1, this is a D-Cache line invalidation access and
|
the HW will not read any actual data, so skip the log (@note1) */
|
the HW will not read any actual data, so skip the log (@note1) */
|
|
printf("MEM RD ERROR @ 0x%08x [0x%08x]\n", s->pc, full_address);
|
if(log_enabled(s) && log!=0 && !(s->status & (1<<16))){
|
if(log_enabled(s) && log!=0 && !(s->status & (1<<16))){
|
fprintf(s->t.log, "(%08X) [%08X] <**>=%08X RD UNMAPPED\n",
|
fprintf(s->t.log, "(%08X) [%08X] <**>=%08X RD UNMAPPED\n",
|
s->pc, full_address, 0);
|
s->pc, full_address, 0);
|
}
|
}
|
return 0;
|
return 0;
|
Line 564... |
Line 664... |
fprintf(s->t.log, "(%08X) [%08X] |%02X|=%08X WR\n",
|
fprintf(s->t.log, "(%08X) [%08X] |%02X|=%08X WR\n",
|
//s->op_addr, address&0xfffffffc, mask, dvalue);
|
//s->op_addr, address&0xfffffffc, mask, dvalue);
|
s->op_addr, address, mask, dvalue);
|
s->op_addr, address, mask, dvalue);
|
}
|
}
|
|
|
if((address&0xffff0000)==DBG_REGS){
|
/* Print anything that's written to a debug register, otherwise ignore it */
|
printf("[%04x]=%08x\n", address & 0xffff, value);
|
if((address&0xffff0000)==(DBG_REGS&0xffff0000)){
|
|
printf("DEBUG REG[%04x]=%08x\n", address & 0xffff, value);
|
|
return;
|
}
|
}
|
|
|
switch(address){
|
switch(address){
|
case UART_WRITE:
|
case UART_WRITE:
|
putch(value);
|
putch(value);
|
Line 606... |
Line 708... |
break;
|
break;
|
}
|
}
|
}
|
}
|
if(!ptr){
|
if(!ptr){
|
/* address out of mapped blocks: log and return zero */
|
/* address out of mapped blocks: log and return zero */
|
|
printf("MEM WR ERROR @ 0x%08x [0x%08x]\n", s->pc, address);
|
if(log_enabled(s) && log!=0){
|
if(log_enabled(s) && 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->op_addr, address, mask, dvalue);
|
s->op_addr, address, mask, dvalue);
|
}
|
}
|
return;
|
return;
|
Line 717... |
Line 820... |
data = (data << disp[offset]) & mask[offset];
|
data = (data << disp[offset]) & mask[offset];
|
|
|
s->r[reg_index] = (s->r[reg_index] & (~mask[offset])) | data;
|
s->r[reg_index] = (s->r[reg_index] & (~mask[offset])) | data;
|
}
|
}
|
|
|
|
/*---- Optional MIPS32 opcodes -----------------------------------------------*/
|
|
|
|
uint32_t count_leading(uint32_t lead, uint32_t src){
|
|
uint32_t mask, bit_val, i;
|
|
|
|
mask = 0x80000000;
|
|
bit_val = lead? mask : 0x0;
|
|
|
|
for(i=0;i<32;i++){
|
|
if((src & mask) != bit_val){
|
|
return i;
|
|
}
|
|
mask = mask >> 1;
|
|
}
|
|
|
|
return i;
|
|
}
|
|
|
|
uint32_t mult_gpr(uint32_t m1, uint32_t m2){
|
|
uint32_t temp;
|
|
|
|
temp = m1 * m2;
|
|
return temp;
|
|
}
|
|
|
|
uint32_t ext_bitfield(uint32_t src, uint32_t opcode){
|
|
uint32_t pos, size, mask, value;
|
|
|
|
pos = (opcode>>6) & 0x1f;
|
|
size = ((opcode>>11) & 0x1f) + 1;
|
|
mask = (1 << size)-1;
|
|
mask = mask << pos;
|
|
|
|
value = (src & mask) >> pos;
|
|
return value;
|
|
}
|
|
|
|
uint32_t ins_bitfield(uint32_t target, uint32_t src, uint32_t opcode){
|
|
uint32_t pos, size, mask, value;
|
|
|
|
pos = (opcode>>6) & 0x1f;
|
|
size = ((opcode>>11) & 0x1f) + 1;
|
|
mask = (1 << size)-1;
|
|
mask = mask << pos;
|
|
|
|
value = target & (~mask);
|
|
value |= ((src << pos) & mask);
|
|
return value;
|
|
}
|
|
|
/*---- Optional MMU and cache implementation ---------------------------------*/
|
/*---- Optional MMU and cache implementation ---------------------------------*/
|
|
|
/*
|
/*
|
The actual core does not have a cache so all of the original Plasma mlite.c
|
The actual core does not have a cache so all of the original Plasma mlite.c
|
Line 788... |
Line 940... |
/** 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){
|
unsigned int opcode;
|
unsigned int opcode;
|
int delay_slot = 0; /* 1 of this instruction is a branch */
|
int delay_slot = 0; /* 1 of this instruction is a branch */
|
unsigned int op, rs, rt, rd, re, func, imm, target;
|
unsigned int op, rs, rt, rd, re, func, imm, target;
|
int trap_cause = 0;
|
|
int imm_shift, branch=0, lbranch=2, skip2=0;
|
int imm_shift, branch=0, lbranch=2, skip2=0;
|
|
int link=0; /* !=0 if this is a 'branch-and-link' opcode */
|
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;
|
char format;
|
char format;
|
uint32_t aux;
|
uint32_t aux;
|
uint32_t target_offset16;
|
uint32_t target_offset16;
|
uint32_t target_long;
|
uint32_t target_long;
|
|
|
|
s->trap_cause = -1;
|
|
|
/* fetch and decode instruction */
|
/* fetch and decode instruction */
|
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;
|
re = (opcode >> 6) & 0x1f;
|
re = (opcode >> 6) & 0x1f;
|
Line 843... |
Line 998... |
}
|
}
|
else{
|
else{
|
aux = op&0x03;
|
aux = op&0x03;
|
switch(rs){
|
switch(rs){
|
case 16:
|
case 16:
|
/* FIXME partial decoding */
|
/* FIXME partial decoding of some COP0 opcodes */
|
printf(" RFE "); format = ' '; break;
|
printf(" RFE "); format = ' '; break;
|
case 4:
|
case 4:
|
printf(" MTC%1d ", aux); break;
|
printf(" MTC%1d ", aux); break;
|
case 0:
|
case 0:
|
printf(" MFC%1d ", aux); break;
|
printf(" MFC%1d ", aux); break;
|
Line 946... |
Line 1101... |
case 0x02:/*SRL*/ r[rd]=u[rt]>>re; break;
|
case 0x02:/*SRL*/ r[rd]=u[rt]>>re; break;
|
case 0x03:/*SRA*/ r[rd]=r[rt]>>re; break;
|
case 0x03:/*SRA*/ r[rd]=r[rt]>>re; break;
|
case 0x04:/*SLLV*/ r[rd]=r[rt]<<r[rs]; break;
|
case 0x04:/*SLLV*/ r[rd]=r[rt]<<r[rs]; break;
|
case 0x06:/*SRLV*/ r[rd]=u[rt]>>r[rs]; break;
|
case 0x06:/*SRLV*/ r[rd]=u[rt]>>r[rs]; break;
|
case 0x07:/*SRAV*/ r[rd]=r[rt]>>r[rs]; break;
|
case 0x07:/*SRAV*/ r[rd]=r[rt]>>r[rs]; break;
|
case 0x08:/*JR*/ delay_slot=1;
|
case 0x08:/*JR*/ if(rs==31) log_ret(r[rs],epc);
|
|
delay_slot=1;
|
s->pc_next=r[rs]; break;
|
s->pc_next=r[rs]; break;
|
case 0x09:/*JALR*/ delay_slot=1;
|
case 0x09:/*JALR*/ delay_slot=1;
|
r[rd]=s->pc_next;
|
r[rd]=s->pc_next;
|
s->pc_next=r[rs]; break;
|
s->pc_next=r[rs];
|
|
log_call(s->pc_next, epc); break;
|
case 0x0a:/*MOVZ*/ if(!r[rt]) r[rd]=r[rs]; break; /*IV*/
|
case 0x0a:/*MOVZ*/ if(!r[rt]) r[rd]=r[rs]; break; /*IV*/
|
case 0x0b:/*MOVN*/ if(r[rt]) r[rd]=r[rs]; break; /*IV*/
|
case 0x0b:/*MOVN*/ if(r[rt]) r[rd]=r[rs]; break; /*IV*/
|
case 0x0c:/*SYSCALL*/ trap_cause = 8;
|
case 0x0c:/*SYSCALL*/ s->trap_cause = 8;
|
s->exceptionId=1;
|
|
/*
|
/*
|
FIXME enable when running uClinux
|
FIXME enable when running uClinux
|
printf("SYSCALL (%08x)\n", s->pc);
|
printf("SYSCALL (%08x)\n", s->pc);
|
*/
|
*/
|
break;
|
break;
|
case 0x0d:/*BREAK*/ trap_cause = 9;
|
case 0x0d:/*BREAK*/ s->trap_cause = 9;
|
s->exceptionId=1;
|
|
/*
|
/*
|
FIXME enable when running uClinux
|
FIXME enable when running uClinux
|
printf("BREAK (%08x)\n", s->pc);
|
printf("BREAK (%08x)\n", s->pc);
|
*/
|
*/
|
break;
|
break;
|
Line 992... |
Line 1147... |
case 0x31:/*TGEU*/ break;
|
case 0x31:/*TGEU*/ break;
|
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:
|
/* FIXME should trap unknown opcode */
|
reserved_opcode(epc, opcode, s);
|
s->wakeup=1;
|
|
}
|
}
|
break;
|
break;
|
case 0x01:/*REGIMM*/
|
case 0x01:/*REGIMM*/
|
switch(rt){
|
switch(rt){
|
case 0x10:/*BLTZAL*/ r[31]=s->pc_next;
|
case 0x10:/*BLTZAL*/ r[31]=s->pc_next; link=1;
|
case 0x00:/*BLTZ*/ branch=r[rs]<0; break;
|
case 0x00:/*BLTZ*/ branch=r[rs]<0; break;
|
case 0x11:/*BGEZAL*/ r[31]=s->pc_next;
|
case 0x11:/*BGEZAL*/ r[31]=s->pc_next; link=1;
|
case 0x01:/*BGEZ*/ branch=r[rs]>=0; break;
|
case 0x01:/*BGEZ*/ branch=r[rs]>=0; break;
|
case 0x12:/*BLTZALL*/r[31]=s->pc_next;
|
case 0x12:/*BLTZALL*/r[31]=s->pc_next; link=1;
|
case 0x02:/*BLTZL*/ lbranch=r[rs]<0; break;
|
case 0x02:/*BLTZL*/ lbranch=r[rs]<0; break;
|
case 0x13:/*BGEZALL*/r[31]=s->pc_next;
|
case 0x13:/*BGEZALL*/r[31]=s->pc_next; link=1;
|
case 0x03:/*BGEZL*/ lbranch=r[rs]>=0; break;
|
case 0x03:/*BGEZL*/ lbranch=r[rs]>=0; break;
|
default: printf("ERROR1\n"); s->wakeup=1;
|
default: printf("ERROR1\n"); s->wakeup=1;
|
}
|
}
|
break;
|
break;
|
case 0x03:/*JAL*/ r[31]=s->pc_next;
|
case 0x03:/*JAL*/ r[31]=s->pc_next; log_call(((s->pc&0xf0000000)|target), epc);
|
case 0x02:/*J*/ delay_slot=1;
|
case 0x02:/*J*/ delay_slot=1;
|
s->pc_next=(s->pc&0xf0000000)|target; break;
|
s->pc_next=(s->pc&0xf0000000)|target; break;
|
case 0x04:/*BEQ*/ branch=r[rs]==r[rt]; break;
|
case 0x04:/*BEQ*/ branch=r[rs]==r[rt]; break;
|
case 0x05:/*BNE*/ branch=r[rs]!=r[rt]; break;
|
case 0x05:/*BNE*/ branch=r[rs]!=r[rt]; break;
|
case 0x06:/*BLEZ*/ branch=r[rs]<=0; break;
|
case 0x06:/*BLEZ*/ branch=r[rs]<=0; break;
|
Line 1035... |
Line 1189... |
case 12: r[rt]=s->status & 0x0000003f; 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]=R3000_ID; break;
|
case 15: r[rt]=R3000_ID; break;
|
default:
|
default:
|
|
printf("mfc0 [%02d] @ [0x%08x]\n", rt, s->pc);
|
break;
|
break;
|
}
|
}
|
}
|
}
|
else{ //move to CP0 (mtc0)
|
else{ //move to CP0 (mtc0)
|
/* FIXME check CF= reg address */
|
/* FIXME check CF= reg address */
|
Line 1050... |
Line 1205... |
/* Move to unimplemented COP0 register: display warning */
|
/* Move to unimplemented COP0 register: display warning */
|
/* FIXME should log ignored move */
|
/* FIXME should log ignored move */
|
printf("mtc0 [%2d]=0x%08x @ [0x%08x] IGNORED\n",
|
printf("mtc0 [%2d]=0x%08x @ [0x%08x] IGNORED\n",
|
rd, r[rt], epc);
|
rd, r[rt], epc);
|
}
|
}
|
/* FIXME remove remnants of Plasma MMU simulation */
|
|
/*
|
|
if(s->processId && (r[rt]&2)){
|
|
s->userMode|=r[rt]&2;
|
|
//printf("CpuStatus=%d %d %d\n", r[rt], s->status, s->userMode);
|
|
//s->wakeup = 1;
|
|
//printf("pc=0x%x\n", epc);
|
|
}
|
|
*/
|
|
}
|
}
|
}
|
}
|
else{
|
else{
|
/* tried to execute mtc* or mfc* in user mode: trap */
|
/* tried to execute mtc* or mfc* in user mode: trap */
|
printf("COP0 UNAVAILABLE address=0x%08x opcode=0x%x -- ",
|
printf("COP0 UNAVAILABLE [0x%08x] = 0x%x %c -- ",
|
epc, opcode);
|
epc, opcode, (s->delay_slot? 'D':' '));
|
print_opcode_fields(opcode);
|
print_opcode_fields(opcode);
|
printf("\n");
|
printf("\n");
|
|
|
trap_cause = 11; /* unavailable coprocessor */
|
s->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;
|
case 0x14:/*BEQL*/ lbranch=r[rs]==r[rt]; break;
|
case 0x14:/*BEQL*/ lbranch=r[rs]==r[rt]; break;
|
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:/*SPECIAL2*/
|
|
/* MIPS32 opcodes, some of which may be emulated */
|
|
if(cmd_line_args.emulate_some_mips32){
|
|
switch(func){
|
|
case 0x20: /* CLZ */ r[rt] = count_leading(0, r[rs]); break;
|
|
case 0x21: /* CLO */ r[rt] = count_leading(1, r[rs]); break;
|
|
case 0x02: /* MUL */ r[rd] = mult_gpr(r[rs], r[rt]); break;
|
|
default:
|
|
reserved_opcode(epc, opcode, s);
|
|
}
|
|
}
|
|
else{
|
|
reserved_opcode(epc, opcode, s);
|
|
}
|
|
break;
|
|
case 0x1f: /* SPECIAL3 */
|
|
if(cmd_line_args.emulate_some_mips32){
|
|
switch(func){
|
|
case 0x00: /* EXT */ r[rt] = ext_bitfield(r[rs], opcode); break;
|
|
case 0x04: /* INS */ r[rt] = ins_bitfield(r[rt], r[rs], opcode); break;
|
|
default:
|
|
reserved_opcode(epc, opcode, s);
|
|
}
|
|
}
|
|
break;
|
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, ptr, 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;
|
Line 1132... |
Line 1301... |
// case 0x3b:/*SWC3*/ break;
|
// case 0x3b:/*SWC3*/ break;
|
// case 0x3d:/*SDC1*/ break;
|
// case 0x3d:/*SDC1*/ break;
|
// case 0x3e:/*SDC2*/ break;
|
// case 0x3e:/*SDC2*/ break;
|
// case 0x3f:/*SDC3*/ break;
|
// case 0x3f:/*SDC3*/ break;
|
default: /* unimplemented opcode */
|
default: /* unimplemented opcode */
|
if(cmd_line_args.trap_on_reserved){
|
reserved_opcode(epc, opcode, s);
|
trap_cause = 10; /* reserved instruction */
|
|
s->exceptionId=1;
|
|
}
|
|
else{
|
|
printf("RESERVED OPCODE address=0x%08x opcode=0x%x -- ",
|
|
epc, opcode);
|
|
print_opcode_fields(opcode);
|
|
printf("\n");
|
|
}
|
}
|
|
|
|
/* */
|
|
if((branch || lbranch == 1) && link){
|
|
log_call(s->pc_next + imm_shift, epc);
|
}
|
}
|
|
|
/* adjust next PC if this was a a jump instruction */
|
/* adjust next PC if this was a a jump 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;
|
Line 1159... |
Line 1324... |
|
|
/* if there's a delayed load pending, do it now: load reg with memory data*/
|
/* if there's a delayed load pending, do it now: load reg with memory data*/
|
/* load delay slots not simulated */
|
/* load delay slots not simulated */
|
|
|
/* Handle exceptions */
|
/* Handle exceptions */
|
if(s->exceptionId){
|
if(s->trap_cause>=0){
|
r[rt] = rSave;
|
r[rt] = rSave;
|
/* set cause field ... */
|
/* set cause field ... */
|
s->cp0_cause = (s->delay_slot & 0x1) << 31 | (trap_cause & 0x1f) << 2;
|
s->cp0_cause = (s->delay_slot & 0x1) << 31 | (s->trap_cause & 0x1f) << 2;
|
/* ...save previous KU/IE flags in SR... */
|
/* ...save previous KU/IE flags in SR... */
|
s->status = (s->status & 0xffffffc3) | ((s->status & 0x0f) << 2);
|
s->status = (s->status & 0xffffffc3) | ((s->status & 0x0f) << 2);
|
/* ...and raise KU(EXL) kernel mode flag */
|
/* ...and raise KU(EXL) kernel mode flag */
|
s->status |= 0x02;
|
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 */
|
Line 1174... |
Line 1339... |
epc = epc - 4;
|
epc = epc - 4;
|
}
|
}
|
s->epc = epc;
|
s->epc = epc;
|
s->pc_next = VECTOR_TRAP;
|
s->pc_next = VECTOR_TRAP;
|
s->skip = 1;
|
s->skip = 1;
|
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 we're NOT showing output to console, log state of CPU to file */
|
if(!show_mode){
|
if(!show_mode){
|
log_cycle(s);
|
s->wakeup |= 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
|
Line 1210... |
Line 1374... |
printf("%02x:", field);
|
printf("%02x:", field);
|
field = (opcode >> 0)&0x3f;
|
field = (opcode >> 0)&0x3f;
|
printf("%02x", field);
|
printf("%02x", field);
|
}
|
}
|
|
|
|
/** Deal with reserved, unimplemented opcodes. Updates s->trap_cause. */
|
|
void reserved_opcode(uint32_t pc, uint32_t opcode, t_state* s){
|
|
if(cmd_line_args.trap_on_reserved){
|
|
s->trap_cause = 10; /* reserved instruction */
|
|
}
|
|
else{
|
|
printf("RESERVED OPCODE [0x%08x] = 0x%08x %c -- ",
|
|
pc, opcode, (s->delay_slot? 'D':' '));
|
|
print_opcode_fields(opcode);
|
|
printf("\n");
|
|
}
|
|
}
|
|
|
|
|
/** 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);
|
Line 1387... |
Line 1564... |
int read_binary_files(t_state *s, t_args *args){
|
int read_binary_files(t_state *s, t_args *args){
|
FILE *in;
|
FILE *in;
|
uint8_t *target;
|
uint8_t *target;
|
uint32_t bytes=0, i, files_read=0;
|
uint32_t bytes=0, i, files_read=0;
|
|
|
|
/* read map file if requested */
|
|
if(args->map_filename!=NULL){
|
|
if(read_map_file(args->map_filename, &map_info)<0){
|
|
printf("Trouble reading map file '%s', quitting!\n",
|
|
args->map_filename);
|
|
return 1;
|
|
}
|
|
printf("Read %d functions from the map file; call trace enabled.\n\n",
|
|
map_info.num_functions);
|
|
}
|
|
|
|
/* read object code binaries */
|
for(i=0;i<NUM_MEM_BLOCKS;i++){
|
for(i=0;i<NUM_MEM_BLOCKS;i++){
|
bytes = 0;
|
bytes = 0;
|
if(args->bin_filename[i]!=NULL){
|
if(args->bin_filename[i]!=NULL){
|
|
|
in = fopen(args->bin_filename[i], "rb");
|
in = fopen(args->bin_filename[i], "rb");
|
Line 1416... |
Line 1605... |
|
|
fclose(in);
|
fclose(in);
|
|
|
/* Now reverse the endianness of the data we just read, if it's
|
/* Now reverse the endianness of the data we just read, if it's
|
necessary. */
|
necessary. */
|
/* FIXME add cmd line param, etc. */
|
/* FIXME handle little-endian stuff (?) */
|
//reverse_endianess(target, bytes);
|
//reverse_endianess(target, bytes);
|
|
|
files_read++;
|
files_read++;
|
}
|
}
|
printf("%-16s [size= %6dKB, start= 0x%08x] loaded %d bytes.\n",
|
printf("%-16s [size= %6dKB, start= 0x%08x] loaded %d bytes.\n",
|
Line 1457... |
Line 1646... |
/*----------------------------------------------------------------------------*/
|
/*----------------------------------------------------------------------------*/
|
|
|
int main(int argc,char *argv[]){
|
int main(int argc,char *argv[]){
|
t_state state, *s=&state;
|
t_state state, *s=&state;
|
|
|
|
|
|
|
/* Parse command line and pass any relevant arguments to CPU record */
|
/* Parse command line and pass any relevant arguments to CPU record */
|
if(parse_cmd_line(argc,argv, &cmd_line_args)==0){
|
if(parse_cmd_line(argc,argv, &cmd_line_args)==0){
|
return 0;
|
return 0;
|
}
|
}
|
|
|
Line 1484... |
Line 1675... |
|
|
/* Simulate a CPU reset */
|
/* Simulate a CPU reset */
|
reset_cpu(s);
|
reset_cpu(s);
|
|
|
/* Simulate the work of the uClinux bootloader */
|
/* Simulate the work of the uClinux bootloader */
|
if(cmd_line_args.memory_map == MAP_UCLINUX){
|
if(cmd_line_args.memory_map == MAP_UCLINUX_BRAM){
|
/* FIXME this is a stub, flesh it out */
|
/* FIXME this 'bootloader' is a stub, flesh it out */
|
s->pc = 0x80002400;
|
s->pc = 0x80002400;
|
}
|
}
|
|
|
/* Enter debug command interface; will only exit clean with user command */
|
/* Enter debug command interface; will only exit clean with user command */
|
do_debug(s, cmd_line_args.no_prompt);
|
do_debug(s, cmd_line_args.no_prompt);
|
Line 1510... |
Line 1701... |
s->t.disasm_ptr = VECTOR_RESET;
|
s->t.disasm_ptr = VECTOR_RESET;
|
|
|
#if FILE_LOGGING_DISABLED
|
#if FILE_LOGGING_DISABLED
|
s->t.log = NULL;
|
s->t.log = NULL;
|
s->t.log_triggered = 0;
|
s->t.log_triggered = 0;
|
|
map_info.log = NULL;
|
return;
|
return;
|
#else
|
#else
|
/* clear trace buffer */
|
/* clear trace buffer */
|
for(i=0;i<TRACE_BUFFER_SIZE;i++){
|
for(i=0;i<TRACE_BUFFER_SIZE;i++){
|
s->t.buf[i]=0xffffffff;
|
s->t.buf[i]=0xffffffff;
|
Line 1533... |
Line 1725... |
}
|
}
|
|
|
/* Setup log trigger */
|
/* Setup log trigger */
|
s->t.log_triggered = 0;
|
s->t.log_triggered = 0;
|
s->t.log_trigger_address = args->log_trigger_address;
|
s->t.log_trigger_address = args->log_trigger_address;
|
|
|
|
/* if file logging of function calls is enabled, open log file */
|
|
if(map_info.log_filename!=NULL){
|
|
map_info.log = fopen(map_info.log_filename, "w");
|
|
if(map_info.log==NULL){
|
|
printf("Error opening log file '%s', file logging disabled\n",
|
|
map_info.log_filename);
|
|
}
|
|
}
|
#endif
|
#endif
|
}
|
}
|
|
|
/** Dumps last jump targets as a chunk of hex numbers (older is left top) */
|
/** Dumps last jump targets as a chunk of hex numbers (older is left top) */
|
void dump_trace_buffer(t_state *s){
|
void dump_trace_buffer(t_state *s){
|
Line 1549... |
Line 1750... |
}
|
}
|
}
|
}
|
}
|
}
|
|
|
/** 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){
|
uint32_t 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;
|
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;
|
|
log_pc = s->op_addr;
|
|
|
|
|
/* if file logging is enabled, dump a trace log to file */
|
/* if file logging is enabled, dump a trace log to file */
|
if(log_enabled(s)){
|
if(log_enabled(s)){
|
log_pc = s->op_addr;
|
|
|
|
/* skip register zero which does not change */
|
/* skip register zero which does not change */
|
for(i=1;i<32;i++){
|
for(i=1;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", log_pc, i, s->r[i]);
|
fprintf(s->t.log, "(%08X) [%02X]=%08X\n", log_pc, i, s->r[i]);
|
Line 1593... |
Line 1795... |
if(s->status != s->t. status){
|
if(s->status != s->t. status){
|
fprintf(s->t.log, "(%08X) [SR]=%08X\n", log_pc, s->status);
|
fprintf(s->t.log, "(%08X) [SR]=%08X\n", log_pc, s->status);
|
}
|
}
|
s->t.status = s->status;
|
s->t.status = s->status;
|
}
|
}
|
|
|
|
#if 0
|
|
/* FIXME Try to detect a code crash by looking at SP */
|
|
if(1){
|
|
if((s->r[29]&0xffff0000) == 0xffff00000){
|
|
printf("SP derailed! @ 0x%08x [0x%08x]\n", log_pc, s->r[29]);
|
|
return 1;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
return 0;
|
}
|
}
|
|
|
/** 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){
|
if(s->t.log){
|
if(s->t.log){
|
fclose(s->t.log);
|
fclose(s->t.log);
|
}
|
}
|
|
if(map_info.log){
|
|
fclose(map_info.log);
|
|
}
|
}
|
}
|
|
|
/** Logs a message for each failed assertion, each in a line */
|
/** Logs a message for each failed assertion, each in a line */
|
void log_failed_assertions(t_state *s){
|
void log_failed_assertions(t_state *s){
|
unsigned bitmap = s->failed_assertions;
|
unsigned bitmap = s->failed_assertions;
|
Line 1638... |
Line 1855... |
s->t.lo = s->lo;
|
s->t.lo = s->lo;
|
s->t.hi = s->hi;
|
s->t.hi = s->hi;
|
s->t.epc = s->epc;
|
s->t.epc = s->epc;
|
}
|
}
|
|
|
|
int32_t read_map_file(char *filename, t_map_info* map){
|
|
FILE *f;
|
|
uint32_t address, i;
|
|
uint32_t segment_text = 0;
|
|
char line[256];
|
|
char name[256];
|
|
|
|
f = fopen (filename, "rt"); /* open the file for reading */
|
|
|
|
if(!f){
|
|
return -1;
|
|
}
|
|
|
|
while(fgets(line, sizeof(line)-1, f) != NULL){
|
|
if(!strncmp(line, ".text", 5)){
|
|
segment_text = 1;
|
|
}
|
|
else if(line[0]==' ' && segment_text){
|
|
/* may be a function address */
|
|
for(i=0;(i<sizeof(line)-1) && (line[i]==' '); i++);
|
|
if(line[i]=='0'){
|
|
sscanf(line, "%*[ \n\t]%x%*[ \n\t]%s", &address, &(name[0]));
|
|
|
|
strncpy(map->fn_name[map->num_functions],
|
|
name, MAP_MAX_NAME_LEN-1);
|
|
map->fn_address[map->num_functions] = address;
|
|
map->num_functions++;
|
|
if(map->num_functions >= MAP_MAX_FUNCTIONS){
|
|
printf("WARNING: too many functions in map file!\n");
|
|
return map->num_functions;
|
|
}
|
|
}
|
|
}
|
|
else if(line[0]=='.' && segment_text){
|
|
break;
|
|
}
|
|
}
|
|
fclose(f);
|
|
|
|
#if 0
|
|
for(i=0;i<map->num_functions;i++){
|
|
printf("--> %08x %s\n", map->fn_address[i], map->fn_name[i]);
|
|
}
|
|
#endif
|
|
|
|
return map->num_functions;
|
|
}
|
|
|
|
|
void free_cpu(t_state *s){
|
void free_cpu(t_state *s){
|
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);
|
Line 1656... |
Line 1922... |
s->status = 0x02; /* kernel mode, interrupts disabled */
|
s->status = 0x02; /* kernel mode, interrupts disabled */
|
/* init trace struct to prevent spurious logs */
|
/* init trace struct to prevent spurious logs */
|
s->t.status = s->status;
|
s->t.status = s->status;
|
}
|
}
|
|
|
|
/* FIXME redundant function, merge with reserved_opcode */
|
void unimplemented(t_state *s, const char *txt){
|
void unimplemented(t_state *s, const char *txt){
|
/* FIXME unimplemented opcode trap */
|
|
printf("UNIMPLEMENTED: %s\n", txt);
|
printf("UNIMPLEMENTED: %s\n", txt);
|
}
|
}
|
|
|
int init_cpu(t_state *s, t_args *args){
|
int init_cpu(t_state *s, t_args *args){
|
int i, j;
|
int i, j;
|
Line 1695... |
Line 1961... |
}
|
}
|
|
|
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){
|
uint32_t i;
|
uint32_t i;
|
|
|
|
/* Initialize logging parameters */
|
|
map_info.num_functions = 0;
|
|
map_info.log_filename = NULL;
|
|
map_info.log = stdout;
|
|
|
/* fill cmd line args with default values */
|
/* fill cmd line args with default values */
|
args->memory_map = MAP_DEFAULT;
|
args->memory_map = MAP_DEFAULT;
|
args->trap_on_reserved = 1;
|
args->trap_on_reserved = 1;
|
|
args->emulate_some_mips32 = 1;
|
args->start_addr = VECTOR_RESET;
|
args->start_addr = VECTOR_RESET;
|
args->do_unaligned = 0;
|
args->do_unaligned = 0;
|
args->no_prompt = 0;
|
args->no_prompt = 0;
|
args->breakpoint = 0xffffffff;
|
args->breakpoint = 0xffffffff;
|
args->log_file_name = "sw_sim_log.txt";
|
args->log_file_name = "sw_sim_log.txt";
|
args->log_trigger_address = VECTOR_RESET;
|
args->log_trigger_address = VECTOR_RESET;
|
|
args->map_filename = NULL;
|
for(i=0;i<NUM_MEM_BLOCKS;i++){
|
for(i=0;i<NUM_MEM_BLOCKS;i++){
|
args->bin_filename[i] = NULL;
|
args->bin_filename[i] = NULL;
|
args->offset[i] = 0;
|
args->offset[i] = 0;
|
}
|
}
|
|
|
Line 1717... |
Line 1990... |
/* plasma simulation not supported, error*/
|
/* plasma simulation not supported, error*/
|
printf("Error: program compiled for compatibility to MIPS-I\n");
|
printf("Error: program compiled for compatibility to MIPS-I\n");
|
return 0;
|
return 0;
|
}
|
}
|
else if(strcmp(argv[i],"--uclinux")==0){
|
else if(strcmp(argv[i],"--uclinux")==0){
|
args->memory_map = MAP_UCLINUX;
|
args->memory_map = MAP_UCLINUX_BRAM;
|
/* FIXME selecting uClinux enables unaligned L/S emulation */
|
/* FIXME selecting uClinux enables unaligned L/S emulation */
|
args->do_unaligned = 1;
|
args->do_unaligned = 1;
|
}
|
}
|
else if(strcmp(argv[i],"--small")==0){
|
else if(strcmp(argv[i],"--small")==0){
|
args->memory_map = MAP_SMALL;
|
args->memory_map = MAP_SMALL;
|
Line 1733... |
Line 2006... |
args->no_prompt = 1;
|
args->no_prompt = 1;
|
}
|
}
|
else if(strcmp(argv[i],"--notrap10")==0){
|
else if(strcmp(argv[i],"--notrap10")==0){
|
args->trap_on_reserved = 0;
|
args->trap_on_reserved = 0;
|
}
|
}
|
|
else if(strcmp(argv[i],"--nomips32")==0){
|
|
args->emulate_some_mips32 = 0;
|
|
}
|
else if(strncmp(argv[i],"--bram=", strlen("--bram="))==0){
|
else if(strncmp(argv[i],"--bram=", strlen("--bram="))==0){
|
args->bin_filename[0] = &(argv[i][strlen("--bram=")]);
|
args->bin_filename[0] = &(argv[i][strlen("--bram=")]);
|
}
|
}
|
else if(strncmp(argv[i],"--flash=", strlen("--flash="))==0){
|
else if(strncmp(argv[i],"--flash=", strlen("--flash="))==0){
|
args->bin_filename[3] = &(argv[i][strlen("--flash=")]);
|
args->bin_filename[3] = &(argv[i][strlen("--flash=")]);
|
}
|
}
|
else if(strncmp(argv[i],"--xram=", strlen("--xram="))==0){
|
else if(strncmp(argv[i],"--xram=", strlen("--xram="))==0){
|
args->bin_filename[1] = &(argv[i][strlen("--xram=")]);
|
args->bin_filename[1] = &(argv[i][strlen("--xram=")]);
|
}
|
}
|
|
else if(strncmp(argv[i],"--map=", strlen("--map="))==0){
|
|
args->map_filename = &(argv[i][strlen("--map=")]);
|
|
}
|
|
else if(strncmp(argv[i],"--trace_log=", strlen("--trace_log="))==0){
|
|
map_info.log_filename = &(argv[i][strlen("--trace_log=")]);
|
|
}
|
else if(strncmp(argv[i],"--start=", strlen("--start="))==0){
|
else if(strncmp(argv[i],"--start=", strlen("--start="))==0){
|
sscanf(&(argv[i][strlen("--start=")]), "%x", &(args->start_addr));
|
sscanf(&(argv[i][strlen("--start=")]), "%x", &(args->start_addr));
|
}
|
}
|
else if(strncmp(argv[i],"--kernel=", strlen("--kernel="))==0){
|
else if(strncmp(argv[i],"--kernel=", strlen("--kernel="))==0){
|
args->bin_filename[1] = &(argv[i][strlen("--kernel=")]);
|
args->bin_filename[1] = &(argv[i][strlen("--kernel=")]);
|
Line 1782... |
Line 2064... |
printf("--bram=<file name> : BRAM initialization file\n");
|
printf("--bram=<file name> : BRAM initialization file\n");
|
printf("--xram=<file name> : XRAM initialization file\n");
|
printf("--xram=<file name> : XRAM initialization file\n");
|
printf("--kernel=<file name> : XRAM initialization file for uClinux kernel\n");
|
printf("--kernel=<file name> : XRAM initialization file for uClinux kernel\n");
|
printf(" (loads at block offset 0x2000)\n");
|
printf(" (loads at block offset 0x2000)\n");
|
printf("--flash=<file name> : FLASH initialization file\n");
|
printf("--flash=<file name> : FLASH initialization file\n");
|
|
printf("--map=<file name> : Map file to be used for tracing, if any\n");
|
|
printf("--trace_log=<file name> : Log file used for tracing, if any\n");
|
printf("--trigger=<hex number> : Log trigger address\n");
|
printf("--trigger=<hex number> : Log trigger address\n");
|
printf("--break=<hex number> : Breakpoint address\n");
|
printf("--break=<hex number> : Breakpoint address\n");
|
printf("--start=<hex number> : Start here instead of at reset vector\n");
|
printf("--start=<hex number> : Start here instead of at reset vector\n");
|
printf("--notrap10 : Reserverd opcodes are NOPs and don't trap\n");
|
printf("--notrap10 : Reserverd opcodes are NOPs and don't trap\n");
|
|
printf("--nomips32 : Do not emulate any mips32 opcodes\n");
|
printf("--plasma : Simulate Plasma instead of MIPS-I\n");
|
printf("--plasma : Simulate Plasma instead of MIPS-I\n");
|
printf("--uclinux : Use memory map tailored to uClinux\n");
|
printf("--uclinux : Use memory map tailored to uClinux\n");
|
printf("--unaligned : Implement unaligned load/store instructions\n");
|
printf("--unaligned : Implement unaligned load/store instructions\n");
|
printf("--noprompt : Run in batch mode\n");
|
printf("--noprompt : Run in batch mode\n");
|
printf("--stop_at_zero : Stop simulation when fetching from address 0x0\n");
|
printf("--stop_at_zero : Stop simulation when fetching from address 0x0\n");
|