| 1 | 2 | ja_rd | /*------------------------------------------------------------------------------
 | 
      
         | 2 |  |  | * slite.c -- MIPS-I simulator based on Steve Rhoad's "mlite"
 | 
      
         | 3 |  |  | *
 | 
      
         | 4 | 163 | ja_rd | * This is a heavily modified version of Steve Rhoad's "mlite" simulator, which
 | 
      
         | 5 | 2 | ja_rd | * is part of his PLASMA project (original date: 1/31/01).
 | 
      
         | 6 |  |  | *
 | 
      
         | 7 |  |  | *-------------------------------------------------------------------------------
 | 
      
         | 8 |  |  | * Usage:
 | 
      
         | 9 | 163 | ja_rd | *     slite [options]
 | 
      
         | 10 | 2 | ja_rd | *
 | 
      
         | 11 | 163 | ja_rd | * See function 'usage' for a very brief explaination of the available options.
 | 
      
         | 12 | 2 | ja_rd | *
 | 
      
         | 13 | 163 | ja_rd | * Generally, upon startup the program will allocate some RAM for the simulated
 | 
      
         | 14 |  |  | * system and initialize it with the contents of one or more plain binary,
 | 
      
         | 15 |  |  | * big-endian object files. Then it will simulate a cpu reset and start the
 | 
      
         | 16 |  |  | * simulation, in interactive or batch mode.
 | 
      
         | 17 | 2 | ja_rd | *
 | 
      
         | 18 |  |  | * A simulation log file will be dumped to file "sw_sim_log.txt". This log can be
 | 
      
         | 19 |  |  | * used to compare with an equivalent log dumped by the hardware simulation, as
 | 
      
         | 20 |  |  | * a simple way to validate the hardware for a given program. See the project
 | 
      
         | 21 |  |  | * readme files for details.
 | 
      
         | 22 |  |  | *
 | 
      
         | 23 |  |  | *-------------------------------------------------------------------------------
 | 
      
         | 24 | 163 | ja_rd | * This program simulates the CPU connected to a certain memory map (chosen from
 | 
      
         | 25 |  |  | * a set of predefined options) and to a UART.
 | 
      
         | 26 |  |  | * The UART is hardcoded at a fixed address and is not configurable in runtime.
 | 
      
         | 27 |  |  | * The simulated UART includes the real UART status bits, hardcoded to 'always
 | 
      
         | 28 |  |  | * ready' so that software and hardware simulations can be made identical with
 | 
      
         | 29 |  |  | * more ease (no need to simulate the actual cycle count of TX/RX, etc.).
 | 
      
         | 30 |  |  | *-------------------------------------------------------------------------------
 | 
      
         | 31 | 2 | ja_rd | * KNOWN BUGS:
 | 
      
         | 32 |  |  | *
 | 
      
         | 33 |  |  | *-------------------------------------------------------------------------------
 | 
      
         | 34 |  |  | * @date 2011-jan-16
 | 
      
         | 35 |  |  | *
 | 
      
         | 36 |  |  | *-------------------------------------------------------------------------------
 | 
      
         | 37 |  |  | * COPYRIGHT:    Software placed into the public domain by the author.
 | 
      
         | 38 |  |  | *               Software 'as is' without warranty.  Author liable for nothing.
 | 
      
         | 39 |  |  | *
 | 
      
         | 40 | 163 | ja_rd | * IMPORTANT: Assumes host is little endian and target is big endian.
 | 
      
         | 41 | 2 | ja_rd | *-----------------------------------------------------------------------------*/
 | 
      
         | 42 | 166 | ja_rd |  
 | 
      
         | 43 |  |  | #include <errno.h>
 | 
      
         | 44 | 2 | ja_rd | #include <stdio.h>
 | 
      
         | 45 | 11 | ja_rd | #include <stdlib.h>
 | 
      
         | 46 |  |  | #include <stdint.h>
 | 
      
         | 47 | 2 | ja_rd | #include <string.h>
 | 
      
         | 48 |  |  | #include <ctype.h>
 | 
      
         | 49 |  |  | #include <assert.h>
 | 
      
         | 50 |  |  |  
 | 
      
         | 51 | 163 | ja_rd | /** CPU identification code (contents of register CP0[15], PRId */
 | 
      
         | 52 | 152 | ja_rd | #define R3000_ID (0x00000200)
 | 
      
         | 53 |  |  |  
 | 
      
         | 54 | 31 | ja_rd | /** Set to !=0 to disable file logging (much faster simulation) */
 | 
      
         | 55 | 163 | ja_rd | /* alternately you can just set an unreachable log trigger address */
 | 
      
         | 56 | 2 | ja_rd | #define FILE_LOGGING_DISABLED (0)
 | 
      
         | 57 |  |  | /** Define to enable cache simulation (unimplemented) */
 | 
      
         | 58 |  |  | //#define ENABLE_CACHE
 | 
      
         | 59 | 163 | ja_rd | /** Set to !=0 to display a fancier listing of register values */
 | 
      
         | 60 |  |  | #define FANCY_REGISTER_DISPLAY (1)
 | 
      
         | 61 | 31 | ja_rd |  
 | 
      
         | 62 |  |  |  
 | 
      
         | 63 |  |  | /*---- Definition of simulated system parameters -----------------------------*/
 | 
      
         | 64 |  |  |  
 | 
      
         | 65 | 61 | ja_rd | #define VECTOR_RESET (0xbfc00000)
 | 
      
         | 66 |  |  | #define VECTOR_TRAP  (0xbfc00180)
 | 
      
         | 67 |  |  |  
 | 
      
         | 68 |  |  | /** Definition of a memory block */
 | 
      
         | 69 | 31 | ja_rd | typedef struct s_block {
 | 
      
         | 70 |  |  |     uint32_t start;
 | 
      
         | 71 |  |  |     uint32_t size;
 | 
      
         | 72 | 44 | ja_rd |     uint32_t mask;
 | 
      
         | 73 | 61 | ja_rd |     uint32_t read_only;
 | 
      
         | 74 | 31 | ja_rd |     uint8_t  *mem;
 | 
      
         | 75 | 61 | ja_rd |     char     *area_name;
 | 
      
         | 76 | 31 | ja_rd | } t_block;
 | 
      
         | 77 | 105 | ja_rd |  
 | 
      
         | 78 |  |  | #define NUM_MEM_BLOCKS      (4)
 | 
      
         | 79 | 152 | ja_rd | #define NUM_MEM_MAPS        (4)
 | 
      
         | 80 | 105 | ja_rd |  
 | 
      
         | 81 |  |  | /** Definition of a memory map */
 | 
      
         | 82 |  |  | /* FIXME i/o addresses missing, hardcoded */
 | 
      
         | 83 |  |  | typedef struct s_map {
 | 
      
         | 84 |  |  |     t_block blocks[NUM_MEM_BLOCKS];
 | 
      
         | 85 |  |  | } t_map;
 | 
      
         | 86 |  |  |  
 | 
      
         | 87 | 31 | ja_rd |  
 | 
      
         | 88 |  |  |  
 | 
      
         | 89 | 61 | ja_rd | /*  Here's where we define the memory areas (blocks) of the system.
 | 
      
         | 90 |  |  |  
 | 
      
         | 91 |  |  |     The blocks should be defined in this order: BRAM, XRAM, FLASH
 | 
      
         | 92 |  |  |  
 | 
      
         | 93 |  |  |     BRAM is FPGA block ram initialized with bootstrap code
 | 
      
         | 94 |  |  |     XRAM is external SRAM
 | 
      
         | 95 |  |  |     FLASH is external flash
 | 
      
         | 96 |  |  |  
 | 
      
         | 97 |  |  |     Give any area a size of 0x0 to leave it unused.
 | 
      
         | 98 |  |  |  
 | 
      
         | 99 |  |  |     When a binary file is specified in the cmd line for one of these areas, it
 | 
      
         | 100 |  |  |     will be used to initialize it, checking bounds.
 | 
      
         | 101 |  |  |  
 | 
      
         | 102 |  |  |     Memory decoding is done in the order the blocks are defined; the address
 | 
      
         | 103 |  |  |     is anded with field .mask and then compared to field .start. If they match
 | 
      
         | 104 |  |  |     the address modulo the field .size is used to index the memory block, giving
 | 
      
         | 105 |  |  |     a 'mirror' effect. All of this simulates how the actual hardware works.
 | 
      
         | 106 |  |  |     Make sure the blocks don't overlap or the scheme will fail.
 | 
      
         | 107 | 44 | ja_rd | */
 | 
      
         | 108 | 31 | ja_rd |  
 | 
      
         | 109 | 152 | ja_rd | #define MAP_DEFAULT         (0)
 | 
      
         | 110 |  |  | #define MAP_UCLINUX_BRAM    (1)  /* debug only */
 | 
      
         | 111 |  |  | #define MAP_SMALL           (2)
 | 
      
         | 112 |  |  | #define MAP_UCLINUX         (3)
 | 
      
         | 113 | 105 | ja_rd |  
 | 
      
         | 114 |  |  | t_map memory_maps[NUM_MEM_MAPS] = {
 | 
      
         | 115 |  |  |     {/* Experimental memory map (default) */
 | 
      
         | 116 |  |  |         {/* Bootstrap BRAM, read only */
 | 
      
         | 117 |  |  |         {VECTOR_RESET,  0x00004800, 0xf8000000, 1, NULL, "Boot BRAM"},
 | 
      
         | 118 |  |  |         /* main external ram block  */
 | 
      
         | 119 |  |  |         {0x00000000,    0x00080000, 0xf8000000, 0, NULL, "XRAM0"},
 | 
      
         | 120 |  |  |         /* main external ram block  */
 | 
      
         | 121 |  |  |         {0x80000000,    0x00080000, 0xf8000000, 0, NULL, "XRAM1"},
 | 
      
         | 122 |  |  |         /* external flash block */
 | 
      
         | 123 |  |  |         {0xb0000000,    0x00040000, 0xf8000000, 0, NULL, "Flash"},
 | 
      
         | 124 |  |  |         }
 | 
      
         | 125 |  |  |     },
 | 
      
         | 126 |  |  |  
 | 
      
         | 127 | 152 | ja_rd |     {/* uClinux memory map with bootstrap BRAM, debug only, to be removed */
 | 
      
         | 128 | 105 | ja_rd |         {/* Bootstrap BRAM, read only */
 | 
      
         | 129 |  |  |         {VECTOR_RESET,  0x00001000, 0xf8000000, 1, NULL, "Boot BRAM"},
 | 
      
         | 130 |  |  |         /* main external ram block  */
 | 
      
         | 131 | 166 | ja_rd |         {0x80000000,    0x00800000, 0xf8000000, 0, NULL, "XRAM0"},
 | 
      
         | 132 |  |  |         {0x00000000,    0x00800000, 0xf8000000, 0, NULL, "XRAM1"},
 | 
      
         | 133 | 105 | ja_rd |         /* external flash block */
 | 
      
         | 134 |  |  |         {0xb0000000,    0x00100000, 0xf8000000, 0, NULL, "Flash"},
 | 
      
         | 135 |  |  |         }
 | 
      
         | 136 | 108 | ja_rd |     },
 | 
      
         | 137 |  |  |  
 | 
      
         | 138 |  |  |     {/* Experimental memory map with small XRAM */
 | 
      
         | 139 |  |  |         {/* Bootstrap BRAM, read only */
 | 
      
         | 140 |  |  |         {VECTOR_RESET,  0x00004800, 0xf8000000, 1, NULL, "Boot BRAM"},
 | 
      
         | 141 |  |  |         /* main external ram block  */
 | 
      
         | 142 |  |  |         {0x00000000,    0x00001000, 0xf8000000, 0, NULL, "XRAM0"},
 | 
      
         | 143 |  |  |         /* main external ram block  */
 | 
      
         | 144 |  |  |         {0x80000000,    0x00001000, 0xf8000000, 0, NULL, "XRAM1"},
 | 
      
         | 145 |  |  |         /* external flash block */
 | 
      
         | 146 |  |  |         {0xb0000000,    0x00040000, 0xf8000000, 0, NULL, "Flash"},
 | 
      
         | 147 |  |  |         }
 | 
      
         | 148 | 152 | ja_rd |     },
 | 
      
         | 149 |  |  |  
 | 
      
         | 150 |  |  |     {/* uClinux memory map with FLASH and XRAM */
 | 
      
         | 151 |  |  |         {/* Flash mapped at two different addresses is actually meant to be
 | 
      
         | 152 |  |  |             a single chip (note they have the same size). */
 | 
      
         | 153 |  |  |          /* E.g. put the bootloader at 0xbfc00000 and the romfs at 0xb0020000;
 | 
      
         | 154 |  |  |             chip offsets will be 0x0 and 0x20000. */
 | 
      
         | 155 |  |  |          /* Don't forget there's no address translation here. */
 | 
      
         | 156 |  |  |         {0xbfc00000,    0x00400000, 0xf8000000, 1, NULL, "Flash (bootloader)"},
 | 
      
         | 157 |  |  |         {0xb0000000,    0x00400000, 0xf8000000, 1, NULL, "Flash (romfs)"},
 | 
      
         | 158 |  |  |         /* main external ram block (kernal & user areas ) */
 | 
      
         | 159 |  |  |         {0x80000000,    0x00200000, 0xf8000000, 0, NULL, "XRAM (kernel)"},
 | 
      
         | 160 |  |  |         {0x00000000,    0x00400000, 0xf8000000, 0, NULL, "XRAM (user)"},
 | 
      
         | 161 |  |  |         }
 | 
      
         | 162 | 105 | ja_rd |     },
 | 
      
         | 163 | 31 | ja_rd | };
 | 
      
         | 164 | 105 | ja_rd |  
 | 
      
         | 165 | 31 | ja_rd |  
 | 
      
         | 166 | 61 | ja_rd | /*---- end of system parameters ----------------------------------------------*/
 | 
      
         | 167 |  |  |  
 | 
      
         | 168 |  |  |  
 | 
      
         | 169 |  |  | /** Values for the command line arguments */
 | 
      
         | 170 |  |  | typedef struct s_args {
 | 
      
         | 171 | 163 | ja_rd |     /** !=0 to trap on unimplemented opcodes, 0 to print warning and NOP */
 | 
      
         | 172 |  |  |     uint32_t trap_on_reserved;
 | 
      
         | 173 | 166 | ja_rd |     /** !=0 to emulate some common mips32 opcodes */
 | 
      
         | 174 |  |  |     uint32_t emulate_some_mips32;
 | 
      
         | 175 | 163 | ja_rd |     /** address to start execution from (by default, reset vector) */
 | 
      
         | 176 |  |  |     uint32_t start_addr;
 | 
      
         | 177 | 105 | ja_rd |     /** memory map to be used */
 | 
      
         | 178 |  |  |     uint32_t memory_map;
 | 
      
         | 179 |  |  |     /** implement unaligned load/stores (don't just trap them) */
 | 
      
         | 180 |  |  |     uint32_t do_unaligned;
 | 
      
         | 181 |  |  |     /** start simulation without showing monitor prompt and quit on
 | 
      
         | 182 |  |  |         end condition -- useful for batch runs */
 | 
      
         | 183 |  |  |     uint32_t no_prompt;
 | 
      
         | 184 |  |  |     /** breakpoint address (0xffffffff if unused) */
 | 
      
         | 185 |  |  |     uint32_t breakpoint;
 | 
      
         | 186 |  |  |     /** a code fetch from this address starts logging */
 | 
      
         | 187 | 93 | ja_rd |     uint32_t log_trigger_address;
 | 
      
         | 188 | 105 | ja_rd |     /** full name of log file */
 | 
      
         | 189 | 93 | ja_rd |     char *log_file_name;
 | 
      
         | 190 | 105 | ja_rd |     /** bin file to load to each area or null */
 | 
      
         | 191 |  |  |     char *bin_filename[NUM_MEM_BLOCKS];
 | 
      
         | 192 | 166 | ja_rd |     /** map file to be used for function call tracing, if any */
 | 
      
         | 193 |  |  |     char *map_filename;
 | 
      
         | 194 | 105 | ja_rd |     /** offset into area (in bytes) where bin wile will be loaded */
 | 
      
         | 195 |  |  |     uint32_t offset[NUM_MEM_BLOCKS];
 | 
      
         | 196 | 61 | ja_rd | } t_args;
 | 
      
         | 197 |  |  | /** Parse cmd line args globally accessible */
 | 
      
         | 198 |  |  | t_args cmd_line_args;
 | 
      
         | 199 |  |  |  
 | 
      
         | 200 |  |  |  
 | 
      
         | 201 |  |  | /*---- Endianess conversion macros -------------------------------------------*/
 | 
      
         | 202 | 2 | ja_rd |  
 | 
      
         | 203 |  |  | #define ntohs(A) ( ((A)>>8) | (((A)&0xff)<<8) )
 | 
      
         | 204 |  |  | #define htons(A) ntohs(A)
 | 
      
         | 205 |  |  | #define ntohl(A) ( ((A)>>24) | (((A)&0xff0000)>>8) | (((A)&0xff00)<<8) | ((A)<<24) )
 | 
      
         | 206 |  |  | #define htonl(A) ntohl(A)
 | 
      
         | 207 |  |  |  
 | 
      
         | 208 |  |  | /*---- OS-dependent support functions and definitions ------------------------*/
 | 
      
         | 209 |  |  | #ifndef WIN32
 | 
      
         | 210 |  |  | //Support for Linux
 | 
      
         | 211 |  |  | #define putch putchar
 | 
      
         | 212 |  |  | #include <termios.h>
 | 
      
         | 213 |  |  | #include <unistd.h>
 | 
      
         | 214 |  |  |  
 | 
      
         | 215 | 31 | ja_rd | void slite_sleep(unsigned int value){
 | 
      
         | 216 |  |  |     usleep(value * 1000);
 | 
      
         | 217 | 2 | ja_rd | }
 | 
      
         | 218 |  |  |  
 | 
      
         | 219 | 31 | ja_rd | int kbhit(void){
 | 
      
         | 220 |  |  |     struct termios oldt, newt;
 | 
      
         | 221 |  |  |     struct timeval tv;
 | 
      
         | 222 |  |  |     fd_set read_fd;
 | 
      
         | 223 | 2 | ja_rd |  
 | 
      
         | 224 | 31 | ja_rd |     tcgetattr(STDIN_FILENO, &oldt);
 | 
      
         | 225 |  |  |     newt = oldt;
 | 
      
         | 226 |  |  |     newt.c_lflag &= ~(ICANON | ECHO);
 | 
      
         | 227 |  |  |     tcsetattr(STDIN_FILENO, TCSANOW, &newt);
 | 
      
         | 228 |  |  |     tv.tv_sec=0;
 | 
      
         | 229 |  |  |     tv.tv_usec=0;
 | 
      
         | 230 |  |  |     FD_ZERO(&read_fd);
 | 
      
         | 231 |  |  |     FD_SET(0,&read_fd);
 | 
      
         | 232 |  |  |     if(select(1, &read_fd, NULL, NULL, &tv) == -1){
 | 
      
         | 233 |  |  |         return 0;
 | 
      
         | 234 |  |  |     }
 | 
      
         | 235 |  |  |     //tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
 | 
      
         | 236 |  |  |     if(FD_ISSET(0,&read_fd)){
 | 
      
         | 237 |  |  |         return 1;
 | 
      
         | 238 |  |  |     }
 | 
      
         | 239 |  |  |     return 0;
 | 
      
         | 240 | 2 | ja_rd | }
 | 
      
         | 241 |  |  |  
 | 
      
         | 242 | 31 | ja_rd | int getch(void){
 | 
      
         | 243 |  |  |     struct termios oldt, newt;
 | 
      
         | 244 |  |  |     int ch;
 | 
      
         | 245 | 2 | ja_rd |  
 | 
      
         | 246 | 31 | ja_rd |     tcgetattr(STDIN_FILENO, &oldt);
 | 
      
         | 247 |  |  |     newt = oldt;
 | 
      
         | 248 |  |  |     newt.c_lflag &= ~(ICANON | ECHO);
 | 
      
         | 249 |  |  |     tcsetattr(STDIN_FILENO, TCSANOW, &newt);
 | 
      
         | 250 |  |  |     ch = getchar();
 | 
      
         | 251 |  |  |     //tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
 | 
      
         | 252 |  |  |     return ch;
 | 
      
         | 253 | 2 | ja_rd | }
 | 
      
         | 254 |  |  | #else
 | 
      
         | 255 |  |  | //Support for Windows
 | 
      
         | 256 |  |  | #include <conio.h>
 | 
      
         | 257 | 31 | ja_rd | extern void __stdcall Sleep(unsigned long value);
 | 
      
         | 258 |  |  |  
 | 
      
         | 259 |  |  | void slite_sleep(unsigned int value){
 | 
      
         | 260 |  |  |     Sleep(value);
 | 
      
         | 261 |  |  | }
 | 
      
         | 262 |  |  |  
 | 
      
         | 263 | 2 | ja_rd | #endif
 | 
      
         | 264 |  |  | /*---- End of OS-dependent support functions and definitions -----------------*/
 | 
      
         | 265 |  |  |  
 | 
      
         | 266 |  |  | /*---- Hardware system parameters --------------------------------------------*/
 | 
      
         | 267 |  |  |  
 | 
      
         | 268 |  |  | /* Much of this is a remnant from Plasma's mlite and is  no longer used. */
 | 
      
         | 269 |  |  | /* FIXME Refactor HW system params */
 | 
      
         | 270 |  |  |  
 | 
      
         | 271 | 105 | ja_rd | #define DBG_REGS          (0x20010000)
 | 
      
         | 272 | 166 | ja_rd | #define UART_WRITE        (0x20000000)
 | 
      
         | 273 |  |  | #define UART_READ         (0x20000000)
 | 
      
         | 274 |  |  |  
 | 
      
         | 275 |  |  | /* FIXME The following addresses are remnants of Plasma to be removed */
 | 
      
         | 276 | 2 | ja_rd | #define IRQ_MASK          0x20000010
 | 
      
         | 277 |  |  | #define IRQ_STATUS        0x20000020
 | 
      
         | 278 |  |  | #define CONFIG_REG        0x20000070
 | 
      
         | 279 |  |  | #define MMU_PROCESS_ID    0x20000080
 | 
      
         | 280 |  |  | #define MMU_FAULT_ADDR    0x20000090
 | 
      
         | 281 |  |  | #define MMU_TLB           0x200000a0
 | 
      
         | 282 |  |  |  
 | 
      
         | 283 |  |  | #define IRQ_UART_READ_AVAILABLE  0x001
 | 
      
         | 284 |  |  | #define IRQ_UART_WRITE_AVAILABLE 0x002
 | 
      
         | 285 |  |  | #define IRQ_COUNTER18_NOT        0x004
 | 
      
         | 286 |  |  | #define IRQ_COUNTER18            0x008
 | 
      
         | 287 |  |  | #define IRQ_MMU                  0x200
 | 
      
         | 288 |  |  |  
 | 
      
         | 289 | 5 | ja_rd | /*----------------------------------------------------------------------------*/
 | 
      
         | 290 | 2 | ja_rd |  
 | 
      
         | 291 | 5 | ja_rd | /* These are flags that will be used to notify the main cycle function of any
 | 
      
         | 292 |  |  |    failed assertions in its subfunctions. */
 | 
      
         | 293 |  |  | #define ASRT_UNALIGNED_READ         (1<<0)
 | 
      
         | 294 |  |  | #define ASRT_UNALIGNED_WRITE        (1<<1)
 | 
      
         | 295 |  |  |  
 | 
      
         | 296 |  |  | char *assertion_messages[2] = {
 | 
      
         | 297 |  |  |    "Unaligned read",
 | 
      
         | 298 |  |  |    "Unaligned write"
 | 
      
         | 299 |  |  | };
 | 
      
         | 300 |  |  |  
 | 
      
         | 301 |  |  |  
 | 
      
         | 302 | 2 | ja_rd | /** Length of debugging jump target queue */
 | 
      
         | 303 |  |  | #define TRACE_BUFFER_SIZE (32)
 | 
      
         | 304 |  |  |  
 | 
      
         | 305 | 31 | ja_rd | typedef struct s_trace {
 | 
      
         | 306 | 2 | ja_rd |    unsigned int buf[TRACE_BUFFER_SIZE];   /**< queue of last jump targets */
 | 
      
         | 307 |  |  |    unsigned int next;                     /**< internal queue head pointer */
 | 
      
         | 308 |  |  |    FILE *log;                             /**< text log file or NULL */
 | 
      
         | 309 | 93 | ja_rd |    int log_triggered;                     /**< !=0 if log has been triggered */
 | 
      
         | 310 |  |  |    uint32_t log_trigger_address;          /**< */
 | 
      
         | 311 | 2 | ja_rd |    int pr[32];                            /**< last value of register bank */
 | 
      
         | 312 | 152 | ja_rd |    int hi, lo, epc, status;               /**< last value of internal regs */
 | 
      
         | 313 | 163 | ja_rd |    int disasm_ptr;                        /**< disassembly pointer */
 | 
      
         | 314 | 31 | ja_rd | } t_trace;
 | 
      
         | 315 | 2 | ja_rd |  
 | 
      
         | 316 | 31 | ja_rd | typedef struct s_state {
 | 
      
         | 317 | 5 | ja_rd |    unsigned failed_assertions;            /**< assertion bitmap */
 | 
      
         | 318 |  |  |    unsigned faulty_address;               /**< addr that failed assertion */
 | 
      
         | 319 | 105 | ja_rd |    uint32_t do_unaligned;                 /**< !=0 to enable unaligned L/S */
 | 
      
         | 320 |  |  |    uint32_t breakpoint;                   /**< BP address of 0xffffffff */
 | 
      
         | 321 | 27 | ja_rd |  
 | 
      
         | 322 |  |  |    int delay_slot;              /**< !=0 if prev. instruction was a branch */
 | 
      
         | 323 | 5 | ja_rd |  
 | 
      
         | 324 | 2 | ja_rd |    int r[32];
 | 
      
         | 325 |  |  |    int opcode;
 | 
      
         | 326 | 53 | ja_rd |    int pc, pc_next, epc;
 | 
      
         | 327 |  |  |    uint32_t op_addr;            /**< address of opcode being simulated */
 | 
      
         | 328 | 2 | ja_rd |    unsigned int hi;
 | 
      
         | 329 |  |  |    unsigned int lo;
 | 
      
         | 330 | 27 | ja_rd |    int status;
 | 
      
         | 331 | 166 | ja_rd |    int32_t trap_cause;          /**< temporary trap code or <0 if no trap */
 | 
      
         | 332 | 27 | ja_rd |    unsigned cp0_cause;
 | 
      
         | 333 | 163 | ja_rd |    int userMode;                /**< DEPRECATED, to be removed */
 | 
      
         | 334 |  |  |    int processId;               /**< DEPRECATED, to be removed */
 | 
      
         | 335 |  |  |    int faultAddr;               /**< DEPRECATED, to be removed */
 | 
      
         | 336 |  |  |    int irqStatus;               /**< DEPRECATED, to be removed */
 | 
      
         | 337 | 2 | ja_rd |    int skip;
 | 
      
         | 338 | 163 | ja_rd |    t_trace t;
 | 
      
         | 339 | 31 | ja_rd |    t_block blocks[NUM_MEM_BLOCKS];
 | 
      
         | 340 | 2 | ja_rd |    int wakeup;
 | 
      
         | 341 |  |  |    int big_endian;
 | 
      
         | 342 | 31 | ja_rd | } t_state;
 | 
      
         | 343 | 163 | ja_rd |  
 | 
      
         | 344 |  |  | static char *reg_names[]={
 | 
      
         | 345 |  |  |     "zero","at","v0","v1","a0","a1","a2","a3",
 | 
      
         | 346 |  |  |     "t0","t1","t2","t3","t4","t5","t6","t7",
 | 
      
         | 347 |  |  |     "s0","s1","s2","s3","s4","s5","s6","s7",
 | 
      
         | 348 |  |  |     "t8","t9","k0","k1","gp","sp","s8","ra"
 | 
      
         | 349 |  |  | };
 | 
      
         | 350 | 2 | ja_rd |  
 | 
      
         | 351 |  |  | static char *opcode_string[]={
 | 
      
         | 352 | 163 | ja_rd |    "0SPECIAL","0REGIMM","1J","1JAL","2BEQ","2BNE","3BLEZ","3BGTZ",
 | 
      
         | 353 |  |  |    "5ADDI","5ADDIU","5SLTI","5SLTIU","5ANDI","5ORI","5XORI","6LUI",
 | 
      
         | 354 |  |  |    "cCOP0","cCOP1","cCOP2","cCOP3","2BEQL","2BNEL","3BLEZL","3BGTZL",
 | 
      
         | 355 | 166 | ja_rd |    "0?","0?","0?","0?","0SPECIAL2","0?","0?","0SPECIAL3",
 | 
      
         | 356 | 163 | ja_rd |    "8LB","8LH","8LWL","8LW","8LBU","8LHU","8LWR","0?",
 | 
      
         | 357 |  |  |    "8SB","8SH","8SWL","8SW","0?","0?","8SWR","0CACHE",
 | 
      
         | 358 |  |  |    "0LL","0LWC1","0LWC2","0LWC3","?","0LDC1","0LDC2","0LDC3"
 | 
      
         | 359 |  |  |    "0SC","0SWC1","0SWC2","0SWC3","?","0SDC1","0SDC2","0SDC3"
 | 
      
         | 360 | 2 | ja_rd | };
 | 
      
         | 361 |  |  |  
 | 
      
         | 362 |  |  | static char *special_string[]={
 | 
      
         | 363 | 163 | ja_rd |    "4SLL","0?","4SRL","4SRA","bSLLV","0?","bSRLV","bSRAV",
 | 
      
         | 364 |  |  |    "aJR","aJALR","0MOVZ","0MOVN","0SYSCALL","0BREAK","0?","0SYNC",
 | 
      
         | 365 |  |  |    "0MFHI","0MTHI","0MFLO","0MTLO","0?","0?","0?","0?",
 | 
      
         | 366 |  |  |    "0MULT","0MULTU","0DIV","0DIVU","0?","0?","0?","0?",
 | 
      
         | 367 |  |  |    "7ADD","7ADDU","7SUB","7SUBU","7AND","7OR","7XOR","7NOR",
 | 
      
         | 368 |  |  |    "0?","0?","7SLT","7SLTU","0?","0DADDU","0?","0?",
 | 
      
         | 369 |  |  |    "7TGE","7TGEU","7TLT","7TLTU","7TEQ","0?","7TNE","0?",
 | 
      
         | 370 |  |  |    "0?","0?","0?","0?","0?","0?","0?","0?"
 | 
      
         | 371 | 2 | ja_rd | };
 | 
      
         | 372 |  |  |  
 | 
      
         | 373 |  |  | static char *regimm_string[]={
 | 
      
         | 374 | 163 | ja_rd |    "9BLTZ","9BGEZ","9BLTZL","9BGEZL","0?","0?","0?","0?",
 | 
      
         | 375 |  |  |    "0TGEI","0TGEIU","0TLTI","0TLTIU","0TEQI","0?","0TNEI","0?",
 | 
      
         | 376 |  |  |    "9BLTZAL","9BEQZAL","9BLTZALL","9BGEZALL","0?","0?","0?","0?",
 | 
      
         | 377 |  |  |    "0?","0?","0?","0?","0?","0?","0?","0?"
 | 
      
         | 378 |  |  | };
 | 
      
         | 379 | 166 | ja_rd | /*
 | 
      
         | 380 |  |  | static char *special2_string[]={
 | 
      
         | 381 |  |  |     "0MADD","0MADDU","0MUL","0?",  "0?","0?","0?","0?",
 | 
      
         | 382 |  |  |     "0?","0?","0?","0?",  "0?","0?","0?","0?",
 | 
      
         | 383 |  |  |     "0?","0?","0?","0?",  "0?","0?","0?","0?",
 | 
      
         | 384 |  |  |     "0?","0?","0?","0?",  "0?","0?","0?","0?",
 | 
      
         | 385 | 2 | ja_rd |  
 | 
      
         | 386 | 166 | ja_rd |     "0CLZ","0CLO","0?","0?",  "0?","0?","0?","0?",
 | 
      
         | 387 |  |  |     "0?","0?","0?","0?",  "0?","0?","0?","0?",
 | 
      
         | 388 |  |  |     "0?","0?","0?","0?",  "0?","0?","0?","0?",
 | 
      
         | 389 |  |  |     "0?","0?","0?","0?",  "0?","0?","0?","0?",
 | 
      
         | 390 |  |  | };
 | 
      
         | 391 |  |  | */
 | 
      
         | 392 |  |  |  
 | 
      
         | 393 |  |  | /** local memory used by the console simulation code */
 | 
      
         | 394 | 2 | ja_rd | static unsigned int HWMemory[8];
 | 
      
         | 395 |  |  |  
 | 
      
         | 396 | 166 | ja_rd | #define MAP_MAX_FUNCTIONS  (400)
 | 
      
         | 397 |  |  | #define MAP_MAX_NAME_LEN   (80)
 | 
      
         | 398 |  |  |  
 | 
      
         | 399 |  |  | /** Information extracted from the map file, if any */
 | 
      
         | 400 |  |  | typedef struct {
 | 
      
         | 401 |  |  |     uint32_t num_functions;         /**< number of functions in the table */
 | 
      
         | 402 |  |  |     FILE *log;                      /**< text log file or stdout */
 | 
      
         | 403 |  |  |     char *log_filename;             /**< name of log file or NULL */
 | 
      
         | 404 |  |  |     uint32_t fn_address[MAP_MAX_FUNCTIONS];
 | 
      
         | 405 |  |  |     char fn_name[MAP_MAX_FUNCTIONS][MAP_MAX_NAME_LEN];
 | 
      
         | 406 |  |  | } t_map_info;
 | 
      
         | 407 |  |  |  
 | 
      
         | 408 |  |  | t_map_info map_info;
 | 
      
         | 409 |  |  |  
 | 
      
         | 410 | 2 | ja_rd | /*---- Local function prototypes ---------------------------------------------*/
 | 
      
         | 411 |  |  |  
 | 
      
         | 412 |  |  | /* Debug and logging */
 | 
      
         | 413 | 93 | ja_rd | void init_trace_buffer(t_state *s, t_args *args);
 | 
      
         | 414 | 31 | ja_rd | void close_trace_buffer(t_state *s);
 | 
      
         | 415 |  |  | void dump_trace_buffer(t_state *s);
 | 
      
         | 416 | 166 | ja_rd | uint32_t log_cycle(t_state *s);
 | 
      
         | 417 | 31 | ja_rd | void log_read(t_state *s, int full_address, int word_value, int size, int log);
 | 
      
         | 418 |  |  | void log_failed_assertions(t_state *s);
 | 
      
         | 419 | 93 | ja_rd | uint32_t log_enabled(t_state *s);
 | 
      
         | 420 |  |  | void trigger_log(t_state *s);
 | 
      
         | 421 | 152 | ja_rd | void print_opcode_fields(uint32_t opcode);
 | 
      
         | 422 | 166 | ja_rd | void reserved_opcode(uint32_t pc, uint32_t opcode, t_state* s);
 | 
      
         | 423 |  |  | int32_t read_map_file(char *filename, t_map_info* map);
 | 
      
         | 424 |  |  | void log_call(uint32_t to, uint32_t from);
 | 
      
         | 425 |  |  | void log_ret(uint32_t to, uint32_t from);
 | 
      
         | 426 |  |  | int32_t function_index(uint32_t address);
 | 
      
         | 427 | 2 | ja_rd |  
 | 
      
         | 428 | 61 | ja_rd | int32_t parse_cmd_line(uint32_t argc, char **argv, t_args *args);
 | 
      
         | 429 |  |  | void usage(void);
 | 
      
         | 430 |  |  |  
 | 
      
         | 431 | 31 | ja_rd | /* CPU model */
 | 
      
         | 432 |  |  | void free_cpu(t_state *s);
 | 
      
         | 433 | 105 | ja_rd | int init_cpu(t_state *s, t_args *args);
 | 
      
         | 434 |  |  | void reset_cpu(t_state *s);
 | 
      
         | 435 |  |  | void unimplemented(t_state *s, const char *txt);
 | 
      
         | 436 |  |  | void reverse_endianess(uint8_t *data, uint32_t bytes);
 | 
      
         | 437 | 31 | ja_rd |  
 | 
      
         | 438 | 2 | ja_rd | /* Hardware simulation */
 | 
      
         | 439 | 31 | ja_rd | int mem_read(t_state *s, int size, unsigned int address, int log);
 | 
      
         | 440 |  |  | void mem_write(t_state *s, int size, unsigned address, unsigned value, int log);
 | 
      
         | 441 | 53 | ja_rd | void start_load(t_state *s, uint32_t addr, int rt, int data);
 | 
      
         | 442 | 2 | ja_rd |  
 | 
      
         | 443 | 16 | ja_rd |  
 | 
      
         | 444 | 2 | ja_rd | /*---- Local functions -------------------------------------------------------*/
 | 
      
         | 445 | 166 | ja_rd |  
 | 
      
         | 446 |  |  | /*---- Call & ret tracing (EARLY DRAFT) --------------------------------------*/
 | 
      
         | 447 |  |  |  
 | 
      
         | 448 |  |  | static uint32_t call_depth = 0;
 | 
      
         | 449 |  |  |  
 | 
      
         | 450 |  |  | void log_ret(uint32_t to, uint32_t from){
 | 
      
         | 451 |  |  |     int32_t i,j;
 | 
      
         | 452 |  |  |  
 | 
      
         | 453 |  |  |     /* If no map file has been loaded, skip trace */
 | 
      
         | 454 |  |  |     if((!map_info.num_functions) || (!map_info.log)) return;
 | 
      
         | 455 |  |  |  
 | 
      
         | 456 |  |  |     if(call_depth>0){
 | 
      
         | 457 |  |  |         fprintf(map_info.log, "[%08x]  ", from);
 | 
      
         | 458 |  |  |         for(j=0;j<call_depth;j++){
 | 
      
         | 459 |  |  |             fprintf(map_info.log, ". ");
 | 
      
         | 460 |  |  |         }
 | 
      
         | 461 |  |  |         fprintf(map_info.log, "}\n");
 | 
      
         | 462 |  |  |         call_depth--;
 | 
      
         | 463 |  |  |     }
 | 
      
         | 464 |  |  |     else{
 | 
      
         | 465 |  |  |         i = function_index(to);
 | 
      
         | 466 |  |  |         if(i>=0){
 | 
      
         | 467 |  |  |             fprintf(map_info.log, "[%08x]  %s\n", from, map_info.fn_name[i]);
 | 
      
         | 468 |  |  |         }
 | 
      
         | 469 |  |  |         else{
 | 
      
         | 470 |  |  |             fprintf(map_info.log, "[%08x]  %08x\n", from, to);
 | 
      
         | 471 |  |  |         }
 | 
      
         | 472 |  |  |     }
 | 
      
         | 473 |  |  | }
 | 
      
         | 474 |  |  |  
 | 
      
         | 475 |  |  | /** */
 | 
      
         | 476 |  |  | void log_call(uint32_t to, uint32_t from){
 | 
      
         | 477 |  |  |     int32_t i,j;
 | 
      
         | 478 |  |  |  
 | 
      
         | 479 |  |  |     /* If no map file has been loaded, skip trace */
 | 
      
         | 480 |  |  |     if((!map_info.num_functions) || (!map_info.log)) return;
 | 
      
         | 481 |  |  |  
 | 
      
         | 482 |  |  |     i = function_index(to);
 | 
      
         | 483 |  |  |     if(i>=0){
 | 
      
         | 484 |  |  |         call_depth++;
 | 
      
         | 485 |  |  |         fprintf(map_info.log, "[%08x]  ", from);
 | 
      
         | 486 |  |  |         for(j=0;j<call_depth;j++){
 | 
      
         | 487 |  |  |             fprintf(map_info.log, ". ");
 | 
      
         | 488 |  |  |         }
 | 
      
         | 489 |  |  |         fprintf(map_info.log, "%s{\n", map_info.fn_name[i]);
 | 
      
         | 490 |  |  |     }
 | 
      
         | 491 |  |  | }
 | 
      
         | 492 |  |  |  
 | 
      
         | 493 |  |  | int32_t function_index(uint32_t address){
 | 
      
         | 494 |  |  |     uint32_t i;
 | 
      
         | 495 |  |  |  
 | 
      
         | 496 |  |  |     for(i=0;i<map_info.num_functions;i++){
 | 
      
         | 497 |  |  |         if(address==map_info.fn_address[i]){
 | 
      
         | 498 |  |  |             return i;
 | 
      
         | 499 |  |  |         }
 | 
      
         | 500 |  |  |     }
 | 
      
         | 501 |  |  |     return -1;
 | 
      
         | 502 |  |  | }
 | 
      
         | 503 |  |  |  
 | 
      
         | 504 |  |  | /*---- Execution log ---------------------------------------------------------*/
 | 
      
         | 505 | 2 | ja_rd |  
 | 
      
         | 506 |  |  | /** Log to file a memory read operation (not including target reg change) */
 | 
      
         | 507 | 31 | ja_rd | void log_read(t_state *s, int full_address, int word_value, int size, int log){
 | 
      
         | 508 | 147 | ja_rd |     /* if bit CP0.16==1, this is a D-Cache line invalidation access and
 | 
      
         | 509 |  |  |            the HW will not read any actual data, so skip the log (@note1) */
 | 
      
         | 510 |  |  |     if(log_enabled(s) && log!=0 && !(s->status & 0x00010000)){
 | 
      
         | 511 | 53 | ja_rd |         fprintf(s->t.log, "(%08X) [%08X] <**>=%08X RD\n",
 | 
      
         | 512 |  |  |               s->op_addr, full_address, word_value);
 | 
      
         | 513 |  |  |     }
 | 
      
         | 514 | 2 | ja_rd | }
 | 
      
         | 515 |  |  |  
 | 
      
         | 516 |  |  | /** Read memory, optionally logging */
 | 
      
         | 517 | 31 | ja_rd | int mem_read(t_state *s, int size, unsigned int address, int log){
 | 
      
         | 518 |  |  |     unsigned int value=0, word_value=0, i, ptr;
 | 
      
         | 519 |  |  |     unsigned int full_address = address;
 | 
      
         | 520 | 2 | ja_rd |  
 | 
      
         | 521 | 31 | ja_rd |     s->irqStatus |= IRQ_UART_WRITE_AVAILABLE;
 | 
      
         | 522 |  |  |     switch(address){
 | 
      
         | 523 |  |  |     case UART_READ:
 | 
      
         | 524 |  |  |         /* FIXME Take input from text file */
 | 
      
         | 525 | 93 | ja_rd |         while(!kbhit());
 | 
      
         | 526 |  |  |         HWMemory[0] = getch();
 | 
      
         | 527 |  |  |         //s->irqStatus &= ~IRQ_UART_READ_AVAILABLE; //clear bit
 | 
      
         | 528 |  |  |         printf("%c", HWMemory[0]);
 | 
      
         | 529 |  |  |         return (HWMemory[0] << 24) | 0x03;
 | 
      
         | 530 | 31 | ja_rd |     case IRQ_MASK:
 | 
      
         | 531 |  |  |        return HWMemory[1];
 | 
      
         | 532 |  |  |     case IRQ_MASK + 4:
 | 
      
         | 533 |  |  |        slite_sleep(10);
 | 
      
         | 534 |  |  |        return 0;
 | 
      
         | 535 |  |  |     case IRQ_STATUS:
 | 
      
         | 536 |  |  |        /*if(kbhit())
 | 
      
         | 537 |  |  |           s->irqStatus |= IRQ_UART_READ_AVAILABLE;
 | 
      
         | 538 |  |  |        return s->irqStatus;
 | 
      
         | 539 |  |  |        */
 | 
      
         | 540 |  |  |        /* FIXME Optionally simulate UART TX delay */
 | 
      
         | 541 |  |  |        word_value = 0x00000003; /* Ready to TX and RX */
 | 
      
         | 542 | 53 | ja_rd |        //log_read(s, full_address, word_value, size, log);
 | 
      
         | 543 | 31 | ja_rd |        return word_value;
 | 
      
         | 544 |  |  |     case MMU_PROCESS_ID:
 | 
      
         | 545 |  |  |        return s->processId;
 | 
      
         | 546 |  |  |     case MMU_FAULT_ADDR:
 | 
      
         | 547 |  |  |        return s->faultAddr;
 | 
      
         | 548 |  |  |     }
 | 
      
         | 549 |  |  |  
 | 
      
         | 550 |  |  |     /* point ptr to the byte in the block, or NULL is the address is unmapped */
 | 
      
         | 551 |  |  |     ptr = 0;
 | 
      
         | 552 |  |  |     for(i=0;i<NUM_MEM_BLOCKS;i++){
 | 
      
         | 553 | 61 | ja_rd |         if((address & s->blocks[i].mask) ==
 | 
      
         | 554 |  |  |            (s->blocks[i].start & s->blocks[i].mask)){
 | 
      
         | 555 | 44 | ja_rd |             ptr = (unsigned)(s->blocks[i].mem) +
 | 
      
         | 556 |  |  |                   ((address - s->blocks[i].start) % s->blocks[i].size);
 | 
      
         | 557 | 31 | ja_rd |             break;
 | 
      
         | 558 |  |  |         }
 | 
      
         | 559 |  |  |     }
 | 
      
         | 560 |  |  |     if(!ptr){
 | 
      
         | 561 |  |  |         /* address out of mapped blocks: log and return zero */
 | 
      
         | 562 | 147 | ja_rd |         /* if bit CP0.16==1, this is a D-Cache line invalidation access and
 | 
      
         | 563 | 166 | ja_rd |            the HW will not read any actual data, so skip the log (@note1) */
 | 
      
         | 564 |  |  |         printf("MEM RD ERROR @ 0x%08x [0x%08x]\n", s->pc, full_address);
 | 
      
         | 565 | 147 | ja_rd |         if(log_enabled(s) && log!=0 && !(s->status & (1<<16))){
 | 
      
         | 566 | 31 | ja_rd |             fprintf(s->t.log, "(%08X) [%08X] <**>=%08X RD UNMAPPED\n",
 | 
      
         | 567 |  |  |                 s->pc, full_address, 0);
 | 
      
         | 568 |  |  |         }
 | 
      
         | 569 |  |  |         return 0;
 | 
      
         | 570 |  |  |     }
 | 
      
         | 571 |  |  |  
 | 
      
         | 572 |  |  |     /* get the whole word */
 | 
      
         | 573 |  |  |     word_value = *(int*)(ptr&0xfffffffc);
 | 
      
         | 574 |  |  |     if(s->big_endian){
 | 
      
         | 575 |  |  |         word_value = ntohl(word_value);
 | 
      
         | 576 |  |  |     }
 | 
      
         | 577 | 2 | ja_rd |  
 | 
      
         | 578 | 31 | ja_rd |     switch(size){
 | 
      
         | 579 |  |  |     case 4:
 | 
      
         | 580 |  |  |         if(address & 3){
 | 
      
         | 581 | 2 | ja_rd |             printf("Unaligned access PC=0x%x address=0x%x\n",
 | 
      
         | 582 | 31 | ja_rd |                 (int)s->pc, (int)address);
 | 
      
         | 583 |  |  |         }
 | 
      
         | 584 |  |  |         if((address & 3) != 0){
 | 
      
         | 585 |  |  |             /* unaligned word, log fault */
 | 
      
         | 586 | 5 | ja_rd |             s->failed_assertions |= ASRT_UNALIGNED_READ;
 | 
      
         | 587 |  |  |             s->faulty_address = address;
 | 
      
         | 588 |  |  |             address = address & 0xfffffffc;
 | 
      
         | 589 | 31 | ja_rd |         }
 | 
      
         | 590 |  |  |         value = *(int*)ptr;
 | 
      
         | 591 |  |  |         if(s->big_endian){
 | 
      
         | 592 |  |  |             value = ntohl(value);
 | 
      
         | 593 |  |  |         }
 | 
      
         | 594 |  |  |         break;
 | 
      
         | 595 |  |  |     case 2:
 | 
      
         | 596 |  |  |         if((address & 1) != 0){
 | 
      
         | 597 |  |  |             /* unaligned halfword, log fault */
 | 
      
         | 598 | 5 | ja_rd |             s->failed_assertions |= ASRT_UNALIGNED_READ;
 | 
      
         | 599 |  |  |             s->faulty_address = address;
 | 
      
         | 600 |  |  |             address = address & 0xfffffffe;
 | 
      
         | 601 | 31 | ja_rd |         }
 | 
      
         | 602 |  |  |         value = *(unsigned short*)ptr;
 | 
      
         | 603 |  |  |         if(s->big_endian){
 | 
      
         | 604 |  |  |             value = ntohs((unsigned short)value);
 | 
      
         | 605 |  |  |         }
 | 
      
         | 606 |  |  |         break;
 | 
      
         | 607 |  |  |     case 1:
 | 
      
         | 608 |  |  |         value = *(unsigned char*)ptr;
 | 
      
         | 609 |  |  |         break;
 | 
      
         | 610 |  |  |     default:
 | 
      
         | 611 | 163 | ja_rd |         /* This is a bug, display warning */
 | 
      
         | 612 |  |  |         printf("\n\n**** BUG: wrong memory read size at 0x%08x\n\n", s->pc);
 | 
      
         | 613 | 31 | ja_rd |     }
 | 
      
         | 614 | 2 | ja_rd |  
 | 
      
         | 615 | 53 | ja_rd |     //log_read(s, full_address, value, size, log);
 | 
      
         | 616 | 31 | ja_rd |     return(value);
 | 
      
         | 617 | 2 | ja_rd | }
 | 
      
         | 618 |  |  |  
 | 
      
         | 619 |  |  | /** Write memory */
 | 
      
         | 620 | 31 | ja_rd | void mem_write(t_state *s, int size, unsigned address, unsigned value, int log){
 | 
      
         | 621 |  |  |     unsigned int i, ptr, mask, dvalue, b0, b1, b2, b3;
 | 
      
         | 622 | 2 | ja_rd |  
 | 
      
         | 623 | 93 | ja_rd |     if(log_enabled(s)){
 | 
      
         | 624 | 31 | ja_rd |         b0 = value & 0x000000ff;
 | 
      
         | 625 |  |  |         b1 = value & 0x0000ff00;
 | 
      
         | 626 |  |  |         b2 = value & 0x00ff0000;
 | 
      
         | 627 |  |  |         b3 = value & 0xff000000;
 | 
      
         | 628 | 2 | ja_rd |  
 | 
      
         | 629 | 31 | ja_rd |         switch(size){
 | 
      
         | 630 |  |  |         case 4:  mask = 0x0f;
 | 
      
         | 631 |  |  |             dvalue = value;
 | 
      
         | 632 |  |  |             break;
 | 
      
         | 633 |  |  |         case 2:
 | 
      
         | 634 |  |  |             if((address&0x2)==0){
 | 
      
         | 635 |  |  |                 mask = 0xc;
 | 
      
         | 636 |  |  |                 dvalue = b1<<16 | b0<<16;
 | 
      
         | 637 |  |  |             }
 | 
      
         | 638 |  |  |             else{
 | 
      
         | 639 |  |  |                mask = 0x3;
 | 
      
         | 640 |  |  |                dvalue = b1 | b0;
 | 
      
         | 641 |  |  |             }
 | 
      
         | 642 |  |  |             break;
 | 
      
         | 643 |  |  |         case 1:
 | 
      
         | 644 |  |  |             switch(address%4){
 | 
      
         | 645 |  |  |             case 0 : mask = 0x8;
 | 
      
         | 646 |  |  |                 dvalue = b0<<24;
 | 
      
         | 647 |  |  |                 break;
 | 
      
         | 648 |  |  |             case 1 : mask = 0x4;
 | 
      
         | 649 |  |  |                 dvalue = b0<<16;
 | 
      
         | 650 |  |  |                 break;
 | 
      
         | 651 |  |  |             case 2 : mask = 0x2;
 | 
      
         | 652 |  |  |                 dvalue = b0<<8;
 | 
      
         | 653 |  |  |                 break;
 | 
      
         | 654 |  |  |             case 3 : mask = 0x1;
 | 
      
         | 655 |  |  |                 dvalue = b0;
 | 
      
         | 656 |  |  |                 break;
 | 
      
         | 657 |  |  |             }
 | 
      
         | 658 |  |  |             break;
 | 
      
         | 659 |  |  |         default:
 | 
      
         | 660 | 2 | ja_rd |             printf("BUG: mem write size invalid (%08x)\n", s->pc);
 | 
      
         | 661 |  |  |             exit(2);
 | 
      
         | 662 | 31 | ja_rd |         }
 | 
      
         | 663 | 2 | ja_rd |  
 | 
      
         | 664 | 31 | ja_rd |         fprintf(s->t.log, "(%08X) [%08X] |%02X|=%08X WR\n",
 | 
      
         | 665 | 147 | ja_rd |                 //s->op_addr, address&0xfffffffc, mask, dvalue);
 | 
      
         | 666 |  |  |                 s->op_addr, address, mask, dvalue);
 | 
      
         | 667 | 31 | ja_rd |     }
 | 
      
         | 668 | 166 | ja_rd |  
 | 
      
         | 669 |  |  |     /* Print anything that's written to a debug register, otherwise ignore it */
 | 
      
         | 670 |  |  |     if((address&0xffff0000)==(DBG_REGS&0xffff0000)){
 | 
      
         | 671 |  |  |         printf("DEBUG REG[%04x]=%08x\n", address & 0xffff, value);
 | 
      
         | 672 |  |  |         return;
 | 
      
         | 673 | 105 | ja_rd |     }
 | 
      
         | 674 | 2 | ja_rd |  
 | 
      
         | 675 | 31 | ja_rd |     switch(address){
 | 
      
         | 676 |  |  |     case UART_WRITE:
 | 
      
         | 677 |  |  |         putch(value);
 | 
      
         | 678 |  |  |         fflush(stdout);
 | 
      
         | 679 |  |  |         return;
 | 
      
         | 680 |  |  |     case IRQ_MASK:
 | 
      
         | 681 |  |  |         HWMemory[1] = value;
 | 
      
         | 682 |  |  |         return;
 | 
      
         | 683 |  |  |     case IRQ_STATUS:
 | 
      
         | 684 |  |  |         s->irqStatus = value;
 | 
      
         | 685 |  |  |         return;
 | 
      
         | 686 |  |  |     case CONFIG_REG:
 | 
      
         | 687 |  |  |         return;
 | 
      
         | 688 |  |  |     case MMU_PROCESS_ID:
 | 
      
         | 689 |  |  |         //printf("processId=%d\n", value);
 | 
      
         | 690 |  |  |         s->processId = value;
 | 
      
         | 691 |  |  |         return;
 | 
      
         | 692 |  |  |     }
 | 
      
         | 693 | 2 | ja_rd |  
 | 
      
         | 694 | 31 | ja_rd |     ptr = 0;
 | 
      
         | 695 |  |  |     for(i=0;i<NUM_MEM_BLOCKS;i++){
 | 
      
         | 696 | 61 | ja_rd |         if((address & s->blocks[i].mask) ==
 | 
      
         | 697 |  |  |                   (s->blocks[i].start & s->blocks[i].mask)){
 | 
      
         | 698 | 44 | ja_rd |             ptr = (unsigned)(s->blocks[i].mem) +
 | 
      
         | 699 |  |  |                             ((address - s->blocks[i].start) % s->blocks[i].size);
 | 
      
         | 700 | 61 | ja_rd |  
 | 
      
         | 701 |  |  |             if(s->blocks[i].read_only){
 | 
      
         | 702 | 93 | ja_rd |                 if(log_enabled(s) && log!=0){
 | 
      
         | 703 | 61 | ja_rd |                     fprintf(s->t.log, "(%08X) [%08X] |%02X|=%08X WR READ ONLY\n",
 | 
      
         | 704 |  |  |                     s->op_addr, address, mask, dvalue);
 | 
      
         | 705 |  |  |                     return;
 | 
      
         | 706 |  |  |                 }
 | 
      
         | 707 |  |  |             }
 | 
      
         | 708 | 31 | ja_rd |             break;
 | 
      
         | 709 |  |  |         }
 | 
      
         | 710 |  |  |     }
 | 
      
         | 711 |  |  |     if(!ptr){
 | 
      
         | 712 | 166 | ja_rd |         /* address out of mapped blocks: log and return zero */
 | 
      
         | 713 |  |  |         printf("MEM WR ERROR @ 0x%08x [0x%08x]\n", s->pc, address);
 | 
      
         | 714 | 93 | ja_rd |         if(log_enabled(s) && log!=0){
 | 
      
         | 715 | 31 | ja_rd |             fprintf(s->t.log, "(%08X) [%08X] |%02X|=%08X WR UNMAPPED\n",
 | 
      
         | 716 | 53 | ja_rd |                 s->op_addr, address, mask, dvalue);
 | 
      
         | 717 | 31 | ja_rd |         }
 | 
      
         | 718 |  |  |         return;
 | 
      
         | 719 |  |  |     }
 | 
      
         | 720 | 2 | ja_rd |  
 | 
      
         | 721 | 31 | ja_rd |     switch(size){
 | 
      
         | 722 |  |  |     case 4:
 | 
      
         | 723 |  |  |         if((address & 3) != 0){
 | 
      
         | 724 |  |  |             /* unaligned word, log fault */
 | 
      
         | 725 | 5 | ja_rd |             s->failed_assertions |= ASRT_UNALIGNED_WRITE;
 | 
      
         | 726 |  |  |             s->faulty_address = address;
 | 
      
         | 727 |  |  |             address = address & (~0x03);
 | 
      
         | 728 | 31 | ja_rd |         }
 | 
      
         | 729 |  |  |         if(s->big_endian){
 | 
      
         | 730 |  |  |             value = htonl(value);
 | 
      
         | 731 |  |  |         }
 | 
      
         | 732 |  |  |         *(int*)ptr = value;
 | 
      
         | 733 |  |  |         break;
 | 
      
         | 734 |  |  |     case 2:
 | 
      
         | 735 |  |  |         if((address & 1) != 0){
 | 
      
         | 736 |  |  |             /* unaligned halfword, log fault */
 | 
      
         | 737 | 5 | ja_rd |             s->failed_assertions |= ASRT_UNALIGNED_WRITE;
 | 
      
         | 738 |  |  |             s->faulty_address = address;
 | 
      
         | 739 |  |  |             address = address & (~0x01);
 | 
      
         | 740 | 31 | ja_rd |         }
 | 
      
         | 741 |  |  |         if(s->big_endian){
 | 
      
         | 742 |  |  |             value = htons((unsigned short)value);
 | 
      
         | 743 |  |  |         }
 | 
      
         | 744 |  |  |         *(short*)ptr = (unsigned short)value;
 | 
      
         | 745 |  |  |         break;
 | 
      
         | 746 |  |  |     case 1:
 | 
      
         | 747 |  |  |         *(char*)ptr = (unsigned char)value;
 | 
      
         | 748 |  |  |         break;
 | 
      
         | 749 |  |  |     default:
 | 
      
         | 750 | 163 | ja_rd |         /* This is a bug, display warning */
 | 
      
         | 751 |  |  |         printf("\n\n**** BUG: wrong memory write size at 0x%08x\n\n", s->pc);
 | 
      
         | 752 | 31 | ja_rd |     }
 | 
      
         | 753 | 2 | ja_rd | }
 | 
      
         | 754 |  |  |  
 | 
      
         | 755 | 105 | ja_rd | /*-- unaligned store and load instructions -----------------------------------*/
 | 
      
         | 756 |  |  | /*
 | 
      
         | 757 |  |  |  These are meant to be left unimplemented and trapped. These functions simulate
 | 
      
         | 758 |  |  |  the unaligned r/w instructions until proper trap handlers are written.
 | 
      
         | 759 |  |  | */
 | 
      
         | 760 |  |  |  
 | 
      
         | 761 |  |  | void mem_swl(t_state *s, uint32_t address, uint32_t value, uint32_t log){
 | 
      
         | 762 |  |  |     uint32_t data, offset;
 | 
      
         | 763 |  |  |  
 | 
      
         | 764 |  |  |     if(!s->do_unaligned) return unimplemented(s, "SWL");
 | 
      
         | 765 |  |  |  
 | 
      
         | 766 |  |  |     offset = (address & 0x03);
 | 
      
         | 767 |  |  |     address = (address & (~0x03));
 | 
      
         | 768 |  |  |     data = value;
 | 
      
         | 769 |  |  |  
 | 
      
         | 770 |  |  |     while(offset<4){
 | 
      
         | 771 |  |  |         mem_write(s,1,address+offset,(data>>24) & 0xff,0);
 | 
      
         | 772 |  |  |         data = data << 8;
 | 
      
         | 773 |  |  |         offset++;
 | 
      
         | 774 |  |  |     }
 | 
      
         | 775 |  |  | }
 | 
      
         | 776 |  |  |  
 | 
      
         | 777 |  |  | void mem_swr(t_state *s, uint32_t address, uint32_t value, uint32_t log){
 | 
      
         | 778 |  |  |     uint32_t data, offset;
 | 
      
         | 779 |  |  |  
 | 
      
         | 780 |  |  |     if(!s->do_unaligned) return unimplemented(s, "SWR");
 | 
      
         | 781 |  |  |  
 | 
      
         | 782 |  |  |     offset = (address & 0x03);
 | 
      
         | 783 |  |  |     address = (address & (~0x03));
 | 
      
         | 784 |  |  |     data = value;
 | 
      
         | 785 |  |  |  
 | 
      
         | 786 |  |  |     while(offset>=0){
 | 
      
         | 787 |  |  |         mem_write(s,1,address+offset,data & 0xff,0);
 | 
      
         | 788 |  |  |         data = data >> 8;
 | 
      
         | 789 |  |  |         offset--;
 | 
      
         | 790 |  |  |     }
 | 
      
         | 791 |  |  | }
 | 
      
         | 792 |  |  |  
 | 
      
         | 793 |  |  | void mem_lwr(t_state *s, uint32_t address, uint32_t reg_index, uint32_t log){
 | 
      
         | 794 |  |  |     uint32_t offset, data;
 | 
      
         | 795 |  |  |     uint32_t disp[4] = {24,         16,         8,          0};
 | 
      
         | 796 |  |  |     uint32_t mask[4] = {0x000000ff, 0x0000ffff, 0x00ffffff, 0xffffffff};
 | 
      
         | 797 |  |  |  
 | 
      
         | 798 |  |  |     if(!s->do_unaligned) return unimplemented(s, "LWR");
 | 
      
         | 799 |  |  |  
 | 
      
         | 800 |  |  |     offset = (address & 0x03);
 | 
      
         | 801 |  |  |     address = (address & (~0x03));
 | 
      
         | 802 |  |  |  
 | 
      
         | 803 |  |  |     data = mem_read(s, 4, address, 0);
 | 
      
         | 804 |  |  |     data = (data >> disp[offset]) & mask[offset];
 | 
      
         | 805 |  |  |  
 | 
      
         | 806 |  |  |     s->r[reg_index] = (s->r[reg_index] & (~mask[offset])) | data;
 | 
      
         | 807 |  |  | }
 | 
      
         | 808 |  |  |  
 | 
      
         | 809 |  |  | void mem_lwl(t_state *s, uint32_t address, uint32_t reg_index, uint32_t log){
 | 
      
         | 810 |  |  |     uint32_t offset, data;
 | 
      
         | 811 |  |  |     uint32_t disp[4] = {0,          8,          16,         24};
 | 
      
         | 812 |  |  |     uint32_t mask[4] = {0xffffffff, 0xffffff00, 0xffff0000, 0xff000000};
 | 
      
         | 813 |  |  |  
 | 
      
         | 814 |  |  |     if(!s->do_unaligned) return unimplemented(s, "LWL");
 | 
      
         | 815 |  |  |  
 | 
      
         | 816 |  |  |     offset = (address & 0x03);
 | 
      
         | 817 |  |  |     address = (address & (~0x03));
 | 
      
         | 818 |  |  |  
 | 
      
         | 819 |  |  |     data = mem_read(s, 4, address, 0);
 | 
      
         | 820 |  |  |     data = (data << disp[offset]) & mask[offset];
 | 
      
         | 821 |  |  |  
 | 
      
         | 822 |  |  |     s->r[reg_index] = (s->r[reg_index] & (~mask[offset])) | data;
 | 
      
         | 823 |  |  | }
 | 
      
         | 824 | 166 | ja_rd |  
 | 
      
         | 825 |  |  | /*---- Optional MIPS32 opcodes -----------------------------------------------*/
 | 
      
         | 826 |  |  |  
 | 
      
         | 827 |  |  | uint32_t count_leading(uint32_t lead, uint32_t src){
 | 
      
         | 828 |  |  |     uint32_t mask, bit_val, i;
 | 
      
         | 829 |  |  |  
 | 
      
         | 830 |  |  |     mask = 0x80000000;
 | 
      
         | 831 |  |  |     bit_val = lead? mask : 0x0;
 | 
      
         | 832 |  |  |  
 | 
      
         | 833 |  |  |     for(i=0;i<32;i++){
 | 
      
         | 834 |  |  |         if((src & mask) != bit_val){
 | 
      
         | 835 |  |  |             return i;
 | 
      
         | 836 |  |  |         }
 | 
      
         | 837 |  |  |         mask = mask >> 1;
 | 
      
         | 838 |  |  |     }
 | 
      
         | 839 |  |  |  
 | 
      
         | 840 |  |  |     return i;
 | 
      
         | 841 |  |  | }
 | 
      
         | 842 |  |  |  
 | 
      
         | 843 |  |  | uint32_t mult_gpr(uint32_t m1, uint32_t m2){
 | 
      
         | 844 |  |  |     uint32_t temp;
 | 
      
         | 845 |  |  |  
 | 
      
         | 846 |  |  |     temp = m1 * m2;
 | 
      
         | 847 |  |  |     return temp;
 | 
      
         | 848 |  |  | }
 | 
      
         | 849 |  |  |  
 | 
      
         | 850 |  |  | uint32_t ext_bitfield(uint32_t src, uint32_t opcode){
 | 
      
         | 851 |  |  |     uint32_t pos, size, mask, value;
 | 
      
         | 852 |  |  |  
 | 
      
         | 853 |  |  |     pos = (opcode>>6) & 0x1f;
 | 
      
         | 854 |  |  |     size = ((opcode>>11) & 0x1f) + 1;
 | 
      
         | 855 |  |  |     mask = (1 << size)-1;
 | 
      
         | 856 |  |  |     mask = mask << pos;
 | 
      
         | 857 |  |  |  
 | 
      
         | 858 |  |  |     value = (src & mask) >> pos;
 | 
      
         | 859 |  |  |     return value;
 | 
      
         | 860 |  |  | }
 | 
      
         | 861 | 105 | ja_rd |  
 | 
      
         | 862 | 166 | ja_rd | uint32_t ins_bitfield(uint32_t target, uint32_t src, uint32_t opcode){
 | 
      
         | 863 |  |  |     uint32_t pos, size, mask, value;
 | 
      
         | 864 | 105 | ja_rd |  
 | 
      
         | 865 | 166 | ja_rd |     pos = (opcode>>6) & 0x1f;
 | 
      
         | 866 |  |  |     size = ((opcode>>11) & 0x1f) + 1;
 | 
      
         | 867 |  |  |     mask = (1 << size)-1;
 | 
      
         | 868 |  |  |     mask = mask << pos;
 | 
      
         | 869 |  |  |  
 | 
      
         | 870 |  |  |     value = target & (~mask);
 | 
      
         | 871 |  |  |     value |= ((src << pos) & mask);
 | 
      
         | 872 |  |  |     return value;
 | 
      
         | 873 |  |  | }
 | 
      
         | 874 |  |  |  
 | 
      
         | 875 | 2 | ja_rd | /*---- Optional MMU and cache implementation ---------------------------------*/
 | 
      
         | 876 |  |  |  
 | 
      
         | 877 |  |  | /*
 | 
      
         | 878 |  |  |    The actual core does not have a cache so all of the original Plasma mlite.c
 | 
      
         | 879 |  |  |    code for cache simulation has been removed.
 | 
      
         | 880 |  |  | */
 | 
      
         | 881 |  |  |  
 | 
      
         | 882 |  |  | /*---- End optional cache implementation -------------------------------------*/
 | 
      
         | 883 |  |  |  
 | 
      
         | 884 |  |  |  
 | 
      
         | 885 |  |  | /** Simulates MIPS-I multiplier unsigned behavior*/
 | 
      
         | 886 |  |  | void mult_big(unsigned int a,
 | 
      
         | 887 |  |  |               unsigned int b,
 | 
      
         | 888 |  |  |               unsigned int *hi,
 | 
      
         | 889 | 31 | ja_rd |               unsigned int *lo){
 | 
      
         | 890 |  |  |     unsigned int ahi, alo, bhi, blo;
 | 
      
         | 891 |  |  |     unsigned int c0, c1, c2;
 | 
      
         | 892 |  |  |     unsigned int c1_a, c1_b;
 | 
      
         | 893 | 2 | ja_rd |  
 | 
      
         | 894 | 31 | ja_rd |     ahi = a >> 16;
 | 
      
         | 895 |  |  |     alo = a & 0xffff;
 | 
      
         | 896 |  |  |     bhi = b >> 16;
 | 
      
         | 897 |  |  |     blo = b & 0xffff;
 | 
      
         | 898 | 2 | ja_rd |  
 | 
      
         | 899 | 31 | ja_rd |     c0 = alo * blo;
 | 
      
         | 900 |  |  |     c1_a = ahi * blo;
 | 
      
         | 901 |  |  |     c1_b = alo * bhi;
 | 
      
         | 902 |  |  |     c2 = ahi * bhi;
 | 
      
         | 903 | 2 | ja_rd |  
 | 
      
         | 904 | 31 | ja_rd |     c2 += (c1_a >> 16) + (c1_b >> 16);
 | 
      
         | 905 |  |  |     c1 = (c1_a & 0xffff) + (c1_b & 0xffff) + (c0 >> 16);
 | 
      
         | 906 |  |  |     c2 += (c1 >> 16);
 | 
      
         | 907 |  |  |     c0 = (c1 << 16) + (c0 & 0xffff);
 | 
      
         | 908 |  |  |     *hi = c2;
 | 
      
         | 909 |  |  |     *lo = c0;
 | 
      
         | 910 | 2 | ja_rd | }
 | 
      
         | 911 |  |  |  
 | 
      
         | 912 |  |  | /** Simulates MIPS-I multiplier signed behavior*/
 | 
      
         | 913 |  |  | void mult_big_signed(int a,
 | 
      
         | 914 |  |  |                      int b,
 | 
      
         | 915 |  |  |                      unsigned int *hi,
 | 
      
         | 916 | 31 | ja_rd |                      unsigned int *lo){
 | 
      
         | 917 |  |  |     int64_t xa, xb, xr, temp;
 | 
      
         | 918 |  |  |     int32_t rh, rl;
 | 
      
         | 919 | 11 | ja_rd |  
 | 
      
         | 920 | 31 | ja_rd |     xa = a;
 | 
      
         | 921 |  |  |     xb = b;
 | 
      
         | 922 |  |  |     xr = xa * xb;
 | 
      
         | 923 | 11 | ja_rd |  
 | 
      
         | 924 | 31 | ja_rd |     temp = (xr >> 32) & 0xffffffff;
 | 
      
         | 925 |  |  |     rh = temp;
 | 
      
         | 926 |  |  |     temp = (xr >> 0) & 0xffffffff;
 | 
      
         | 927 |  |  |     rl = temp;
 | 
      
         | 928 | 11 | ja_rd |  
 | 
      
         | 929 | 31 | ja_rd |     *hi = rh;
 | 
      
         | 930 |  |  |     *lo = rl;
 | 
      
         | 931 | 2 | ja_rd | }
 | 
      
         | 932 |  |  |  
 | 
      
         | 933 |  |  | /** Load data from memory (used to simulate load delay slots) */
 | 
      
         | 934 | 53 | ja_rd | void start_load(t_state *s, uint32_t addr, int rt, int data){
 | 
      
         | 935 | 31 | ja_rd |     /* load delay slot not simulated */
 | 
      
         | 936 | 53 | ja_rd |     log_read(s, addr, data, 1, 1);
 | 
      
         | 937 | 31 | ja_rd |     s->r[rt] = data;
 | 
      
         | 938 | 2 | ja_rd | }
 | 
      
         | 939 |  |  |  
 | 
      
         | 940 |  |  | /** Execute one cycle of the CPU (including any interlock stall cycles) */
 | 
      
         | 941 | 31 | ja_rd | void cycle(t_state *s, int show_mode){
 | 
      
         | 942 |  |  |     unsigned int opcode;
 | 
      
         | 943 |  |  |     int delay_slot = 0; /* 1 of this instruction is a branch */
 | 
      
         | 944 | 166 | ja_rd |     unsigned int op, rs, rt, rd, re, func, imm, target;
 | 
      
         | 945 |  |  |     int imm_shift, branch=0, lbranch=2, skip2=0;
 | 
      
         | 946 |  |  |     int link=0; /* !=0 if this is a 'branch-and-link' opcode */
 | 
      
         | 947 | 31 | ja_rd |     int *r=s->r;
 | 
      
         | 948 |  |  |     unsigned int *u=(unsigned int*)s->r;
 | 
      
         | 949 | 163 | ja_rd |     unsigned int ptr, epc, rSave;
 | 
      
         | 950 |  |  |     char format;
 | 
      
         | 951 |  |  |     uint32_t aux;
 | 
      
         | 952 |  |  |     uint32_t target_offset16;
 | 
      
         | 953 |  |  |     uint32_t target_long;
 | 
      
         | 954 | 2 | ja_rd |  
 | 
      
         | 955 | 166 | ja_rd |     s->trap_cause = -1;
 | 
      
         | 956 |  |  |  
 | 
      
         | 957 | 93 | ja_rd |     /* fetch and decode instruction */
 | 
      
         | 958 | 166 | ja_rd |     opcode = mem_read(s, 4, s->pc, 0);
 | 
      
         | 959 |  |  |  
 | 
      
         | 960 | 31 | ja_rd |     op = (opcode >> 26) & 0x3f;
 | 
      
         | 961 |  |  |     rs = (opcode >> 21) & 0x1f;
 | 
      
         | 962 |  |  |     rt = (opcode >> 16) & 0x1f;
 | 
      
         | 963 |  |  |     rd = (opcode >> 11) & 0x1f;
 | 
      
         | 964 |  |  |     re = (opcode >> 6) & 0x1f;
 | 
      
         | 965 |  |  |     func = opcode & 0x3f;
 | 
      
         | 966 |  |  |     imm = opcode & 0xffff;
 | 
      
         | 967 |  |  |     imm_shift = (((int)(short)imm) << 2) - 4;
 | 
      
         | 968 |  |  |     target = (opcode << 6) >> 4;
 | 
      
         | 969 |  |  |     ptr = (short)imm + r[rs];
 | 
      
         | 970 |  |  |     r[0] = 0;
 | 
      
         | 971 | 163 | ja_rd |     target_offset16 = opcode & 0xffff;
 | 
      
         | 972 |  |  |     if(target_offset16 & 0x8000){
 | 
      
         | 973 |  |  |         target_offset16 |= 0xffff0000;
 | 
      
         | 974 |  |  |     }
 | 
      
         | 975 |  |  |     target_long = (opcode & 0x03ffffff)<<2;
 | 
      
         | 976 |  |  |     target_long |= (s->pc & 0xf0000000);
 | 
      
         | 977 | 31 | ja_rd |  
 | 
      
         | 978 | 93 | ja_rd |     /* Trigger log if we fetch from trigger address */
 | 
      
         | 979 |  |  |     if(s->pc == s->t.log_trigger_address){
 | 
      
         | 980 |  |  |         trigger_log(s);
 | 
      
         | 981 |  |  |     }
 | 
      
         | 982 |  |  |  
 | 
      
         | 983 | 31 | ja_rd |     /* if we are priting state to console, do it now */
 | 
      
         | 984 |  |  |     if(show_mode){
 | 
      
         | 985 |  |  |         printf("%8.8x %8.8x ", s->pc, opcode);
 | 
      
         | 986 |  |  |         if(op == 0){
 | 
      
         | 987 | 163 | ja_rd |             printf("  %-6s ", &(special_string[func][1]));
 | 
      
         | 988 |  |  |             format = special_string[func][0];
 | 
      
         | 989 | 31 | ja_rd |         }
 | 
      
         | 990 | 163 | ja_rd |         else if(op == 1){
 | 
      
         | 991 |  |  |             printf("  %-6s ", &(regimm_string[rt][1]));
 | 
      
         | 992 |  |  |             format = regimm_string[rt][0];
 | 
      
         | 993 | 31 | ja_rd |         }
 | 
      
         | 994 | 163 | ja_rd |         else{
 | 
      
         | 995 |  |  |             format = opcode_string[op][0];
 | 
      
         | 996 |  |  |             if(format!='c'){
 | 
      
         | 997 |  |  |                 printf("  %-6s ", &(opcode_string[op][1]));
 | 
      
         | 998 |  |  |             }
 | 
      
         | 999 |  |  |             else{
 | 
      
         | 1000 |  |  |                 aux = op&0x03;
 | 
      
         | 1001 |  |  |                 switch(rs){
 | 
      
         | 1002 |  |  |                     case 16:
 | 
      
         | 1003 | 166 | ja_rd |                         /* FIXME partial decoding of some COP0 opcodes */
 | 
      
         | 1004 | 163 | ja_rd |                         printf("  RFE      "); format = ' '; break;
 | 
      
         | 1005 |  |  |                     case 4:
 | 
      
         | 1006 |  |  |                         printf("  MTC%1d   ", aux); break;
 | 
      
         | 1007 |  |  |                     case 0:
 | 
      
         | 1008 |  |  |                         printf("  MFC%1d   ", aux); break;
 | 
      
         | 1009 |  |  |                     default:
 | 
      
         | 1010 |  |  |                         printf("  ???      "); break;
 | 
      
         | 1011 |  |  |                         format = '?';
 | 
      
         | 1012 |  |  |                 }
 | 
      
         | 1013 |  |  |             }
 | 
      
         | 1014 | 31 | ja_rd |         }
 | 
      
         | 1015 | 163 | ja_rd |  
 | 
      
         | 1016 |  |  |         switch(format){
 | 
      
         | 1017 |  |  |             case '1':
 | 
      
         | 1018 |  |  |                 printf("0x%08x", target_long);
 | 
      
         | 1019 |  |  |                 break;
 | 
      
         | 1020 |  |  |             case '2':
 | 
      
         | 1021 |  |  |                 printf("%s,%s,0x%08x",
 | 
      
         | 1022 |  |  |                        reg_names[rt], reg_names[rs],
 | 
      
         | 1023 |  |  |                        (target_offset16*4)+s->pc+4);
 | 
      
         | 1024 |  |  |                 break;
 | 
      
         | 1025 |  |  |             case '3':
 | 
      
         | 1026 |  |  |                 printf("%s,0x%08x", reg_names[rt], (target_offset16*4)+s->pc+4);
 | 
      
         | 1027 |  |  |                 break;
 | 
      
         | 1028 |  |  |             case '4':
 | 
      
         | 1029 |  |  |                 printf("%s,%s,%d", reg_names[rd], reg_names[rt], re);
 | 
      
         | 1030 |  |  |                 break;
 | 
      
         | 1031 |  |  |             case '5':
 | 
      
         | 1032 |  |  |                 printf("%s,%s,0x%04x",
 | 
      
         | 1033 |  |  |                        reg_names[rt], reg_names[rs],
 | 
      
         | 1034 |  |  |                        target_offset16&0xffff);
 | 
      
         | 1035 |  |  |                 break;
 | 
      
         | 1036 |  |  |             case '6':
 | 
      
         | 1037 |  |  |                 printf("%s,0x%04x",
 | 
      
         | 1038 |  |  |                        reg_names[rt],
 | 
      
         | 1039 |  |  |                        target_offset16&0xffff);
 | 
      
         | 1040 |  |  |                 break;
 | 
      
         | 1041 |  |  |             case '7':
 | 
      
         | 1042 |  |  |                 printf("%s,%s,%s", reg_names[rd], reg_names[rs], reg_names[rt]);
 | 
      
         | 1043 |  |  |                 break;
 | 
      
         | 1044 |  |  |             case '8':
 | 
      
         | 1045 |  |  |                 printf("%s,%d(%s)", reg_names[rt],
 | 
      
         | 1046 |  |  |                        (target_offset16), reg_names[rs]);
 | 
      
         | 1047 |  |  |                 break;
 | 
      
         | 1048 |  |  |             case '9':
 | 
      
         | 1049 |  |  |                 printf("%s,0x%08x", reg_names[rt], (target_offset16*4)+s->pc+4);
 | 
      
         | 1050 |  |  |                 break;
 | 
      
         | 1051 |  |  |             case 'a':
 | 
      
         | 1052 |  |  |                 printf("%s", reg_names[rs]);
 | 
      
         | 1053 |  |  |                 break;
 | 
      
         | 1054 |  |  |             case 'b':
 | 
      
         | 1055 |  |  |                 printf("%s,%s,%s", reg_names[rd], reg_names[rt], reg_names[rs]);
 | 
      
         | 1056 |  |  |                 break;
 | 
      
         | 1057 |  |  |             case 'c':
 | 
      
         | 1058 |  |  |                 printf("%s,$%d", reg_names[rt], rd);
 | 
      
         | 1059 |  |  |                 break;
 | 
      
         | 1060 |  |  |             case '0':
 | 
      
         | 1061 |  |  |                 printf("$%2.2d $%2.2d $%2.2d $%2.2d ", rs, rt, rd, re);
 | 
      
         | 1062 |  |  |                 printf("%4.4x", imm);
 | 
      
         | 1063 |  |  |                 break;
 | 
      
         | 1064 |  |  |             default:;
 | 
      
         | 1065 |  |  |         }
 | 
      
         | 1066 |  |  |  
 | 
      
         | 1067 | 2 | ja_rd |  
 | 
      
         | 1068 | 31 | ja_rd |         if(show_mode == 1){
 | 
      
         | 1069 |  |  |             printf(" r[%2.2d]=%8.8x r[%2.2d]=%8.8x", rs, r[rs], rt, r[rt]);
 | 
      
         | 1070 |  |  |         }
 | 
      
         | 1071 |  |  |         printf("\n");
 | 
      
         | 1072 |  |  |     }
 | 
      
         | 1073 |  |  |  
 | 
      
         | 1074 |  |  |     /* if we're just showing state to console, quit and don't run instruction */
 | 
      
         | 1075 |  |  |     if(show_mode > 5){
 | 
      
         | 1076 |  |  |         return;
 | 
      
         | 1077 |  |  |     }
 | 
      
         | 1078 |  |  |  
 | 
      
         | 1079 |  |  |     /* epc will point to the victim instruction, i.e. THIS instruction */
 | 
      
         | 1080 |  |  |     epc = s->pc;
 | 
      
         | 1081 | 32 | ja_rd |  
 | 
      
         | 1082 |  |  |     /* If we catch a jump instruction jumping to itself, assume we hit the
 | 
      
         | 1083 |  |  |        and of the program and quit. */
 | 
      
         | 1084 |  |  |     if(s->pc == s->pc_next+4){
 | 
      
         | 1085 |  |  |         printf("\n\nEndless loop at 0x%08x\n\n", s->pc-4);
 | 
      
         | 1086 |  |  |         s->wakeup = 1;
 | 
      
         | 1087 | 53 | ja_rd |     }
 | 
      
         | 1088 |  |  |     s->op_addr = s->pc;
 | 
      
         | 1089 | 31 | ja_rd |     s->pc = s->pc_next;
 | 
      
         | 1090 |  |  |     s->pc_next = s->pc_next + 4;
 | 
      
         | 1091 |  |  |     if(s->skip){
 | 
      
         | 1092 |  |  |         s->skip = 0;
 | 
      
         | 1093 |  |  |         return;
 | 
      
         | 1094 |  |  |     }
 | 
      
         | 1095 |  |  |     rSave = r[rt];
 | 
      
         | 1096 |  |  |  
 | 
      
         | 1097 |  |  |     switch(op){
 | 
      
         | 1098 |  |  |     case 0x00:/*SPECIAL*/
 | 
      
         | 1099 |  |  |         switch(func){
 | 
      
         | 1100 |  |  |         case 0x00:/*SLL*/  r[rd]=r[rt]<<re;          break;
 | 
      
         | 1101 |  |  |         case 0x02:/*SRL*/  r[rd]=u[rt]>>re;          break;
 | 
      
         | 1102 |  |  |         case 0x03:/*SRA*/  r[rd]=r[rt]>>re;          break;
 | 
      
         | 1103 |  |  |         case 0x04:/*SLLV*/ r[rd]=r[rt]<<r[rs];       break;
 | 
      
         | 1104 |  |  |         case 0x06:/*SRLV*/ r[rd]=u[rt]>>r[rs];       break;
 | 
      
         | 1105 |  |  |         case 0x07:/*SRAV*/ r[rd]=r[rt]>>r[rs];       break;
 | 
      
         | 1106 | 166 | ja_rd |         case 0x08:/*JR*/   if(rs==31) log_ret(r[rs],epc);
 | 
      
         | 1107 |  |  |                            delay_slot=1;
 | 
      
         | 1108 | 31 | ja_rd |                            s->pc_next=r[rs];         break;
 | 
      
         | 1109 |  |  |         case 0x09:/*JALR*/ delay_slot=1;
 | 
      
         | 1110 |  |  |                            r[rd]=s->pc_next;
 | 
      
         | 1111 | 166 | ja_rd |                            s->pc_next=r[rs];
 | 
      
         | 1112 |  |  |                            log_call(s->pc_next, epc); break;
 | 
      
         | 1113 | 31 | ja_rd |         case 0x0a:/*MOVZ*/ if(!r[rt]) r[rd]=r[rs];   break;  /*IV*/
 | 
      
         | 1114 |  |  |         case 0x0b:/*MOVN*/ if(r[rt]) r[rd]=r[rs];    break;  /*IV*/
 | 
      
         | 1115 | 166 | ja_rd |         case 0x0c:/*SYSCALL*/ s->trap_cause = 8;
 | 
      
         | 1116 | 105 | ja_rd |                               /*
 | 
      
         | 1117 |  |  |                               FIXME enable when running uClinux
 | 
      
         | 1118 |  |  |                               printf("SYSCALL (%08x)\n", s->pc);
 | 
      
         | 1119 |  |  |                               */
 | 
      
         | 1120 |  |  |                               break;
 | 
      
         | 1121 | 166 | ja_rd |         case 0x0d:/*BREAK*/   s->trap_cause = 9;
 | 
      
         | 1122 | 105 | ja_rd |                               /*
 | 
      
         | 1123 |  |  |                               FIXME enable when running uClinux
 | 
      
         | 1124 |  |  |                               printf("BREAK (%08x)\n", s->pc);
 | 
      
         | 1125 |  |  |                               */
 | 
      
         | 1126 |  |  |                               break;
 | 
      
         | 1127 | 31 | ja_rd |         case 0x0f:/*SYNC*/ s->wakeup=1;              break;
 | 
      
         | 1128 |  |  |         case 0x10:/*MFHI*/ r[rd]=s->hi;              break;
 | 
      
         | 1129 |  |  |         case 0x11:/*FTHI*/ s->hi=r[rs];              break;
 | 
      
         | 1130 |  |  |         case 0x12:/*MFLO*/ r[rd]=s->lo;              break;
 | 
      
         | 1131 |  |  |         case 0x13:/*MTLO*/ s->lo=r[rs];              break;
 | 
      
         | 1132 |  |  |         case 0x18:/*MULT*/ mult_big_signed(r[rs],r[rt],&s->hi,&s->lo); break;
 | 
      
         | 1133 |  |  |         case 0x19:/*MULTU*/ mult_big(r[rs],r[rt],&s->hi,&s->lo); break;
 | 
      
         | 1134 |  |  |         case 0x1a:/*DIV*/  s->lo=r[rs]/r[rt]; s->hi=r[rs]%r[rt]; break;
 | 
      
         | 1135 |  |  |         case 0x1b:/*DIVU*/ s->lo=u[rs]/u[rt]; s->hi=u[rs]%u[rt]; break;
 | 
      
         | 1136 |  |  |         case 0x20:/*ADD*/  r[rd]=r[rs]+r[rt];        break;
 | 
      
         | 1137 |  |  |         case 0x21:/*ADDU*/ r[rd]=r[rs]+r[rt];        break;
 | 
      
         | 1138 |  |  |         case 0x22:/*SUB*/  r[rd]=r[rs]-r[rt];        break;
 | 
      
         | 1139 |  |  |         case 0x23:/*SUBU*/ r[rd]=r[rs]-r[rt];        break;
 | 
      
         | 1140 |  |  |         case 0x24:/*AND*/  r[rd]=r[rs]&r[rt];        break;
 | 
      
         | 1141 |  |  |         case 0x25:/*OR*/   r[rd]=r[rs]|r[rt];        break;
 | 
      
         | 1142 |  |  |         case 0x26:/*XOR*/  r[rd]=r[rs]^r[rt];        break;
 | 
      
         | 1143 |  |  |         case 0x27:/*NOR*/  r[rd]=~(r[rs]|r[rt]);     break;
 | 
      
         | 1144 |  |  |         case 0x2a:/*SLT*/  r[rd]=r[rs]<r[rt];        break;
 | 
      
         | 1145 |  |  |         case 0x2b:/*SLTU*/ r[rd]=u[rs]<u[rt];        break;
 | 
      
         | 1146 |  |  |         case 0x2d:/*DADDU*/r[rd]=r[rs]+u[rt];        break;
 | 
      
         | 1147 |  |  |         case 0x31:/*TGEU*/ break;
 | 
      
         | 1148 |  |  |         case 0x32:/*TLT*/  break;
 | 
      
         | 1149 |  |  |         case 0x33:/*TLTU*/ break;
 | 
      
         | 1150 |  |  |         case 0x34:/*TEQ*/  break;
 | 
      
         | 1151 |  |  |         case 0x36:/*TNE*/  break;
 | 
      
         | 1152 | 166 | ja_rd |         default:
 | 
      
         | 1153 |  |  |             reserved_opcode(epc, opcode, s);
 | 
      
         | 1154 | 31 | ja_rd |         }
 | 
      
         | 1155 |  |  |         break;
 | 
      
         | 1156 |  |  |     case 0x01:/*REGIMM*/
 | 
      
         | 1157 |  |  |         switch(rt){
 | 
      
         | 1158 | 166 | ja_rd |             case 0x10:/*BLTZAL*/ r[31]=s->pc_next; link=1;
 | 
      
         | 1159 | 2 | ja_rd |             case 0x00:/*BLTZ*/   branch=r[rs]<0;    break;
 | 
      
         | 1160 | 166 | ja_rd |             case 0x11:/*BGEZAL*/ r[31]=s->pc_next; link=1;
 | 
      
         | 1161 | 2 | ja_rd |             case 0x01:/*BGEZ*/   branch=r[rs]>=0;   break;
 | 
      
         | 1162 | 166 | ja_rd |             case 0x12:/*BLTZALL*/r[31]=s->pc_next; link=1;
 | 
      
         | 1163 | 2 | ja_rd |             case 0x02:/*BLTZL*/  lbranch=r[rs]<0;   break;
 | 
      
         | 1164 | 166 | ja_rd |             case 0x13:/*BGEZALL*/r[31]=s->pc_next; link=1;
 | 
      
         | 1165 | 2 | ja_rd |             case 0x03:/*BGEZL*/  lbranch=r[rs]>=0;  break;
 | 
      
         | 1166 |  |  |             default: printf("ERROR1\n"); s->wakeup=1;
 | 
      
         | 1167 | 31 | ja_rd |         }
 | 
      
         | 1168 |  |  |         break;
 | 
      
         | 1169 | 166 | ja_rd |     case 0x03:/*JAL*/    r[31]=s->pc_next; log_call(((s->pc&0xf0000000)|target), epc);
 | 
      
         | 1170 | 31 | ja_rd |     case 0x02:/*J*/      delay_slot=1;
 | 
      
         | 1171 |  |  |                        s->pc_next=(s->pc&0xf0000000)|target; break;
 | 
      
         | 1172 |  |  |     case 0x04:/*BEQ*/    branch=r[rs]==r[rt];     break;
 | 
      
         | 1173 |  |  |     case 0x05:/*BNE*/    branch=r[rs]!=r[rt];     break;
 | 
      
         | 1174 |  |  |     case 0x06:/*BLEZ*/   branch=r[rs]<=0;         break;
 | 
      
         | 1175 |  |  |     case 0x07:/*BGTZ*/   branch=r[rs]>0;          break;
 | 
      
         | 1176 |  |  |     case 0x08:/*ADDI*/   r[rt]=r[rs]+(short)imm;  break;
 | 
      
         | 1177 |  |  |     case 0x09:/*ADDIU*/  u[rt]=u[rs]+(short)imm;  break;
 | 
      
         | 1178 |  |  |     case 0x0a:/*SLTI*/   r[rt]=r[rs]<(short)imm;  break;
 | 
      
         | 1179 |  |  |     case 0x0b:/*SLTIU*/  u[rt]=u[rs]<(unsigned int)(short)imm; break;
 | 
      
         | 1180 |  |  |     case 0x0c:/*ANDI*/   r[rt]=r[rs]&imm;         break;
 | 
      
         | 1181 |  |  |     case 0x0d:/*ORI*/    r[rt]=r[rs]|imm;         break;
 | 
      
         | 1182 |  |  |     case 0x0e:/*XORI*/   r[rt]=r[rs]^imm;         break;
 | 
      
         | 1183 |  |  |     case 0x0f:/*LUI*/    r[rt]=(imm<<16);         break;
 | 
      
         | 1184 | 152 | ja_rd |     case 0x10:/*COP0*/
 | 
      
         | 1185 |  |  |         if(s->status & 0x02){ /* kernel mode? */
 | 
      
         | 1186 | 163 | ja_rd |             if((opcode & (1<<23)) == 0){  //move from CP0 (mfc0)
 | 
      
         | 1187 |  |  |                 //printf("mfc0: [SR]=0x%08x @ [0x%08x]\n", s->status, epc);
 | 
      
         | 1188 | 152 | ja_rd |                 switch(rd){
 | 
      
         | 1189 |  |  |                     case 12: r[rt]=s->status & 0x0000003f; break;
 | 
      
         | 1190 |  |  |                     case 13: r[rt]=s->cp0_cause; break;
 | 
      
         | 1191 |  |  |                     case 14: r[rt]=s->epc; break;
 | 
      
         | 1192 |  |  |                     case 15: r[rt]=R3000_ID; break;
 | 
      
         | 1193 |  |  |                     default:
 | 
      
         | 1194 | 166 | ja_rd |                         printf("mfc0 [%02d] @ [0x%08x]\n", rt, s->pc);
 | 
      
         | 1195 | 152 | ja_rd |                         break;
 | 
      
         | 1196 |  |  |                 }
 | 
      
         | 1197 | 27 | ja_rd |             }
 | 
      
         | 1198 | 152 | ja_rd |             else{                         //move to CP0 (mtc0)
 | 
      
         | 1199 | 163 | ja_rd |                 /* FIXME check CF= reg address */
 | 
      
         | 1200 |  |  |                 if(rd==12){
 | 
      
         | 1201 |  |  |                     s->status=r[rt] & 0x0003003f; /* mask W/O bits */
 | 
      
         | 1202 |  |  |                     //printf("mtc0: [SR]=0x%08x @ [0x%08x]\n", s->status, epc);
 | 
      
         | 1203 |  |  |                 }
 | 
      
         | 1204 |  |  |                 else{
 | 
      
         | 1205 |  |  |                     /* Move to unimplemented COP0 register: display warning */
 | 
      
         | 1206 |  |  |                     /* FIXME should log ignored move */
 | 
      
         | 1207 |  |  |                     printf("mtc0 [%2d]=0x%08x @ [0x%08x] IGNORED\n",
 | 
      
         | 1208 |  |  |                            rd, r[rt], epc);
 | 
      
         | 1209 |  |  |                 }
 | 
      
         | 1210 | 152 | ja_rd |             }
 | 
      
         | 1211 |  |  |         }
 | 
      
         | 1212 |  |  |         else{
 | 
      
         | 1213 |  |  |             /* tried to execute mtc* or mfc* in user mode: trap */
 | 
      
         | 1214 | 166 | ja_rd |             printf("COP0 UNAVAILABLE [0x%08x] = 0x%x %c -- ",
 | 
      
         | 1215 |  |  |                    epc, opcode, (s->delay_slot? 'D':' '));
 | 
      
         | 1216 | 163 | ja_rd |             print_opcode_fields(opcode);
 | 
      
         | 1217 |  |  |             printf("\n");
 | 
      
         | 1218 |  |  |  
 | 
      
         | 1219 | 166 | ja_rd |             s->trap_cause = 11; /* unavailable coprocessor */
 | 
      
         | 1220 | 31 | ja_rd |         }
 | 
      
         | 1221 |  |  |         break;
 | 
      
         | 1222 | 105 | ja_rd |     case 0x11:/*COP1*/  unimplemented(s,"COP1");
 | 
      
         | 1223 |  |  |                         break;
 | 
      
         | 1224 | 2 | ja_rd | //      case 0x12:/*COP2*/ break;
 | 
      
         | 1225 |  |  | //      case 0x13:/*COP3*/ break;
 | 
      
         | 1226 | 31 | ja_rd |     case 0x14:/*BEQL*/  lbranch=r[rs]==r[rt];    break;
 | 
      
         | 1227 |  |  |     case 0x15:/*BNEL*/  lbranch=r[rs]!=r[rt];    break;
 | 
      
         | 1228 |  |  |     case 0x16:/*BLEZL*/ lbranch=r[rs]<=0;        break;
 | 
      
         | 1229 |  |  |     case 0x17:/*BGTZL*/ lbranch=r[rs]>0;         break;
 | 
      
         | 1230 | 166 | ja_rd |     case 0x1c:/*SPECIAL2*/
 | 
      
         | 1231 |  |  |         /* MIPS32 opcodes, some of which may be emulated */
 | 
      
         | 1232 |  |  |         if(cmd_line_args.emulate_some_mips32){
 | 
      
         | 1233 |  |  |             switch(func){
 | 
      
         | 1234 |  |  |                 case 0x20: /* CLZ */ r[rt] = count_leading(0, r[rs]); break;
 | 
      
         | 1235 |  |  |                 case 0x21: /* CLO */ r[rt] = count_leading(1, r[rs]); break;
 | 
      
         | 1236 |  |  |                 case 0x02: /* MUL */ r[rd] = mult_gpr(r[rs], r[rt]); break;
 | 
      
         | 1237 |  |  |                 default:
 | 
      
         | 1238 |  |  |                     reserved_opcode(epc, opcode, s);
 | 
      
         | 1239 |  |  |             }
 | 
      
         | 1240 |  |  |         }
 | 
      
         | 1241 |  |  |         else{
 | 
      
         | 1242 |  |  |             reserved_opcode(epc, opcode, s);
 | 
      
         | 1243 |  |  |         }
 | 
      
         | 1244 |  |  |         break;
 | 
      
         | 1245 |  |  |     case 0x1f: /* SPECIAL3 */
 | 
      
         | 1246 |  |  |         if(cmd_line_args.emulate_some_mips32){
 | 
      
         | 1247 |  |  |             switch(func){
 | 
      
         | 1248 |  |  |                 case 0x00: /* EXT */ r[rt] = ext_bitfield(r[rs], opcode); break;
 | 
      
         | 1249 |  |  |                 case 0x04: /* INS */ r[rt] = ins_bitfield(r[rt], r[rs], opcode); break;
 | 
      
         | 1250 |  |  |                 default:
 | 
      
         | 1251 |  |  |                     reserved_opcode(epc, opcode, s);
 | 
      
         | 1252 |  |  |             }
 | 
      
         | 1253 |  |  |         }
 | 
      
         | 1254 |  |  |         break;
 | 
      
         | 1255 | 31 | ja_rd |     case 0x20:/*LB*/    //r[rt]=(signed char)mem_read(s,1,ptr,1);  break;
 | 
      
         | 1256 | 53 | ja_rd |                         start_load(s, ptr, rt,(signed char)mem_read(s,1,ptr,1));
 | 
      
         | 1257 | 31 | ja_rd |                         break;
 | 
      
         | 1258 | 2 | ja_rd |  
 | 
      
         | 1259 | 31 | ja_rd |     case 0x21:/*LH*/    //r[rt]=(signed short)mem_read(s,2,ptr,1); break;
 | 
      
         | 1260 | 53 | ja_rd |                         start_load(s, ptr, rt, (signed short)mem_read(s,2,ptr,1));
 | 
      
         | 1261 | 31 | ja_rd |                         break;
 | 
      
         | 1262 | 105 | ja_rd |     case 0x22:/*LWL*/   mem_lwl(s, ptr, rt, 1);
 | 
      
         | 1263 |  |  |                         //printf("LWL\n");
 | 
      
         | 1264 | 31 | ja_rd |                         break;
 | 
      
         | 1265 |  |  |     case 0x23:/*LW*/    //r[rt]=mem_read(s,4,ptr,1);   break;
 | 
      
         | 1266 | 53 | ja_rd |                         start_load(s, ptr, rt, mem_read(s,4,ptr,1));
 | 
      
         | 1267 | 31 | ja_rd |                         break;
 | 
      
         | 1268 |  |  |     case 0x24:/*LBU*/   //r[rt]=(unsigned char)mem_read(s,1,ptr,1); break;
 | 
      
         | 1269 | 53 | ja_rd |                         start_load(s, ptr, rt, (unsigned char)mem_read(s,1,ptr,1));
 | 
      
         | 1270 | 31 | ja_rd |                         break;
 | 
      
         | 1271 |  |  |     case 0x25:/*LHU*/   //r[rt]= (unsigned short)mem_read(s,2,ptr,1);
 | 
      
         | 1272 | 53 | ja_rd |                         start_load(s, ptr, rt, (unsigned short)mem_read(s,2,ptr,1));
 | 
      
         | 1273 | 31 | ja_rd |                         break;
 | 
      
         | 1274 | 105 | ja_rd |     case 0x26:/*LWR*/   mem_lwr(s, ptr, rt, 1);
 | 
      
         | 1275 |  |  |                         //printf("LWR\n");
 | 
      
         | 1276 | 31 | ja_rd |                         break;
 | 
      
         | 1277 |  |  |     case 0x28:/*SB*/    mem_write(s,1,ptr,r[rt],1);  break;
 | 
      
         | 1278 |  |  |     case 0x29:/*SH*/    mem_write(s,2,ptr,r[rt],1);  break;
 | 
      
         | 1279 | 105 | ja_rd |     case 0x2a:/*SWL*/   mem_swl(s, ptr, r[rt], 1);
 | 
      
         | 1280 |  |  |                         //printf("SWL\n");
 | 
      
         | 1281 |  |  |                         break;
 | 
      
         | 1282 | 31 | ja_rd |     case 0x2b:/*SW*/    mem_write(s,4,ptr,r[rt],1);  break;
 | 
      
         | 1283 | 105 | ja_rd |     case 0x2e:/*SWR*/   mem_swr(s, ptr, r[rt], 1);
 | 
      
         | 1284 |  |  |                         //printf("SWR\n");
 | 
      
         | 1285 |  |  |                         break;
 | 
      
         | 1286 |  |  |     case 0x2f:/*CACHE*/ unimplemented(s,"CACHE");
 | 
      
         | 1287 |  |  |                         break;
 | 
      
         | 1288 |  |  |     case 0x30:/*LL*/    //unimplemented(s,"LL");
 | 
      
         | 1289 | 53 | ja_rd |                         start_load(s, ptr, rt, mem_read(s,4,ptr,1));
 | 
      
         | 1290 | 31 | ja_rd |                         break;
 | 
      
         | 1291 | 2 | ja_rd | //      case 0x31:/*LWC1*/ break;
 | 
      
         | 1292 |  |  | //      case 0x32:/*LWC2*/ break;
 | 
      
         | 1293 |  |  | //      case 0x33:/*LWC3*/ break;
 | 
      
         | 1294 |  |  | //      case 0x35:/*LDC1*/ break;
 | 
      
         | 1295 |  |  | //      case 0x36:/*LDC2*/ break;
 | 
      
         | 1296 |  |  | //      case 0x37:/*LDC3*/ break;
 | 
      
         | 1297 |  |  | //      case 0x38:/*SC*/     *(int*)ptr=r[rt]; r[rt]=1; break;
 | 
      
         | 1298 | 31 | ja_rd |     case 0x38:/*SC*/    mem_write(s,4,ptr,r[rt],1); r[rt]=1; break;
 | 
      
         | 1299 | 2 | ja_rd | //      case 0x39:/*SWC1*/ break;
 | 
      
         | 1300 |  |  | //      case 0x3a:/*SWC2*/ break;
 | 
      
         | 1301 |  |  | //      case 0x3b:/*SWC3*/ break;
 | 
      
         | 1302 |  |  | //      case 0x3d:/*SDC1*/ break;
 | 
      
         | 1303 |  |  | //      case 0x3e:/*SDC2*/ break;
 | 
      
         | 1304 |  |  | //      case 0x3f:/*SDC3*/ break;
 | 
      
         | 1305 | 163 | ja_rd |     default:  /* unimplemented opcode */
 | 
      
         | 1306 | 166 | ja_rd |         reserved_opcode(epc, opcode, s);
 | 
      
         | 1307 | 31 | ja_rd |     }
 | 
      
         | 1308 | 53 | ja_rd |  
 | 
      
         | 1309 | 166 | ja_rd |     /* */
 | 
      
         | 1310 |  |  |     if((branch || lbranch == 1) && link){
 | 
      
         | 1311 |  |  |         log_call(s->pc_next + imm_shift, epc);
 | 
      
         | 1312 |  |  |     }
 | 
      
         | 1313 |  |  |  
 | 
      
         | 1314 | 163 | ja_rd |     /* adjust next PC if this was a a jump instruction */
 | 
      
         | 1315 | 31 | ja_rd |     s->pc_next += (branch || lbranch == 1) ? imm_shift : 0;
 | 
      
         | 1316 |  |  |     s->pc_next &= ~3;
 | 
      
         | 1317 |  |  |     s->skip = (lbranch == 0) | skip2;
 | 
      
         | 1318 | 2 | ja_rd |  
 | 
      
         | 1319 | 31 | ja_rd |     /* If there was trouble (failed assertions), log it */
 | 
      
         | 1320 |  |  |     if(s->failed_assertions!=0){
 | 
      
         | 1321 |  |  |         log_failed_assertions(s);
 | 
      
         | 1322 |  |  |         s->failed_assertions=0;
 | 
      
         | 1323 |  |  |     }
 | 
      
         | 1324 | 5 | ja_rd |  
 | 
      
         | 1325 | 31 | ja_rd |     /* if there's a delayed load pending, do it now: load reg with memory data*/
 | 
      
         | 1326 |  |  |     /* load delay slots not simulated */
 | 
      
         | 1327 | 2 | ja_rd |  
 | 
      
         | 1328 | 31 | ja_rd |     /* Handle exceptions */
 | 
      
         | 1329 | 166 | ja_rd |    if(s->trap_cause>=0){
 | 
      
         | 1330 | 31 | ja_rd |         r[rt] = rSave;
 | 
      
         | 1331 | 152 | ja_rd |         /* set cause field ... */
 | 
      
         | 1332 | 166 | ja_rd |         s->cp0_cause = (s->delay_slot & 0x1) << 31 | (s->trap_cause & 0x1f) << 2;
 | 
      
         | 1333 | 152 | ja_rd |         /* ...save previous KU/IE flags in SR... */
 | 
      
         | 1334 |  |  |         s->status = (s->status & 0xffffffc3) | ((s->status & 0x0f) << 2);
 | 
      
         | 1335 |  |  |         /* ...and raise KU(EXL) kernel mode flag */
 | 
      
         | 1336 |  |  |         s->status |= 0x02;
 | 
      
         | 1337 | 31 | ja_rd |         /* adjust epc if we (i.e. the victim instruction) are in a delay slot */
 | 
      
         | 1338 |  |  |         if(s->delay_slot){
 | 
      
         | 1339 | 152 | ja_rd |             epc = epc - 4;
 | 
      
         | 1340 | 31 | ja_rd |         }
 | 
      
         | 1341 |  |  |         s->epc = epc;
 | 
      
         | 1342 | 61 | ja_rd |         s->pc_next = VECTOR_TRAP;
 | 
      
         | 1343 | 31 | ja_rd |         s->skip = 1;
 | 
      
         | 1344 |  |  |         s->userMode = 0;
 | 
      
         | 1345 |  |  |         //s->wakeup = 1;
 | 
      
         | 1346 |  |  |     }
 | 
      
         | 1347 | 27 | ja_rd |  
 | 
      
         | 1348 | 53 | ja_rd |     /* if we're NOT showing output to console, log state of CPU to file */
 | 
      
         | 1349 |  |  |     if(!show_mode){
 | 
      
         | 1350 | 166 | ja_rd |         s->wakeup |= log_cycle(s);
 | 
      
         | 1351 | 53 | ja_rd |     }
 | 
      
         | 1352 |  |  |  
 | 
      
         | 1353 |  |  |  
 | 
      
         | 1354 |  |  |  
 | 
      
         | 1355 | 31 | ja_rd |     /* if this instruction was any kind of branch that actually jumped, then
 | 
      
         | 1356 |  |  |        the next instruction will be in a delay slot. Remember it. */
 | 
      
         | 1357 |  |  |     delay_slot = ((lbranch==1) || branch || delay_slot);
 | 
      
         | 1358 |  |  |     s->delay_slot = delay_slot;
 | 
      
         | 1359 | 2 | ja_rd | }
 | 
      
         | 1360 |  |  |  
 | 
      
         | 1361 | 152 | ja_rd | /** Print opcode fields for easier debugging */
 | 
      
         | 1362 |  |  | void print_opcode_fields(uint32_t opcode){
 | 
      
         | 1363 |  |  |     uint32_t field;
 | 
      
         | 1364 |  |  |  
 | 
      
         | 1365 |  |  |     field = (opcode >> 26)&0x3f;
 | 
      
         | 1366 |  |  |     printf("%02x:", field);
 | 
      
         | 1367 |  |  |     field = (opcode >> 21)&0x1f;
 | 
      
         | 1368 |  |  |     printf("%02x:", field);
 | 
      
         | 1369 |  |  |     field = (opcode >> 16)&0x1f;
 | 
      
         | 1370 |  |  |     printf("%02x:", field);
 | 
      
         | 1371 |  |  |     field = (opcode >> 11)&0x1f;
 | 
      
         | 1372 |  |  |     printf("%02x:", field);
 | 
      
         | 1373 |  |  |     field = (opcode >>  6)&0x1f;
 | 
      
         | 1374 |  |  |     printf("%02x:", field);
 | 
      
         | 1375 |  |  |     field = (opcode >>  0)&0x3f;
 | 
      
         | 1376 |  |  |     printf("%02x",  field);
 | 
      
         | 1377 |  |  | }
 | 
      
         | 1378 |  |  |  
 | 
      
         | 1379 | 166 | ja_rd | /** Deal with reserved, unimplemented opcodes. Updates s->trap_cause. */
 | 
      
         | 1380 |  |  | void reserved_opcode(uint32_t pc, uint32_t opcode, t_state* s){
 | 
      
         | 1381 |  |  |     if(cmd_line_args.trap_on_reserved){
 | 
      
         | 1382 |  |  |         s->trap_cause = 10; /* reserved instruction */
 | 
      
         | 1383 |  |  |     }
 | 
      
         | 1384 |  |  |     else{
 | 
      
         | 1385 |  |  |         printf("RESERVED OPCODE [0x%08x] = 0x%08x %c -- ",
 | 
      
         | 1386 |  |  |                 pc, opcode, (s->delay_slot? 'D':' '));
 | 
      
         | 1387 |  |  |         print_opcode_fields(opcode);
 | 
      
         | 1388 |  |  |         printf("\n");
 | 
      
         | 1389 |  |  |     }
 | 
      
         | 1390 |  |  | }
 | 
      
         | 1391 | 152 | ja_rd |  
 | 
      
         | 1392 | 166 | ja_rd |  
 | 
      
         | 1393 | 2 | ja_rd | /** Dump CPU state to console */
 | 
      
         | 1394 | 31 | ja_rd | void show_state(t_state *s){
 | 
      
         | 1395 |  |  |     int i,j;
 | 
      
         | 1396 |  |  |     printf("pid=%d userMode=%d, epc=0x%x\n", s->processId, s->userMode, s->epc);
 | 
      
         | 1397 | 163 | ja_rd |     printf("hi=0x%08x lo=0x%08x\n", s->hi, s->lo);
 | 
      
         | 1398 |  |  |  
 | 
      
         | 1399 |  |  |     /* print register values */
 | 
      
         | 1400 |  |  |     #if FANCY_REGISTER_DISPLAY
 | 
      
         | 1401 |  |  |     printf(" v = [%08x %08x]  ", s->r[2], s->r[3]);
 | 
      
         | 1402 |  |  |     printf("           a = [");
 | 
      
         | 1403 |  |  |     for(i=4;i<8;i++){
 | 
      
         | 1404 |  |  |         printf("%08x ", s->r[i]);
 | 
      
         | 1405 |  |  |     }
 | 
      
         | 1406 |  |  |     printf("]\n");
 | 
      
         | 1407 |  |  |     printf(" s = [");
 | 
      
         | 1408 |  |  |     for(i=16;i<24;i++){
 | 
      
         | 1409 |  |  |         printf("%08x ", s->r[i]);
 | 
      
         | 1410 |  |  |     }
 | 
      
         | 1411 |  |  |     printf("]\n");
 | 
      
         | 1412 |  |  |     printf(" t = [");
 | 
      
         | 1413 |  |  |     for(i=8;i<16;i++){
 | 
      
         | 1414 |  |  |         printf("%08x ", s->r[i]);
 | 
      
         | 1415 |  |  |     }
 | 
      
         | 1416 |  |  |     printf("-\n");
 | 
      
         | 1417 |  |  |     printf("      %08x %08x]  ", s->r[24], s->r[25]);
 | 
      
         | 1418 |  |  |     printf("                          ");
 | 
      
         | 1419 |  |  |     printf("  k = [ %08x %08x ]\n", s->r[26], s->r[27]);
 | 
      
         | 1420 |  |  |     printf(" gp = %08x     sp = %08x    ", s->r[28], s->r[29]);
 | 
      
         | 1421 |  |  |     printf(" fp = %08x     ra = %08x ", s->r[30], s->r[31]);
 | 
      
         | 1422 |  |  |     printf("\n\n");
 | 
      
         | 1423 |  |  |     #else
 | 
      
         | 1424 | 31 | ja_rd |     for(i = 0; i < 4; ++i){
 | 
      
         | 1425 |  |  |         printf("%2.2d ", i * 8);
 | 
      
         | 1426 |  |  |         for(j = 0; j < 8; ++j){
 | 
      
         | 1427 |  |  |             printf("%8.8x ", s->r[i*8+j]);
 | 
      
         | 1428 |  |  |         }
 | 
      
         | 1429 |  |  |         printf("\n");
 | 
      
         | 1430 | 163 | ja_rd |     }
 | 
      
         | 1431 |  |  |     #endif
 | 
      
         | 1432 |  |  |  
 | 
      
         | 1433 |  |  |     j = s->pc; /* save pc value (it's altered by the 'cycle' function) */
 | 
      
         | 1434 | 31 | ja_rd |     for(i = -4; i <= 8; ++i){
 | 
      
         | 1435 |  |  |         printf("%c", i==0 ? '*' : ' ');
 | 
      
         | 1436 |  |  |         s->pc = j + i * 4;
 | 
      
         | 1437 |  |  |         cycle(s, 10);
 | 
      
         | 1438 | 163 | ja_rd |     }
 | 
      
         | 1439 |  |  |     s->t.disasm_ptr = s->pc; /* executing code updates the disasm pointer */
 | 
      
         | 1440 |  |  |     s->pc = j; /* restore pc value */
 | 
      
         | 1441 | 2 | ja_rd | }
 | 
      
         | 1442 |  |  |  
 | 
      
         | 1443 |  |  | /** Show debug monitor prompt and execute user command */
 | 
      
         | 1444 | 105 | ja_rd | void do_debug(t_state *s, uint32_t no_prompt){
 | 
      
         | 1445 | 31 | ja_rd |     int ch;
 | 
      
         | 1446 | 105 | ja_rd |     int i, j=0, watch=0, addr;
 | 
      
         | 1447 |  |  |     j = s->breakpoint;
 | 
      
         | 1448 | 31 | ja_rd |     s->pc_next = s->pc + 4;
 | 
      
         | 1449 |  |  |     s->skip = 0;
 | 
      
         | 1450 | 105 | ja_rd |     s->wakeup = 0;
 | 
      
         | 1451 |  |  |  
 | 
      
         | 1452 |  |  |     printf("Starting simulation.\n");
 | 
      
         | 1453 |  |  |  
 | 
      
         | 1454 |  |  |     if(no_prompt){
 | 
      
         | 1455 |  |  |         ch = '5'; /* 'go' command */
 | 
      
         | 1456 |  |  |         printf("\n\n");
 | 
      
         | 1457 |  |  |     }
 | 
      
         | 1458 |  |  |     else{
 | 
      
         | 1459 |  |  |         show_state(s);
 | 
      
         | 1460 |  |  |         ch = ' ';
 | 
      
         | 1461 |  |  |     }
 | 
      
         | 1462 |  |  |  
 | 
      
         | 1463 | 31 | ja_rd |     for(;;){
 | 
      
         | 1464 | 105 | ja_rd |         if(ch != 'n' && !no_prompt){
 | 
      
         | 1465 | 31 | ja_rd |             if(watch){
 | 
      
         | 1466 |  |  |                 printf("0x%8.8x=0x%8.8x\n", watch, mem_read(s, 4, watch,0));
 | 
      
         | 1467 | 2 | ja_rd |             }
 | 
      
         | 1468 | 163 | ja_rd |             printf("1=Debug   2=Trace   3=Step    4=BreakPt 5=Go      ");
 | 
      
         | 1469 |  |  |             printf("6=Memory  7=Watch   8=Jump\n");
 | 
      
         | 1470 |  |  |             printf("9=Quit    A=Dump    L=LogTrg  C=Disasm  ");
 | 
      
         | 1471 |  |  |             printf("> ");
 | 
      
         | 1472 | 31 | ja_rd |         }
 | 
      
         | 1473 | 105 | ja_rd |         if(ch==' ') ch = getch();
 | 
      
         | 1474 | 31 | ja_rd |         if(ch != 'n'){
 | 
      
         | 1475 |  |  |             printf("\n");
 | 
      
         | 1476 |  |  |         }
 | 
      
         | 1477 |  |  |         switch(ch){
 | 
      
         | 1478 |  |  |         case 'a': case 'A':
 | 
      
         | 1479 |  |  |             dump_trace_buffer(s); break;
 | 
      
         | 1480 |  |  |         case '1': case 'd': case ' ':
 | 
      
         | 1481 |  |  |             cycle(s, 0); show_state(s); break;
 | 
      
         | 1482 |  |  |         case 'n':
 | 
      
         | 1483 |  |  |             cycle(s, 1); break;
 | 
      
         | 1484 |  |  |         case '2': case 't':
 | 
      
         | 1485 |  |  |             cycle(s, 0); printf("*"); cycle(s, 10); break;
 | 
      
         | 1486 |  |  |         case '3': case 's':
 | 
      
         | 1487 |  |  |             printf("Count> ");
 | 
      
         | 1488 |  |  |             scanf("%d", &j);
 | 
      
         | 1489 |  |  |             for(i = 0; i < j; ++i){
 | 
      
         | 1490 |  |  |                 cycle(s, 1);
 | 
      
         | 1491 |  |  |             }
 | 
      
         | 1492 |  |  |             show_state(s);
 | 
      
         | 1493 |  |  |             break;
 | 
      
         | 1494 |  |  |         case '4': case 'b':
 | 
      
         | 1495 |  |  |             printf("Line> ");
 | 
      
         | 1496 |  |  |             scanf("%x", &j);
 | 
      
         | 1497 |  |  |             printf("break point=0x%x\n", j);
 | 
      
         | 1498 |  |  |             break;
 | 
      
         | 1499 |  |  |         case '5': case 'g':
 | 
      
         | 1500 |  |  |             s->wakeup = 0;
 | 
      
         | 1501 | 2 | ja_rd |             cycle(s, 0);
 | 
      
         | 1502 | 31 | ja_rd |             while(s->wakeup == 0){
 | 
      
         | 1503 |  |  |                 if(s->pc == j){
 | 
      
         | 1504 |  |  |                     printf("\n\nStop: pc = 0x%08x\n\n", j);
 | 
      
         | 1505 |  |  |                     break;
 | 
      
         | 1506 |  |  |                 }
 | 
      
         | 1507 |  |  |                 cycle(s, 0);
 | 
      
         | 1508 | 105 | ja_rd |             }
 | 
      
         | 1509 |  |  |             if(no_prompt) return;
 | 
      
         | 1510 | 31 | ja_rd |             show_state(s);
 | 
      
         | 1511 |  |  |             break;
 | 
      
         | 1512 |  |  |         case 'G':
 | 
      
         | 1513 |  |  |             s->wakeup = 0;
 | 
      
         | 1514 | 2 | ja_rd |             cycle(s, 1);
 | 
      
         | 1515 | 31 | ja_rd |             while(s->wakeup == 0){
 | 
      
         | 1516 |  |  |                 if(s->pc == j){
 | 
      
         | 1517 |  |  |                     break;
 | 
      
         | 1518 |  |  |                 }
 | 
      
         | 1519 |  |  |                 cycle(s, 1);
 | 
      
         | 1520 |  |  |             }
 | 
      
         | 1521 |  |  |             show_state(s);
 | 
      
         | 1522 |  |  |             break;
 | 
      
         | 1523 |  |  |         case '6': case 'm':
 | 
      
         | 1524 |  |  |             printf("Memory> ");
 | 
      
         | 1525 |  |  |             scanf("%x", &j);
 | 
      
         | 1526 |  |  |             for(i = 0; i < 8; ++i){
 | 
      
         | 1527 |  |  |                 printf("%8.8x ", mem_read(s, 4, j+i*4, 0));
 | 
      
         | 1528 |  |  |             }
 | 
      
         | 1529 |  |  |             printf("\n");
 | 
      
         | 1530 |  |  |             break;
 | 
      
         | 1531 |  |  |         case '7': case 'w':
 | 
      
         | 1532 |  |  |             printf("Watch> ");
 | 
      
         | 1533 |  |  |             scanf("%x", &watch);
 | 
      
         | 1534 |  |  |             break;
 | 
      
         | 1535 |  |  |         case '8': case 'j':
 | 
      
         | 1536 |  |  |             printf("Jump> ");
 | 
      
         | 1537 |  |  |             scanf("%x", &addr);
 | 
      
         | 1538 |  |  |             s->pc = addr;
 | 
      
         | 1539 |  |  |             s->pc_next = addr + 4;
 | 
      
         | 1540 |  |  |             show_state(s);
 | 
      
         | 1541 | 93 | ja_rd |             break;
 | 
      
         | 1542 |  |  |         case '9': case 'q':
 | 
      
         | 1543 |  |  |             return;
 | 
      
         | 1544 |  |  |         case 'l':
 | 
      
         | 1545 |  |  |             printf("Address> ");
 | 
      
         | 1546 |  |  |             scanf("%x", &(s->t.log_trigger_address));
 | 
      
         | 1547 |  |  |             printf("Log trigger address=0x%x\n", s->t.log_trigger_address);
 | 
      
         | 1548 | 163 | ja_rd |             break;
 | 
      
         | 1549 |  |  |         case 'c': case 'C':
 | 
      
         | 1550 |  |  |             j = s->pc;
 | 
      
         | 1551 |  |  |             for(i = 1; i <= 16; ++i){
 | 
      
         | 1552 |  |  |                 printf("%c", i==0 ? '*' : ' ');
 | 
      
         | 1553 |  |  |                 s->pc = s->t.disasm_ptr + i * 4;
 | 
      
         | 1554 |  |  |                 cycle(s, 10);
 | 
      
         | 1555 |  |  |             }
 | 
      
         | 1556 |  |  |             s->t.disasm_ptr = s->pc;
 | 
      
         | 1557 |  |  |             s->pc = j;
 | 
      
         | 1558 | 105 | ja_rd |         }
 | 
      
         | 1559 |  |  |         ch = ' ';
 | 
      
         | 1560 | 31 | ja_rd |     }
 | 
      
         | 1561 | 2 | ja_rd | }
 | 
      
         | 1562 |  |  |  
 | 
      
         | 1563 |  |  | /** Read binary code and data files */
 | 
      
         | 1564 | 61 | ja_rd | int read_binary_files(t_state *s, t_args *args){
 | 
      
         | 1565 | 31 | ja_rd |     FILE *in;
 | 
      
         | 1566 | 105 | ja_rd |     uint8_t *target;
 | 
      
         | 1567 |  |  |     uint32_t bytes=0, i, files_read=0;
 | 
      
         | 1568 | 2 | ja_rd |  
 | 
      
         | 1569 | 166 | ja_rd |     /* read map file if requested */
 | 
      
         | 1570 |  |  |     if(args->map_filename!=NULL){
 | 
      
         | 1571 |  |  |         if(read_map_file(args->map_filename, &map_info)<0){
 | 
      
         | 1572 |  |  |             printf("Trouble reading map file '%s', quitting!\n",
 | 
      
         | 1573 |  |  |                    args->map_filename);
 | 
      
         | 1574 |  |  |             return 1;
 | 
      
         | 1575 |  |  |         }
 | 
      
         | 1576 |  |  |         printf("Read %d functions from the map file; call trace enabled.\n\n",
 | 
      
         | 1577 |  |  |                map_info.num_functions);
 | 
      
         | 1578 |  |  |     }
 | 
      
         | 1579 |  |  |  
 | 
      
         | 1580 |  |  |     /* read object code binaries */
 | 
      
         | 1581 | 31 | ja_rd |     for(i=0;i<NUM_MEM_BLOCKS;i++){
 | 
      
         | 1582 | 105 | ja_rd |         bytes = 0;
 | 
      
         | 1583 | 61 | ja_rd |         if(args->bin_filename[i]!=NULL){
 | 
      
         | 1584 |  |  |  
 | 
      
         | 1585 |  |  |             in = fopen(args->bin_filename[i], "rb");
 | 
      
         | 1586 | 31 | ja_rd |             if(in == NULL){
 | 
      
         | 1587 | 44 | ja_rd |                 free_cpu(s);
 | 
      
         | 1588 | 61 | ja_rd |                 printf("Can't open file %s, quitting!\n",args->bin_filename[i]);
 | 
      
         | 1589 |  |  |                 return(0);
 | 
      
         | 1590 | 31 | ja_rd |             }
 | 
      
         | 1591 | 2 | ja_rd |  
 | 
      
         | 1592 | 105 | ja_rd |             /* FIXME load offset 0x2000 for linux kernel hardcoded! */
 | 
      
         | 1593 |  |  |             //bytes = fread((s->blocks[i].mem + 0x2000), 1, s->blocks[i].size, in);
 | 
      
         | 1594 |  |  |             target = (uint8_t *)(s->blocks[i].mem + args->offset[i]);
 | 
      
         | 1595 |  |  |             while(!feof(in) &&
 | 
      
         | 1596 |  |  |                   ((bytes+1024+args->offset[i]) < (s->blocks[i].size))){
 | 
      
         | 1597 |  |  |                 bytes += fread(&(target[bytes]), 1, 1024, in);
 | 
      
         | 1598 |  |  |                 if(errno!=0){
 | 
      
         | 1599 |  |  |                     printf("ERROR: file load failed with code %d ('%s')\n",
 | 
      
         | 1600 |  |  |                         errno, strerror(errno));
 | 
      
         | 1601 |  |  |                     free_cpu(s);
 | 
      
         | 1602 |  |  |                     return 0;
 | 
      
         | 1603 |  |  |                 }
 | 
      
         | 1604 |  |  |             }
 | 
      
         | 1605 |  |  |  
 | 
      
         | 1606 | 31 | ja_rd |             fclose(in);
 | 
      
         | 1607 | 105 | ja_rd |  
 | 
      
         | 1608 |  |  |             /* Now reverse the endianness of the data we just read, if it's
 | 
      
         | 1609 |  |  |              necessary. */
 | 
      
         | 1610 | 166 | ja_rd |              /* FIXME handle little-endian stuff (?) */
 | 
      
         | 1611 | 105 | ja_rd |             //reverse_endianess(target, bytes);
 | 
      
         | 1612 |  |  |  
 | 
      
         | 1613 | 31 | ja_rd |             files_read++;
 | 
      
         | 1614 |  |  |         }
 | 
      
         | 1615 | 105 | ja_rd |         printf("%-16s [size= %6dKB, start= 0x%08x] loaded %d bytes.\n",
 | 
      
         | 1616 |  |  |                 s->blocks[i].area_name,
 | 
      
         | 1617 |  |  |                 s->blocks[i].size/1024,
 | 
      
         | 1618 |  |  |                 s->blocks[i].start,
 | 
      
         | 1619 |  |  |                 bytes);
 | 
      
         | 1620 | 31 | ja_rd |     }
 | 
      
         | 1621 |  |  |  
 | 
      
         | 1622 |  |  |     if(!files_read){
 | 
      
         | 1623 | 44 | ja_rd |         free_cpu(s);
 | 
      
         | 1624 | 31 | ja_rd |         printf("No binary object files read, quitting\n");
 | 
      
         | 1625 | 44 | ja_rd |         return 0;
 | 
      
         | 1626 | 31 | ja_rd |     }
 | 
      
         | 1627 |  |  |  
 | 
      
         | 1628 | 44 | ja_rd |     return files_read;
 | 
      
         | 1629 | 2 | ja_rd | }
 | 
      
         | 1630 | 105 | ja_rd |  
 | 
      
         | 1631 |  |  | void reverse_endianess(uint8_t *data, uint32_t bytes){
 | 
      
         | 1632 |  |  |     uint8_t w[4];
 | 
      
         | 1633 |  |  |     uint32_t i, j;
 | 
      
         | 1634 |  |  |  
 | 
      
         | 1635 |  |  |     for(i=0;i<bytes;i=i+4){
 | 
      
         | 1636 |  |  |         for(j=0;j<4;j++){
 | 
      
         | 1637 |  |  |             w[3-j] = data[i+j];
 | 
      
         | 1638 |  |  |         }
 | 
      
         | 1639 |  |  |         for(j=0;j<4;j++){
 | 
      
         | 1640 |  |  |             data[i+j] = w[j];
 | 
      
         | 1641 |  |  |         }
 | 
      
         | 1642 |  |  |     }
 | 
      
         | 1643 |  |  | }
 | 
      
         | 1644 |  |  |  
 | 
      
         | 1645 | 2 | ja_rd |  
 | 
      
         | 1646 |  |  | /*----------------------------------------------------------------------------*/
 | 
      
         | 1647 |  |  |  
 | 
      
         | 1648 | 31 | ja_rd | int main(int argc,char *argv[]){
 | 
      
         | 1649 |  |  |     t_state state, *s=&state;
 | 
      
         | 1650 | 166 | ja_rd |  
 | 
      
         | 1651 |  |  |  
 | 
      
         | 1652 | 105 | ja_rd |  
 | 
      
         | 1653 |  |  |     /* Parse command line and pass any relevant arguments to CPU record */
 | 
      
         | 1654 |  |  |     if(parse_cmd_line(argc,argv, &cmd_line_args)==0){
 | 
      
         | 1655 |  |  |         return 0;
 | 
      
         | 1656 |  |  |     }
 | 
      
         | 1657 | 2 | ja_rd |  
 | 
      
         | 1658 | 61 | ja_rd |     printf("MIPS-I emulator (" __DATE__ ")\n\n");
 | 
      
         | 1659 | 105 | ja_rd |     if(!init_cpu(s, &cmd_line_args)){
 | 
      
         | 1660 | 44 | ja_rd |         printf("Trouble allocating memory, quitting!\n");
 | 
      
         | 1661 |  |  |         return 1;
 | 
      
         | 1662 |  |  |     };
 | 
      
         | 1663 | 61 | ja_rd |  
 | 
      
         | 1664 | 93 | ja_rd |     /* Read binary object files into memory*/
 | 
      
         | 1665 | 61 | ja_rd |     if(!read_binary_files(s, &cmd_line_args)){
 | 
      
         | 1666 | 31 | ja_rd |         return 2;
 | 
      
         | 1667 |  |  |     }
 | 
      
         | 1668 | 61 | ja_rd |     printf("\n\n");
 | 
      
         | 1669 | 2 | ja_rd |  
 | 
      
         | 1670 | 93 | ja_rd |     init_trace_buffer(s, &cmd_line_args);
 | 
      
         | 1671 | 2 | ja_rd |  
 | 
      
         | 1672 | 31 | ja_rd |     /* NOTE: Original mlite supported loading little-endian code, which this
 | 
      
         | 1673 | 2 | ja_rd |       program doesn't. The endianess-conversion code has been removed.
 | 
      
         | 1674 | 31 | ja_rd |     */
 | 
      
         | 1675 | 2 | ja_rd |  
 | 
      
         | 1676 | 31 | ja_rd |     /* Simulate a CPU reset */
 | 
      
         | 1677 | 105 | ja_rd |     reset_cpu(s);
 | 
      
         | 1678 |  |  |  
 | 
      
         | 1679 |  |  |     /* Simulate the work of the uClinux bootloader */
 | 
      
         | 1680 | 166 | ja_rd |     if(cmd_line_args.memory_map == MAP_UCLINUX_BRAM){
 | 
      
         | 1681 |  |  |         /* FIXME this 'bootloader' is a stub, flesh it out */
 | 
      
         | 1682 | 105 | ja_rd |         s->pc = 0x80002400;
 | 
      
         | 1683 |  |  |     }
 | 
      
         | 1684 | 2 | ja_rd |  
 | 
      
         | 1685 | 31 | ja_rd |     /* Enter debug command interface; will only exit clean with user command */
 | 
      
         | 1686 | 105 | ja_rd |     do_debug(s, cmd_line_args.no_prompt);
 | 
      
         | 1687 | 2 | ja_rd |  
 | 
      
         | 1688 | 31 | ja_rd |     /* Close and deallocate everything and quit */
 | 
      
         | 1689 |  |  |     close_trace_buffer(s);
 | 
      
         | 1690 |  |  |     free_cpu(s);
 | 
      
         | 1691 |  |  |     return(0);
 | 
      
         | 1692 | 2 | ja_rd | }
 | 
      
         | 1693 |  |  |  
 | 
      
         | 1694 |  |  | /*----------------------------------------------------------------------------*/
 | 
      
         | 1695 |  |  |  
 | 
      
         | 1696 |  |  |  
 | 
      
         | 1697 | 93 | ja_rd | void init_trace_buffer(t_state *s, t_args *args){
 | 
      
         | 1698 | 31 | ja_rd |     int i;
 | 
      
         | 1699 | 2 | ja_rd |  
 | 
      
         | 1700 | 163 | ja_rd |     /* setup misc info related to the monitor interface */
 | 
      
         | 1701 |  |  |     s->t.disasm_ptr = VECTOR_RESET;
 | 
      
         | 1702 |  |  |  
 | 
      
         | 1703 | 2 | ja_rd | #if FILE_LOGGING_DISABLED
 | 
      
         | 1704 | 31 | ja_rd |     s->t.log = NULL;
 | 
      
         | 1705 | 93 | ja_rd |     s->t.log_triggered = 0;
 | 
      
         | 1706 | 166 | ja_rd |     map_info.log = NULL;
 | 
      
         | 1707 | 31 | ja_rd |     return;
 | 
      
         | 1708 | 2 | ja_rd | #else
 | 
      
         | 1709 | 93 | ja_rd |     /* clear trace buffer */
 | 
      
         | 1710 | 31 | ja_rd |     for(i=0;i<TRACE_BUFFER_SIZE;i++){
 | 
      
         | 1711 |  |  |         s->t.buf[i]=0xffffffff;
 | 
      
         | 1712 |  |  |     }
 | 
      
         | 1713 |  |  |     s->t.next = 0;
 | 
      
         | 1714 | 2 | ja_rd |  
 | 
      
         | 1715 | 31 | ja_rd |     /* if file logging is enabled, open log file */
 | 
      
         | 1716 | 93 | ja_rd |     if(args->log_file_name!=NULL){
 | 
      
         | 1717 |  |  |         s->t.log = fopen(args->log_file_name, "w");
 | 
      
         | 1718 | 31 | ja_rd |         if(s->t.log==NULL){
 | 
      
         | 1719 |  |  |             printf("Error opening log file '%s', file logging disabled\n",
 | 
      
         | 1720 | 93 | ja_rd |                     args->log_file_name);
 | 
      
         | 1721 | 31 | ja_rd |         }
 | 
      
         | 1722 |  |  |     }
 | 
      
         | 1723 |  |  |     else{
 | 
      
         | 1724 |  |  |         s->t.log = NULL;
 | 
      
         | 1725 |  |  |     }
 | 
      
         | 1726 | 93 | ja_rd |  
 | 
      
         | 1727 |  |  |     /* Setup log trigger */
 | 
      
         | 1728 |  |  |     s->t.log_triggered = 0;
 | 
      
         | 1729 |  |  |     s->t.log_trigger_address = args->log_trigger_address;
 | 
      
         | 1730 | 166 | ja_rd |  
 | 
      
         | 1731 |  |  |     /* if file logging of function calls is enabled, open log file */
 | 
      
         | 1732 |  |  |     if(map_info.log_filename!=NULL){
 | 
      
         | 1733 |  |  |         map_info.log = fopen(map_info.log_filename, "w");
 | 
      
         | 1734 |  |  |         if(map_info.log==NULL){
 | 
      
         | 1735 |  |  |             printf("Error opening log file '%s', file logging disabled\n",
 | 
      
         | 1736 |  |  |                     map_info.log_filename);
 | 
      
         | 1737 |  |  |         }
 | 
      
         | 1738 |  |  |     }
 | 
      
         | 1739 | 2 | ja_rd | #endif
 | 
      
         | 1740 |  |  | }
 | 
      
         | 1741 |  |  |  
 | 
      
         | 1742 |  |  | /** Dumps last jump targets as a chunk of hex numbers (older is left top) */
 | 
      
         | 1743 | 31 | ja_rd | void dump_trace_buffer(t_state *s){
 | 
      
         | 1744 |  |  |     int i, col;
 | 
      
         | 1745 | 2 | ja_rd |  
 | 
      
         | 1746 | 31 | ja_rd |     for(i=0, col=0;i<TRACE_BUFFER_SIZE;i++, col++){
 | 
      
         | 1747 |  |  |         printf("%08x ", s->t.buf[s->t.next + i]);
 | 
      
         | 1748 |  |  |         if((col % 8)==7){
 | 
      
         | 1749 |  |  |             printf("\n");
 | 
      
         | 1750 |  |  |         }
 | 
      
         | 1751 |  |  |     }
 | 
      
         | 1752 | 2 | ja_rd | }
 | 
      
         | 1753 |  |  |  
 | 
      
         | 1754 |  |  | /** Logs last cycle's activity (changes in state and/or loads/stores) */
 | 
      
         | 1755 | 166 | ja_rd | uint32_t log_cycle(t_state *s){
 | 
      
         | 1756 | 31 | ja_rd |     static unsigned int last_pc = 0;
 | 
      
         | 1757 |  |  |     int i;
 | 
      
         | 1758 | 53 | ja_rd |     uint32_t log_pc;
 | 
      
         | 1759 | 2 | ja_rd |  
 | 
      
         | 1760 | 31 | ja_rd |     /* store PC in trace buffer only if there was a jump */
 | 
      
         | 1761 |  |  |     if(s->pc != (last_pc+4)){
 | 
      
         | 1762 |  |  |         s->t.buf[s->t.next] = s->pc;
 | 
      
         | 1763 |  |  |         s->t.next = (s->t.next + 1) % TRACE_BUFFER_SIZE;
 | 
      
         | 1764 |  |  |     }
 | 
      
         | 1765 | 166 | ja_rd |     last_pc = s->pc;
 | 
      
         | 1766 |  |  |     log_pc = s->op_addr;
 | 
      
         | 1767 |  |  |  
 | 
      
         | 1768 | 2 | ja_rd |  
 | 
      
         | 1769 | 31 | ja_rd |     /* if file logging is enabled, dump a trace log to file */
 | 
      
         | 1770 | 93 | ja_rd |     if(log_enabled(s)){
 | 
      
         | 1771 | 53 | ja_rd |  
 | 
      
         | 1772 | 147 | ja_rd |         /* skip register zero which does not change */
 | 
      
         | 1773 |  |  |         for(i=1;i<32;i++){
 | 
      
         | 1774 | 31 | ja_rd |             if(s->t.pr[i] != s->r[i]){
 | 
      
         | 1775 | 53 | ja_rd |                 fprintf(s->t.log, "(%08X) [%02X]=%08X\n", log_pc, i, s->r[i]);
 | 
      
         | 1776 | 31 | ja_rd |             }
 | 
      
         | 1777 |  |  |             s->t.pr[i] = s->r[i];
 | 
      
         | 1778 |  |  |         }
 | 
      
         | 1779 |  |  |         if(s->lo != s->t.lo){
 | 
      
         | 1780 | 147 | ja_rd |             //fprintf(s->t.log, "(%08X) [LO]=%08X\n", log_pc, s->lo);
 | 
      
         | 1781 | 31 | ja_rd |         }
 | 
      
         | 1782 |  |  |         s->t.lo = s->lo;
 | 
      
         | 1783 | 2 | ja_rd |  
 | 
      
         | 1784 | 31 | ja_rd |         if(s->hi != s->t.hi){
 | 
      
         | 1785 | 147 | ja_rd |             //fprintf(s->t.log, "(%08X) [HI]=%08X\n", log_pc, s->hi);
 | 
      
         | 1786 | 31 | ja_rd |         }
 | 
      
         | 1787 |  |  |         s->t.hi = s->hi;
 | 
      
         | 1788 | 2 | ja_rd |  
 | 
      
         | 1789 | 152 | ja_rd |         /* Catch changes in EPC by direct write (mtc0) and by exception */
 | 
      
         | 1790 | 31 | ja_rd |         if(s->epc != s->t.epc){
 | 
      
         | 1791 | 53 | ja_rd |             fprintf(s->t.log, "(%08X) [EP]=%08X\n", log_pc, s->epc);
 | 
      
         | 1792 | 31 | ja_rd |         }
 | 
      
         | 1793 |  |  |         s->t.epc = s->epc;
 | 
      
         | 1794 | 152 | ja_rd |  
 | 
      
         | 1795 | 166 | ja_rd |         if(s->status != s->t.status){
 | 
      
         | 1796 | 152 | ja_rd |             fprintf(s->t.log, "(%08X) [SR]=%08X\n", log_pc, s->status);
 | 
      
         | 1797 |  |  |         }
 | 
      
         | 1798 |  |  |         s->t.status = s->status;
 | 
      
         | 1799 | 166 | ja_rd |     }
 | 
      
         | 1800 |  |  |  
 | 
      
         | 1801 |  |  | #if 0
 | 
      
         | 1802 |  |  |     /* FIXME Try to detect a code crash by looking at SP */
 | 
      
         | 1803 |  |  |     if(1){
 | 
      
         | 1804 |  |  |             if((s->r[29]&0xffff0000) == 0xffff00000){
 | 
      
         | 1805 |  |  |                 printf("SP derailed! @ 0x%08x [0x%08x]\n", log_pc, s->r[29]);
 | 
      
         | 1806 |  |  |                 return 1;
 | 
      
         | 1807 |  |  |             }
 | 
      
         | 1808 |  |  |     }
 | 
      
         | 1809 |  |  | #endif
 | 
      
         | 1810 |  |  |  
 | 
      
         | 1811 |  |  |     return 0;
 | 
      
         | 1812 | 2 | ja_rd | }
 | 
      
         | 1813 |  |  |  
 | 
      
         | 1814 |  |  | /** Frees debug buffers and closes log file */
 | 
      
         | 1815 | 31 | ja_rd | void close_trace_buffer(t_state *s){
 | 
      
         | 1816 |  |  |     if(s->t.log){
 | 
      
         | 1817 |  |  |         fclose(s->t.log);
 | 
      
         | 1818 |  |  |     }
 | 
      
         | 1819 | 166 | ja_rd |     if(map_info.log){
 | 
      
         | 1820 |  |  |         fclose(map_info.log);
 | 
      
         | 1821 |  |  |     }
 | 
      
         | 1822 | 2 | ja_rd | }
 | 
      
         | 1823 | 5 | ja_rd |  
 | 
      
         | 1824 |  |  | /** Logs a message for each failed assertion, each in a line */
 | 
      
         | 1825 | 31 | ja_rd | void log_failed_assertions(t_state *s){
 | 
      
         | 1826 |  |  |     unsigned bitmap = s->failed_assertions;
 | 
      
         | 1827 |  |  |     int i = 0;
 | 
      
         | 1828 | 5 | ja_rd |  
 | 
      
         | 1829 | 31 | ja_rd |     /* This loop will crash the program if the message table is too short...*/
 | 
      
         | 1830 |  |  |     if(s->t.log != NULL){
 | 
      
         | 1831 |  |  |         for(i=0;i<32;i++){
 | 
      
         | 1832 |  |  |             if(bitmap & 0x1){
 | 
      
         | 1833 |  |  |                 fprintf(s->t.log, "ASSERTION FAILED: [%08x] %s\n",
 | 
      
         | 1834 |  |  |                         s->faulty_address,
 | 
      
         | 1835 |  |  |                         assertion_messages[i]);
 | 
      
         | 1836 |  |  |             }
 | 
      
         | 1837 |  |  |             bitmap = bitmap >> 1;
 | 
      
         | 1838 |  |  |         }
 | 
      
         | 1839 |  |  |     }
 | 
      
         | 1840 | 5 | ja_rd | }
 | 
      
         | 1841 | 31 | ja_rd |  
 | 
      
         | 1842 | 93 | ja_rd | uint32_t log_enabled(t_state *s){
 | 
      
         | 1843 |  |  |     return ((s->t.log != NULL) && (s->t.log_triggered!=0));
 | 
      
         | 1844 |  |  | }
 | 
      
         | 1845 |  |  |  
 | 
      
         | 1846 |  |  | void trigger_log(t_state *s){
 | 
      
         | 1847 |  |  |     uint32_t i;
 | 
      
         | 1848 |  |  |  
 | 
      
         | 1849 |  |  |     s->t.log_triggered = 1;
 | 
      
         | 1850 |  |  |  
 | 
      
         | 1851 |  |  |     for(i=0;i<32;i++){
 | 
      
         | 1852 |  |  |         s->t.pr[i] = s->r[i];
 | 
      
         | 1853 |  |  |     }
 | 
      
         | 1854 |  |  |  
 | 
      
         | 1855 |  |  |     s->t.lo = s->lo;
 | 
      
         | 1856 |  |  |     s->t.hi = s->hi;
 | 
      
         | 1857 |  |  |     s->t.epc = s->epc;
 | 
      
         | 1858 |  |  | }
 | 
      
         | 1859 |  |  |  
 | 
      
         | 1860 | 166 | ja_rd | int32_t read_map_file(char *filename, t_map_info* map){
 | 
      
         | 1861 |  |  |     FILE *f;
 | 
      
         | 1862 |  |  |     uint32_t address, i;
 | 
      
         | 1863 |  |  |     uint32_t segment_text = 0;
 | 
      
         | 1864 |  |  |     char line[256];
 | 
      
         | 1865 |  |  |     char name[256];
 | 
      
         | 1866 |  |  |  
 | 
      
         | 1867 |  |  |     f = fopen (filename, "rt");  /* open the file for reading */
 | 
      
         | 1868 |  |  |  
 | 
      
         | 1869 |  |  |     if(!f){
 | 
      
         | 1870 |  |  |         return -1;
 | 
      
         | 1871 |  |  |     }
 | 
      
         | 1872 |  |  |  
 | 
      
         | 1873 |  |  |    while(fgets(line, sizeof(line)-1, f) != NULL){
 | 
      
         | 1874 |  |  |        if(!strncmp(line, ".text", 5)){
 | 
      
         | 1875 |  |  |            segment_text = 1;
 | 
      
         | 1876 |  |  |        }
 | 
      
         | 1877 |  |  |        else if(line[0]==' ' && segment_text){
 | 
      
         | 1878 |  |  |             /* may be a function address */
 | 
      
         | 1879 |  |  |             for(i=0;(i<sizeof(line)-1) && (line[i]==' '); i++);
 | 
      
         | 1880 |  |  |             if(line[i]=='0'){
 | 
      
         | 1881 |  |  |                 sscanf(line, "%*[ \n\t]%x%*[ \n\t]%s", &address, &(name[0]));
 | 
      
         | 1882 |  |  |  
 | 
      
         | 1883 |  |  |                 strncpy(map->fn_name[map->num_functions],
 | 
      
         | 1884 |  |  |                         name, MAP_MAX_NAME_LEN-1);
 | 
      
         | 1885 |  |  |                 map->fn_address[map->num_functions] = address;
 | 
      
         | 1886 |  |  |                 map->num_functions++;
 | 
      
         | 1887 |  |  |                 if(map->num_functions >= MAP_MAX_FUNCTIONS){
 | 
      
         | 1888 |  |  |                     printf("WARNING: too many functions in map file!\n");
 | 
      
         | 1889 |  |  |                     return map->num_functions;
 | 
      
         | 1890 |  |  |                 }
 | 
      
         | 1891 |  |  |             }
 | 
      
         | 1892 |  |  |        }
 | 
      
         | 1893 |  |  |        else if(line[0]=='.' && segment_text){
 | 
      
         | 1894 |  |  |            break;
 | 
      
         | 1895 |  |  |        }
 | 
      
         | 1896 |  |  |     }
 | 
      
         | 1897 |  |  |     fclose(f);
 | 
      
         | 1898 |  |  |  
 | 
      
         | 1899 |  |  | #if 0
 | 
      
         | 1900 |  |  |     for(i=0;i<map->num_functions;i++){
 | 
      
         | 1901 |  |  |         printf("--> %08x %s\n", map->fn_address[i], map->fn_name[i]);
 | 
      
         | 1902 |  |  |     }
 | 
      
         | 1903 |  |  | #endif
 | 
      
         | 1904 |  |  |  
 | 
      
         | 1905 |  |  |     return map->num_functions;
 | 
      
         | 1906 |  |  | }
 | 
      
         | 1907 |  |  |  
 | 
      
         | 1908 |  |  |  
 | 
      
         | 1909 | 31 | ja_rd | void free_cpu(t_state *s){
 | 
      
         | 1910 |  |  |     int i;
 | 
      
         | 1911 |  |  |  
 | 
      
         | 1912 |  |  |     for(i=0;i<NUM_MEM_BLOCKS;i++){
 | 
      
         | 1913 |  |  |         free(s->blocks[i].mem);
 | 
      
         | 1914 |  |  |         s->blocks[i].mem = NULL;
 | 
      
         | 1915 |  |  |     }
 | 
      
         | 1916 |  |  | }
 | 
      
         | 1917 |  |  |  
 | 
      
         | 1918 |  |  | void reset_cpu(t_state *s){
 | 
      
         | 1919 | 163 | ja_rd |     s->pc = cmd_line_args.start_addr; /* reset start vector or cmd line address */
 | 
      
         | 1920 | 31 | ja_rd |     s->delay_slot = 0;
 | 
      
         | 1921 |  |  |     s->failed_assertions = 0; /* no failed assertions pending */
 | 
      
         | 1922 | 152 | ja_rd |     s->status = 0x02; /* kernel mode, interrupts disabled */
 | 
      
         | 1923 |  |  |     /* init trace struct to prevent spurious logs */
 | 
      
         | 1924 |  |  |     s->t.status = s->status;
 | 
      
         | 1925 | 31 | ja_rd | }
 | 
      
         | 1926 | 166 | ja_rd |  
 | 
      
         | 1927 |  |  | /* FIXME redundant function, merge with reserved_opcode */
 | 
      
         | 1928 | 105 | ja_rd | void unimplemented(t_state *s, const char *txt){
 | 
      
         | 1929 |  |  |     printf("UNIMPLEMENTED: %s\n", txt);
 | 
      
         | 1930 |  |  | }
 | 
      
         | 1931 | 31 | ja_rd |  
 | 
      
         | 1932 | 105 | ja_rd | int init_cpu(t_state *s, t_args *args){
 | 
      
         | 1933 |  |  |     int i, j;
 | 
      
         | 1934 |  |  |     uint32_t k = args->memory_map;
 | 
      
         | 1935 | 44 | ja_rd |  
 | 
      
         | 1936 | 31 | ja_rd |     memset(s, 0, sizeof(t_state));
 | 
      
         | 1937 |  |  |     s->big_endian = 1;
 | 
      
         | 1938 | 61 | ja_rd |  
 | 
      
         | 1939 | 105 | ja_rd |     s->do_unaligned = args->do_unaligned;
 | 
      
         | 1940 |  |  |     s->breakpoint = args->breakpoint;
 | 
      
         | 1941 |  |  |  
 | 
      
         | 1942 | 61 | ja_rd |     /* Initialize memory map */
 | 
      
         | 1943 | 31 | ja_rd |     for(i=0;i<NUM_MEM_BLOCKS;i++){
 | 
      
         | 1944 | 105 | ja_rd |         s->blocks[i].start =        memory_maps[k].blocks[i].start;
 | 
      
         | 1945 |  |  |         s->blocks[i].size =         memory_maps[k].blocks[i].size;
 | 
      
         | 1946 |  |  |         s->blocks[i].area_name =    memory_maps[k].blocks[i].area_name;
 | 
      
         | 1947 |  |  |         s->blocks[i].mask =         memory_maps[k].blocks[i].mask;
 | 
      
         | 1948 |  |  |         s->blocks[i].read_only =    memory_maps[k].blocks[i].read_only;
 | 
      
         | 1949 | 44 | ja_rd |  
 | 
      
         | 1950 |  |  |         s->blocks[i].mem = (unsigned char*)malloc(s->blocks[i].size);
 | 
      
         | 1951 |  |  |  
 | 
      
         | 1952 |  |  |         if(s->blocks[i].mem == NULL){
 | 
      
         | 1953 |  |  |             for(j=0;j<i;j++){
 | 
      
         | 1954 |  |  |                 free(s->blocks[j].mem);
 | 
      
         | 1955 |  |  |             }
 | 
      
         | 1956 |  |  |             return 0;
 | 
      
         | 1957 |  |  |         }
 | 
      
         | 1958 |  |  |         memset(s->blocks[i].mem, 0, s->blocks[i].size);
 | 
      
         | 1959 | 105 | ja_rd |     }
 | 
      
         | 1960 | 44 | ja_rd |     return NUM_MEM_BLOCKS;
 | 
      
         | 1961 | 31 | ja_rd | }
 | 
      
         | 1962 | 61 | ja_rd |  
 | 
      
         | 1963 |  |  | int32_t parse_cmd_line(uint32_t argc, char **argv, t_args *args){
 | 
      
         | 1964 |  |  |     uint32_t i;
 | 
      
         | 1965 |  |  |  
 | 
      
         | 1966 | 166 | ja_rd |     /* Initialize logging parameters */
 | 
      
         | 1967 |  |  |     map_info.num_functions = 0;
 | 
      
         | 1968 |  |  |     map_info.log_filename = NULL;
 | 
      
         | 1969 |  |  |     map_info.log = stdout;
 | 
      
         | 1970 |  |  |  
 | 
      
         | 1971 | 105 | ja_rd |     /* fill cmd line args with default values */
 | 
      
         | 1972 |  |  |     args->memory_map = MAP_DEFAULT;
 | 
      
         | 1973 | 163 | ja_rd |     args->trap_on_reserved = 1;
 | 
      
         | 1974 | 166 | ja_rd |     args->emulate_some_mips32 = 1;
 | 
      
         | 1975 | 163 | ja_rd |     args->start_addr = VECTOR_RESET;
 | 
      
         | 1976 | 105 | ja_rd |     args->do_unaligned = 0;
 | 
      
         | 1977 |  |  |     args->no_prompt = 0;
 | 
      
         | 1978 |  |  |     args->breakpoint = 0xffffffff;
 | 
      
         | 1979 |  |  |     args->log_file_name = "sw_sim_log.txt";
 | 
      
         | 1980 |  |  |     args->log_trigger_address = VECTOR_RESET;
 | 
      
         | 1981 | 166 | ja_rd |     args->map_filename = NULL;
 | 
      
         | 1982 | 61 | ja_rd |     for(i=0;i<NUM_MEM_BLOCKS;i++){
 | 
      
         | 1983 |  |  |         args->bin_filename[i] = NULL;
 | 
      
         | 1984 | 105 | ja_rd |         args->offset[i] = 0;
 | 
      
         | 1985 | 61 | ja_rd |     }
 | 
      
         | 1986 |  |  |  
 | 
      
         | 1987 |  |  |     /* parse actual cmd line args */
 | 
      
         | 1988 |  |  |     for(i=1;i<argc;i++){
 | 
      
         | 1989 |  |  |         if(strcmp(argv[i],"--plasma")==0){
 | 
      
         | 1990 | 105 | ja_rd |             /* plasma simulation not supported, error*/
 | 
      
         | 1991 |  |  |             printf("Error: program compiled for compatibility to MIPS-I\n");
 | 
      
         | 1992 |  |  |             return 0;
 | 
      
         | 1993 |  |  |         }
 | 
      
         | 1994 |  |  |         else if(strcmp(argv[i],"--uclinux")==0){
 | 
      
         | 1995 | 166 | ja_rd |             args->memory_map = MAP_UCLINUX_BRAM;
 | 
      
         | 1996 | 105 | ja_rd |             /* FIXME selecting uClinux enables unaligned L/S emulation */
 | 
      
         | 1997 |  |  |             args->do_unaligned = 1;
 | 
      
         | 1998 | 61 | ja_rd |         }
 | 
      
         | 1999 | 108 | ja_rd |         else if(strcmp(argv[i],"--small")==0){
 | 
      
         | 2000 |  |  |             args->memory_map = MAP_SMALL;
 | 
      
         | 2001 |  |  |         }
 | 
      
         | 2002 | 105 | ja_rd |         else if(strcmp(argv[i],"--unaligned")==0){
 | 
      
         | 2003 |  |  |             args->do_unaligned = 1;
 | 
      
         | 2004 |  |  |         }
 | 
      
         | 2005 |  |  |         else if(strcmp(argv[i],"--noprompt")==0){
 | 
      
         | 2006 |  |  |             args->no_prompt = 1;
 | 
      
         | 2007 |  |  |         }
 | 
      
         | 2008 | 163 | ja_rd |         else if(strcmp(argv[i],"--notrap10")==0){
 | 
      
         | 2009 |  |  |             args->trap_on_reserved = 0;
 | 
      
         | 2010 |  |  |         }
 | 
      
         | 2011 | 166 | ja_rd |         else if(strcmp(argv[i],"--nomips32")==0){
 | 
      
         | 2012 |  |  |             args->emulate_some_mips32 = 0;
 | 
      
         | 2013 |  |  |         }
 | 
      
         | 2014 | 61 | ja_rd |         else if(strncmp(argv[i],"--bram=", strlen("--bram="))==0){
 | 
      
         | 2015 |  |  |             args->bin_filename[0] = &(argv[i][strlen("--bram=")]);
 | 
      
         | 2016 |  |  |         }
 | 
      
         | 2017 |  |  |         else if(strncmp(argv[i],"--flash=", strlen("--flash="))==0){
 | 
      
         | 2018 | 105 | ja_rd |             args->bin_filename[3] = &(argv[i][strlen("--flash=")]);
 | 
      
         | 2019 | 61 | ja_rd |         }
 | 
      
         | 2020 |  |  |         else if(strncmp(argv[i],"--xram=", strlen("--xram="))==0){
 | 
      
         | 2021 |  |  |             args->bin_filename[1] = &(argv[i][strlen("--xram=")]);
 | 
      
         | 2022 |  |  |         }
 | 
      
         | 2023 | 166 | ja_rd |         else if(strncmp(argv[i],"--map=", strlen("--map="))==0){
 | 
      
         | 2024 |  |  |             args->map_filename = &(argv[i][strlen("--map=")]);
 | 
      
         | 2025 |  |  |         }
 | 
      
         | 2026 |  |  |         else if(strncmp(argv[i],"--trace_log=", strlen("--trace_log="))==0){
 | 
      
         | 2027 |  |  |             map_info.log_filename = &(argv[i][strlen("--trace_log=")]);
 | 
      
         | 2028 |  |  |         }
 | 
      
         | 2029 | 163 | ja_rd |         else if(strncmp(argv[i],"--start=", strlen("--start="))==0){
 | 
      
         | 2030 |  |  |             sscanf(&(argv[i][strlen("--start=")]), "%x", &(args->start_addr));
 | 
      
         | 2031 |  |  |         }
 | 
      
         | 2032 | 105 | ja_rd |         else if(strncmp(argv[i],"--kernel=", strlen("--kernel="))==0){
 | 
      
         | 2033 |  |  |             args->bin_filename[1] = &(argv[i][strlen("--kernel=")]);
 | 
      
         | 2034 |  |  |             /* FIXME uClinux kernel 'offset' hardcoded */
 | 
      
         | 2035 |  |  |             args->offset[1] = 0x2000;
 | 
      
         | 2036 |  |  |         }
 | 
      
         | 2037 | 93 | ja_rd |         else if(strncmp(argv[i],"--trigger=", strlen("--trigger="))==0){
 | 
      
         | 2038 |  |  |             sscanf(&(argv[i][strlen("--trigger=")]), "%x", &(args->log_trigger_address));
 | 
      
         | 2039 |  |  |         }
 | 
      
         | 2040 | 163 | ja_rd |         else if(strncmp(argv[i],"--break=", strlen("--break="))==0){
 | 
      
         | 2041 |  |  |             sscanf(&(argv[i][strlen("--break=")]), "%x", &(args->breakpoint));
 | 
      
         | 2042 |  |  |         }
 | 
      
         | 2043 | 105 | ja_rd |         else if(strncmp(argv[i],"--breakpoint=", strlen("--breakpoint="))==0){
 | 
      
         | 2044 |  |  |             sscanf(&(argv[i][strlen("--breakpoint=")]), "%x", &(args->breakpoint));
 | 
      
         | 2045 |  |  |         }
 | 
      
         | 2046 | 61 | ja_rd |         else if((strcmp(argv[i],"--help")==0)||(strcmp(argv[i],"-h")==0)){
 | 
      
         | 2047 |  |  |             usage();
 | 
      
         | 2048 |  |  |             return 0;
 | 
      
         | 2049 |  |  |         }
 | 
      
         | 2050 |  |  |         else{
 | 
      
         | 2051 |  |  |             printf("unknown argument '%s'\n\n",argv[i]);
 | 
      
         | 2052 |  |  |             usage();
 | 
      
         | 2053 |  |  |             return 0;
 | 
      
         | 2054 |  |  |         }
 | 
      
         | 2055 |  |  |     }
 | 
      
         | 2056 |  |  |  
 | 
      
         | 2057 |  |  |     return 1;
 | 
      
         | 2058 |  |  | }
 | 
      
         | 2059 |  |  |  
 | 
      
         | 2060 |  |  | void usage(void){
 | 
      
         | 2061 |  |  |     printf("Usage:");
 | 
      
         | 2062 |  |  |     printf("    slite file.exe [arguments]\n");
 | 
      
         | 2063 |  |  |     printf("Arguments:\n");
 | 
      
         | 2064 |  |  |     printf("--bram=<file name>      : BRAM initialization file\n");
 | 
      
         | 2065 |  |  |     printf("--xram=<file name>      : XRAM initialization file\n");
 | 
      
         | 2066 | 105 | ja_rd |     printf("--kernel=<file name>    : XRAM initialization file for uClinux kernel\n");
 | 
      
         | 2067 |  |  |     printf("                          (loads at block offset 0x2000)\n");
 | 
      
         | 2068 | 61 | ja_rd |     printf("--flash=<file name>     : FLASH initialization file\n");
 | 
      
         | 2069 | 166 | ja_rd |     printf("--map=<file name>       : Map file to be used for tracing, if any\n");
 | 
      
         | 2070 |  |  |     printf("--trace_log=<file name> : Log file used for tracing, if any\n");
 | 
      
         | 2071 | 93 | ja_rd |     printf("--trigger=<hex number>  : Log trigger address\n");
 | 
      
         | 2072 | 163 | ja_rd |     printf("--break=<hex number>    : Breakpoint address\n");
 | 
      
         | 2073 |  |  |     printf("--start=<hex number>    : Start here instead of at reset vector\n");
 | 
      
         | 2074 |  |  |     printf("--notrap10              : Reserverd opcodes are NOPs and don't trap\n");
 | 
      
         | 2075 | 166 | ja_rd |     printf("--nomips32              : Do not emulate any mips32 opcodes\n");
 | 
      
         | 2076 | 61 | ja_rd |     printf("--plasma                : Simulate Plasma instead of MIPS-I\n");
 | 
      
         | 2077 | 105 | ja_rd |     printf("--uclinux               : Use memory map tailored to uClinux\n");
 | 
      
         | 2078 |  |  |     printf("--unaligned             : Implement unaligned load/store instructions\n");
 | 
      
         | 2079 |  |  |     printf("--noprompt              : Run in batch mode\n");
 | 
      
         | 2080 |  |  |     printf("--stop_at_zero          : Stop simulation when fetching from address 0x0\n");
 | 
      
         | 2081 | 61 | ja_rd |     printf("--help, -h              : Show this usage text\n");
 | 
      
         | 2082 |  |  | }
 | 
      
         | 2083 | 105 | ja_rd |  
 |