OpenCores
URL https://opencores.org/ocsvn/ion/ion/trunk

Subversion Repositories ion

[/] [ion/] [trunk/] [tools/] [slite/] [src/] [slite.c] - Blame information for rev 147

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 2 ja_rd
/*------------------------------------------------------------------------------
2
* slite.c -- MIPS-I simulator based on Steve Rhoad's "mlite"
3
*
4
* This is a slightly modified version of Steve Rhoad's "mlite" simulator, which
5
* is part of his PLASMA project (original date: 1/31/01).
6
*
7
*-------------------------------------------------------------------------------
8
* Usage:
9
*     slite <code file name> <data file name>
10
*
11
* The program will allocate a chunk of RAM (MEM_SIZE bytes) and map it to
12
* address 0x00000000 of the simulated CPU.
13
* Then it will read the 'code file' (as a big-endian plain binary) onto address
14
* 0x0 of the simulated CPU memory, and 'data file' on address 0x10000.
15
* Finally, will reset the CPU and enter the interactive debugger.
16
*
17
* (Note that the above is only necessary if the system does not have caches,
18
* because of the Harvard architecture. With caches in place, program loading
19
* would be antirely conventional).
20
*
21
* A simulation log file will be dumped to file "sw_sim_log.txt". This log can be
22
* used to compare with an equivalent log dumped by the hardware simulation, as
23
* a simple way to validate the hardware for a given program. See the project
24
* readme files for details.
25
*
26
*-------------------------------------------------------------------------------
27
* KNOWN BUGS:
28
*
29
*-------------------------------------------------------------------------------
30
* @date 2011-jan-16
31
*
32
*-------------------------------------------------------------------------------
33
* COPYRIGHT:    Software placed into the public domain by the author.
34
*               Software 'as is' without warranty.  Author liable for nothing.
35
*
36
* IMPORTANT: Assumes host is little endian.
37
*-----------------------------------------------------------------------------*/
38
 
39
#include <stdio.h>
40 11 ja_rd
#include <stdlib.h>
41
#include <stdint.h>
42 2 ja_rd
#include <string.h>
43
#include <ctype.h>
44
#include <assert.h>
45
 
46 31 ja_rd
/** Set to !=0 to disable file logging (much faster simulation) */
47 2 ja_rd
#define FILE_LOGGING_DISABLED (0)
48
/** Define to enable cache simulation (unimplemented) */
49
//#define ENABLE_CACHE
50 31 ja_rd
 
51
 
52
/*---- Definition of simulated system parameters -----------------------------*/
53
 
54 61 ja_rd
#define VECTOR_RESET (0xbfc00000)
55
#define VECTOR_TRAP  (0xbfc00180)
56
 
57
/** Definition of a memory block */
58 31 ja_rd
typedef struct s_block {
59
    uint32_t start;
60
    uint32_t size;
61 44 ja_rd
    uint32_t mask;
62 61 ja_rd
    uint32_t read_only;
63 31 ja_rd
    uint8_t  *mem;
64 61 ja_rd
    char     *area_name;
65 31 ja_rd
} t_block;
66 105 ja_rd
 
67
#define NUM_MEM_BLOCKS      (4)
68 108 ja_rd
#define NUM_MEM_MAPS        (3)
69 105 ja_rd
 
70
/** Definition of a memory map */
71
/* FIXME i/o addresses missing, hardcoded */
72
typedef struct s_map {
73
    t_block blocks[NUM_MEM_BLOCKS];
74
} t_map;
75
 
76 31 ja_rd
 
77
 
78 61 ja_rd
/*  Here's where we define the memory areas (blocks) of the system.
79
 
80
    The blocks should be defined in this order: BRAM, XRAM, FLASH
81
 
82
    BRAM is FPGA block ram initialized with bootstrap code
83
    XRAM is external SRAM
84
    FLASH is external flash
85
 
86
    Give any area a size of 0x0 to leave it unused.
87
 
88
    When a binary file is specified in the cmd line for one of these areas, it
89
    will be used to initialize it, checking bounds.
90
 
91
    Memory decoding is done in the order the blocks are defined; the address
92
    is anded with field .mask and then compared to field .start. If they match
93
    the address modulo the field .size is used to index the memory block, giving
94
    a 'mirror' effect. All of this simulates how the actual hardware works.
95
    Make sure the blocks don't overlap or the scheme will fail.
96 44 ja_rd
*/
97 31 ja_rd
 
98 105 ja_rd
#define MAP_DEFAULT (0)
99 108 ja_rd
#define MAP_UCLINUX (1)
100
#define MAP_SMALL   (2)
101 105 ja_rd
 
102
t_map memory_maps[NUM_MEM_MAPS] = {
103
    {/* Experimental memory map (default) */
104
        {/* Bootstrap BRAM, read only */
105
        {VECTOR_RESET,  0x00004800, 0xf8000000, 1, NULL, "Boot BRAM"},
106
        /* main external ram block  */
107
        {0x00000000,    0x00080000, 0xf8000000, 0, NULL, "XRAM0"},
108
        /* main external ram block  */
109
        {0x80000000,    0x00080000, 0xf8000000, 0, NULL, "XRAM1"},
110
        /* external flash block */
111
        {0xb0000000,    0x00040000, 0xf8000000, 0, NULL, "Flash"},
112
        }
113
    },
114
 
115
    {/* uClinux memory map */
116
        {/* Bootstrap BRAM, read only */
117
        {VECTOR_RESET,  0x00001000, 0xf8000000, 1, NULL, "Boot BRAM"},
118
        /* main external ram block  */
119
        {0x80000000,    0x00200000, 0xf8000000, 0, NULL, "XRAM0"},
120
        {0x00000000,    0x00400000, 0xf8000000, 0, NULL, "XRAM1"},
121
        /* external flash block */
122
        {0xb0000000,    0x00100000, 0xf8000000, 0, NULL, "Flash"},
123
        }
124 108 ja_rd
    },
125
 
126
    {/* Experimental memory map with small XRAM */
127
        {/* Bootstrap BRAM, read only */
128
        {VECTOR_RESET,  0x00004800, 0xf8000000, 1, NULL, "Boot BRAM"},
129
        /* main external ram block  */
130
        {0x00000000,    0x00001000, 0xf8000000, 0, NULL, "XRAM0"},
131
        /* main external ram block  */
132
        {0x80000000,    0x00001000, 0xf8000000, 0, NULL, "XRAM1"},
133
        /* external flash block */
134
        {0xb0000000,    0x00040000, 0xf8000000, 0, NULL, "Flash"},
135
        }
136 105 ja_rd
    },
137 31 ja_rd
};
138 105 ja_rd
 
139 31 ja_rd
 
140 61 ja_rd
/*---- end of system parameters ----------------------------------------------*/
141
 
142
 
143
/** Values for the command line arguments */
144
typedef struct s_args {
145 105 ja_rd
    /** memory map to be used */
146
    uint32_t memory_map;
147
    /** implement unaligned load/stores (don't just trap them) */
148
    uint32_t do_unaligned;
149
    /** start simulation without showing monitor prompt and quit on
150
        end condition -- useful for batch runs */
151
    uint32_t no_prompt;
152
    /** breakpoint address (0xffffffff if unused) */
153
    uint32_t breakpoint;
154
    /** a code fetch from this address starts logging */
155 93 ja_rd
    uint32_t log_trigger_address;
156 105 ja_rd
    /** full name of log file */
157 93 ja_rd
    char *log_file_name;
158 105 ja_rd
    /** bin file to load to each area or null */
159
    char *bin_filename[NUM_MEM_BLOCKS];
160
    /** offset into area (in bytes) where bin wile will be loaded */
161
    uint32_t offset[NUM_MEM_BLOCKS];
162 61 ja_rd
} t_args;
163
/** Parse cmd line args globally accessible */
164
t_args cmd_line_args;
165
 
166
 
167
/*---- Endianess conversion macros -------------------------------------------*/
168 2 ja_rd
 
169
#define ntohs(A) ( ((A)>>8) | (((A)&0xff)<<8) )
170
#define htons(A) ntohs(A)
171
#define ntohl(A) ( ((A)>>24) | (((A)&0xff0000)>>8) | (((A)&0xff00)<<8) | ((A)<<24) )
172
#define htonl(A) ntohl(A)
173
 
174
/*---- OS-dependent support functions and definitions ------------------------*/
175
#ifndef WIN32
176
//Support for Linux
177
#define putch putchar
178
#include <termios.h>
179
#include <unistd.h>
180
 
181 31 ja_rd
void slite_sleep(unsigned int value){
182
    usleep(value * 1000);
183 2 ja_rd
}
184
 
185 31 ja_rd
int kbhit(void){
186
    struct termios oldt, newt;
187
    struct timeval tv;
188
    fd_set read_fd;
189 2 ja_rd
 
190 31 ja_rd
    tcgetattr(STDIN_FILENO, &oldt);
191
    newt = oldt;
192
    newt.c_lflag &= ~(ICANON | ECHO);
193
    tcsetattr(STDIN_FILENO, TCSANOW, &newt);
194
    tv.tv_sec=0;
195
    tv.tv_usec=0;
196
    FD_ZERO(&read_fd);
197
    FD_SET(0,&read_fd);
198
    if(select(1, &read_fd, NULL, NULL, &tv) == -1){
199
        return 0;
200
    }
201
    //tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
202
    if(FD_ISSET(0,&read_fd)){
203
        return 1;
204
    }
205
    return 0;
206 2 ja_rd
}
207
 
208 31 ja_rd
int getch(void){
209
    struct termios oldt, newt;
210
    int ch;
211 2 ja_rd
 
212 31 ja_rd
    tcgetattr(STDIN_FILENO, &oldt);
213
    newt = oldt;
214
    newt.c_lflag &= ~(ICANON | ECHO);
215
    tcsetattr(STDIN_FILENO, TCSANOW, &newt);
216
    ch = getchar();
217
    //tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
218
    return ch;
219 2 ja_rd
}
220
#else
221
//Support for Windows
222
#include <conio.h>
223 31 ja_rd
extern void __stdcall Sleep(unsigned long value);
224
 
225
void slite_sleep(unsigned int value){
226
    Sleep(value);
227
}
228
 
229 2 ja_rd
#endif
230
/*---- End of OS-dependent support functions and definitions -----------------*/
231
 
232
/*---- Hardware system parameters --------------------------------------------*/
233
 
234
/* Much of this is a remnant from Plasma's mlite and is  no longer used. */
235
/* FIXME Refactor HW system params */
236
 
237 105 ja_rd
#define DBG_REGS          (0x20010000)
238
 
239 2 ja_rd
#define UART_WRITE        0x20000000
240
#define UART_READ         0x20000000
241
#define IRQ_MASK          0x20000010
242
#define IRQ_STATUS        0x20000020
243
#define CONFIG_REG        0x20000070
244
#define MMU_PROCESS_ID    0x20000080
245
#define MMU_FAULT_ADDR    0x20000090
246
#define MMU_TLB           0x200000a0
247
 
248
#define IRQ_UART_READ_AVAILABLE  0x001
249
#define IRQ_UART_WRITE_AVAILABLE 0x002
250
#define IRQ_COUNTER18_NOT        0x004
251
#define IRQ_COUNTER18            0x008
252
#define IRQ_MMU                  0x200
253
 
254 5 ja_rd
/*----------------------------------------------------------------------------*/
255 2 ja_rd
 
256 5 ja_rd
/* These are flags that will be used to notify the main cycle function of any
257
   failed assertions in its subfunctions. */
258
#define ASRT_UNALIGNED_READ         (1<<0)
259
#define ASRT_UNALIGNED_WRITE        (1<<1)
260
 
261
char *assertion_messages[2] = {
262
   "Unaligned read",
263
   "Unaligned write"
264
};
265
 
266
 
267 2 ja_rd
/** Length of debugging jump target queue */
268
#define TRACE_BUFFER_SIZE (32)
269
 
270 31 ja_rd
typedef struct s_trace {
271 2 ja_rd
   unsigned int buf[TRACE_BUFFER_SIZE];   /**< queue of last jump targets */
272
   unsigned int next;                     /**< internal queue head pointer */
273
   FILE *log;                             /**< text log file or NULL */
274 93 ja_rd
   int log_triggered;                     /**< !=0 if log has been triggered */
275
   uint32_t log_trigger_address;          /**< */
276 2 ja_rd
   int pr[32];                            /**< last value of register bank */
277
   int hi, lo, epc;                       /**< last value of internal regs */
278 31 ja_rd
} t_trace;
279 2 ja_rd
 
280 31 ja_rd
typedef struct s_state {
281 5 ja_rd
   unsigned failed_assertions;            /**< assertion bitmap */
282
   unsigned faulty_address;               /**< addr that failed assertion */
283 105 ja_rd
   uint32_t do_unaligned;                 /**< !=0 to enable unaligned L/S */
284
   uint32_t breakpoint;                   /**< BP address of 0xffffffff */
285 27 ja_rd
 
286
   int delay_slot;              /**< !=0 if prev. instruction was a branch */
287 5 ja_rd
 
288 2 ja_rd
   int r[32];
289
   int opcode;
290 53 ja_rd
   int pc, pc_next, epc;
291
   uint32_t op_addr;            /**< address of opcode being simulated */
292 2 ja_rd
   unsigned int hi;
293
   unsigned int lo;
294 27 ja_rd
   int status;
295
   unsigned cp0_cause;
296 2 ja_rd
   int userMode;
297
   int processId;
298 53 ja_rd
   int exceptionId;             /**< DEPRECATED, to be removed */
299 2 ja_rd
   int faultAddr;
300
   int irqStatus;
301
   int skip;
302 31 ja_rd
   t_trace t;
303
   //unsigned char *mem;
304
   t_block blocks[NUM_MEM_BLOCKS];
305 2 ja_rd
   int wakeup;
306
   int big_endian;
307 31 ja_rd
} t_state;
308 2 ja_rd
 
309
static char *opcode_string[]={
310
   "SPECIAL","REGIMM","J","JAL","BEQ","BNE","BLEZ","BGTZ",
311
   "ADDI","ADDIU","SLTI","SLTIU","ANDI","ORI","XORI","LUI",
312
   "COP0","COP1","COP2","COP3","BEQL","BNEL","BLEZL","BGTZL",
313
   "?","?","?","?","?","?","?","?",
314
   "LB","LH","LWL","LW","LBU","LHU","LWR","?",
315
   "SB","SH","SWL","SW","?","?","SWR","CACHE",
316
   "LL","LWC1","LWC2","LWC3","?","LDC1","LDC2","LDC3"
317
   "SC","SWC1","SWC2","SWC3","?","SDC1","SDC2","SDC3"
318
};
319
 
320
static char *special_string[]={
321
   "SLL","?","SRL","SRA","SLLV","?","SRLV","SRAV",
322
   "JR","JALR","MOVZ","MOVN","SYSCALL","BREAK","?","SYNC",
323
   "MFHI","MTHI","MFLO","MTLO","?","?","?","?",
324
   "MULT","MULTU","DIV","DIVU","?","?","?","?",
325
   "ADD","ADDU","SUB","SUBU","AND","OR","XOR","NOR",
326
   "?","?","SLT","SLTU","?","DADDU","?","?",
327
   "TGE","TGEU","TLT","TLTU","TEQ","?","TNE","?",
328
   "?","?","?","?","?","?","?","?"
329
};
330
 
331
static char *regimm_string[]={
332
   "BLTZ","BGEZ","BLTZL","BGEZL","?","?","?","?",
333
   "TGEI","TGEIU","TLTI","TLTIU","TEQI","?","TNEI","?",
334
   "BLTZAL","BEQZAL","BLTZALL","BGEZALL","?","?","?","?",
335
   "?","?","?","?","?","?","?","?"
336
};
337
 
338
static unsigned int HWMemory[8];
339
 
340
/*---- Local function prototypes ---------------------------------------------*/
341
 
342
/* Debug and logging */
343 93 ja_rd
void init_trace_buffer(t_state *s, t_args *args);
344 31 ja_rd
void close_trace_buffer(t_state *s);
345
void dump_trace_buffer(t_state *s);
346
void log_cycle(t_state *s);
347
void log_read(t_state *s, int full_address, int word_value, int size, int log);
348
void log_failed_assertions(t_state *s);
349 93 ja_rd
uint32_t log_enabled(t_state *s);
350
void trigger_log(t_state *s);
351 2 ja_rd
 
352 61 ja_rd
int32_t parse_cmd_line(uint32_t argc, char **argv, t_args *args);
353
void usage(void);
354
 
355 31 ja_rd
/* CPU model */
356
void free_cpu(t_state *s);
357 105 ja_rd
int init_cpu(t_state *s, t_args *args);
358
void reset_cpu(t_state *s);
359
void unimplemented(t_state *s, const char *txt);
360
void reverse_endianess(uint8_t *data, uint32_t bytes);
361 31 ja_rd
 
362 2 ja_rd
/* Hardware simulation */
363 31 ja_rd
int mem_read(t_state *s, int size, unsigned int address, int log);
364
void mem_write(t_state *s, int size, unsigned address, unsigned value, int log);
365 53 ja_rd
void start_load(t_state *s, uint32_t addr, int rt, int data);
366 2 ja_rd
 
367 16 ja_rd
 
368 2 ja_rd
/*---- Local functions -------------------------------------------------------*/
369
 
370
/** Log to file a memory read operation (not including target reg change) */
371 31 ja_rd
void log_read(t_state *s, int full_address, int word_value, int size, int log){
372 147 ja_rd
    /* if bit CP0.16==1, this is a D-Cache line invalidation access and
373
           the HW will not read any actual data, so skip the log (@note1) */
374
    if(log_enabled(s) && log!=0 && !(s->status & 0x00010000)){
375 53 ja_rd
        fprintf(s->t.log, "(%08X) [%08X] <**>=%08X RD\n",
376
              s->op_addr, full_address, word_value);
377
    }
378 2 ja_rd
}
379
 
380
/** Read memory, optionally logging */
381 31 ja_rd
int mem_read(t_state *s, int size, unsigned int address, int log){
382
    unsigned int value=0, word_value=0, i, ptr;
383
    unsigned int full_address = address;
384 2 ja_rd
 
385 31 ja_rd
    s->irqStatus |= IRQ_UART_WRITE_AVAILABLE;
386
    switch(address){
387
    case UART_READ:
388
        /* FIXME Take input from text file */
389 93 ja_rd
        while(!kbhit());
390
        HWMemory[0] = getch();
391
        //s->irqStatus &= ~IRQ_UART_READ_AVAILABLE; //clear bit
392
        printf("%c", HWMemory[0]);
393
        return (HWMemory[0] << 24) | 0x03;
394 31 ja_rd
    case IRQ_MASK:
395
       return HWMemory[1];
396
    case IRQ_MASK + 4:
397
       slite_sleep(10);
398
       return 0;
399
    case IRQ_STATUS:
400
       /*if(kbhit())
401
          s->irqStatus |= IRQ_UART_READ_AVAILABLE;
402
       return s->irqStatus;
403
       */
404
       /* FIXME Optionally simulate UART TX delay */
405
       word_value = 0x00000003; /* Ready to TX and RX */
406 53 ja_rd
       //log_read(s, full_address, word_value, size, log);
407 31 ja_rd
       return word_value;
408
    case MMU_PROCESS_ID:
409
       return s->processId;
410
    case MMU_FAULT_ADDR:
411
       return s->faultAddr;
412
    }
413
 
414
    /* point ptr to the byte in the block, or NULL is the address is unmapped */
415
    ptr = 0;
416
    for(i=0;i<NUM_MEM_BLOCKS;i++){
417 61 ja_rd
        if((address & s->blocks[i].mask) ==
418
           (s->blocks[i].start & s->blocks[i].mask)){
419 44 ja_rd
            ptr = (unsigned)(s->blocks[i].mem) +
420
                  ((address - s->blocks[i].start) % s->blocks[i].size);
421 31 ja_rd
            break;
422
        }
423
    }
424
    if(!ptr){
425
        /* address out of mapped blocks: log and return zero */
426 147 ja_rd
        /* if bit CP0.16==1, this is a D-Cache line invalidation access and
427
           the HW will not read any actual data, so skip the log (@note1) */
428
        if(log_enabled(s) && log!=0 && !(s->status & (1<<16))){
429 31 ja_rd
            fprintf(s->t.log, "(%08X) [%08X] <**>=%08X RD UNMAPPED\n",
430
                s->pc, full_address, 0);
431
        }
432
        return 0;
433
    }
434
 
435
    /* get the whole word */
436
    word_value = *(int*)(ptr&0xfffffffc);
437
    if(s->big_endian){
438
        word_value = ntohl(word_value);
439
    }
440 2 ja_rd
 
441 31 ja_rd
    switch(size){
442
    case 4:
443
        if(address & 3){
444 2 ja_rd
            printf("Unaligned access PC=0x%x address=0x%x\n",
445 31 ja_rd
                (int)s->pc, (int)address);
446
        }
447
        if((address & 3) != 0){
448
            /* unaligned word, log fault */
449 5 ja_rd
            s->failed_assertions |= ASRT_UNALIGNED_READ;
450
            s->faulty_address = address;
451
            address = address & 0xfffffffc;
452 31 ja_rd
        }
453
        value = *(int*)ptr;
454
        if(s->big_endian){
455
            value = ntohl(value);
456
        }
457
        break;
458
    case 2:
459
        if((address & 1) != 0){
460
            /* unaligned halfword, log fault */
461 5 ja_rd
            s->failed_assertions |= ASRT_UNALIGNED_READ;
462
            s->faulty_address = address;
463
            address = address & 0xfffffffe;
464 31 ja_rd
        }
465
        value = *(unsigned short*)ptr;
466
        if(s->big_endian){
467
            value = ntohs((unsigned short)value);
468
        }
469
        break;
470
    case 1:
471
        value = *(unsigned char*)ptr;
472
        break;
473
    default:
474
        /* FIXME this is a bug, should quit */
475
        printf("ERROR");
476
    }
477 2 ja_rd
 
478 53 ja_rd
    //log_read(s, full_address, value, size, log);
479 31 ja_rd
    return(value);
480 2 ja_rd
}
481
 
482
/** Write memory */
483 31 ja_rd
void mem_write(t_state *s, int size, unsigned address, unsigned value, int log){
484
    unsigned int i, ptr, mask, dvalue, b0, b1, b2, b3;
485 2 ja_rd
 
486 93 ja_rd
    if(log_enabled(s)){
487 31 ja_rd
        b0 = value & 0x000000ff;
488
        b1 = value & 0x0000ff00;
489
        b2 = value & 0x00ff0000;
490
        b3 = value & 0xff000000;
491 2 ja_rd
 
492 31 ja_rd
        switch(size){
493
        case 4:  mask = 0x0f;
494
            dvalue = value;
495
            break;
496
        case 2:
497
            if((address&0x2)==0){
498
                mask = 0xc;
499
                dvalue = b1<<16 | b0<<16;
500
            }
501
            else{
502
               mask = 0x3;
503
               dvalue = b1 | b0;
504
            }
505
            break;
506
        case 1:
507
            switch(address%4){
508
            case 0 : mask = 0x8;
509
                dvalue = b0<<24;
510
                break;
511
            case 1 : mask = 0x4;
512
                dvalue = b0<<16;
513
                break;
514
            case 2 : mask = 0x2;
515
                dvalue = b0<<8;
516
                break;
517
            case 3 : mask = 0x1;
518
                dvalue = b0;
519
                break;
520
            }
521
            break;
522
        default:
523 2 ja_rd
            printf("BUG: mem write size invalid (%08x)\n", s->pc);
524
            exit(2);
525 31 ja_rd
        }
526 2 ja_rd
 
527 31 ja_rd
        fprintf(s->t.log, "(%08X) [%08X] |%02X|=%08X WR\n",
528 147 ja_rd
                //s->op_addr, address&0xfffffffc, mask, dvalue);
529
                s->op_addr, address, mask, dvalue);
530 31 ja_rd
    }
531 105 ja_rd
 
532
    if((address&0xffff0000)==DBG_REGS){
533
        printf("[%04x]=%08x\n", address & 0xffff, value);
534
    }
535 2 ja_rd
 
536 31 ja_rd
    switch(address){
537
    case UART_WRITE:
538
        putch(value);
539
        fflush(stdout);
540
        return;
541
    case IRQ_MASK:
542
        HWMemory[1] = value;
543
        return;
544
    case IRQ_STATUS:
545
        s->irqStatus = value;
546
        return;
547
    case CONFIG_REG:
548
        return;
549
    case MMU_PROCESS_ID:
550
        //printf("processId=%d\n", value);
551
        s->processId = value;
552
        return;
553
    }
554 2 ja_rd
 
555 31 ja_rd
    ptr = 0;
556
    for(i=0;i<NUM_MEM_BLOCKS;i++){
557 61 ja_rd
        if((address & s->blocks[i].mask) ==
558
                  (s->blocks[i].start & s->blocks[i].mask)){
559 44 ja_rd
            ptr = (unsigned)(s->blocks[i].mem) +
560
                            ((address - s->blocks[i].start) % s->blocks[i].size);
561 61 ja_rd
 
562
            if(s->blocks[i].read_only){
563 93 ja_rd
                if(log_enabled(s) && log!=0){
564 61 ja_rd
                    fprintf(s->t.log, "(%08X) [%08X] |%02X|=%08X WR READ ONLY\n",
565
                    s->op_addr, address, mask, dvalue);
566
                    return;
567
                }
568
            }
569 31 ja_rd
            break;
570
        }
571
    }
572
    if(!ptr){
573
        /* address out of mapped blocks: log and return zero */
574 93 ja_rd
        if(log_enabled(s) && log!=0){
575 31 ja_rd
            fprintf(s->t.log, "(%08X) [%08X] |%02X|=%08X WR UNMAPPED\n",
576 53 ja_rd
                s->op_addr, address, mask, dvalue);
577 31 ja_rd
        }
578
        return;
579
    }
580 2 ja_rd
 
581 31 ja_rd
    switch(size){
582
    case 4:
583
        if((address & 3) != 0){
584
            /* unaligned word, log fault */
585 5 ja_rd
            s->failed_assertions |= ASRT_UNALIGNED_WRITE;
586
            s->faulty_address = address;
587
            address = address & (~0x03);
588 31 ja_rd
        }
589
        if(s->big_endian){
590
            value = htonl(value);
591
        }
592
        *(int*)ptr = value;
593
        break;
594
    case 2:
595
        if((address & 1) != 0){
596
            /* unaligned halfword, log fault */
597 5 ja_rd
            s->failed_assertions |= ASRT_UNALIGNED_WRITE;
598
            s->faulty_address = address;
599
            address = address & (~0x01);
600 31 ja_rd
        }
601
        if(s->big_endian){
602
            value = htons((unsigned short)value);
603
        }
604
        *(short*)ptr = (unsigned short)value;
605
        break;
606
    case 1:
607
        *(char*)ptr = (unsigned char)value;
608
        break;
609
    default:
610
        /* FIXME this is a bug, should quit */
611
        printf("ERROR");
612
    }
613 2 ja_rd
}
614
 
615 105 ja_rd
/*-- unaligned store and load instructions -----------------------------------*/
616
/*
617
 These are meant to be left unimplemented and trapped. These functions simulate
618
 the unaligned r/w instructions until proper trap handlers are written.
619
*/
620
 
621
void mem_swl(t_state *s, uint32_t address, uint32_t value, uint32_t log){
622
    uint32_t data, offset;
623
 
624
    if(!s->do_unaligned) return unimplemented(s, "SWL");
625
 
626
    offset = (address & 0x03);
627
    address = (address & (~0x03));
628
    data = value;
629
 
630
    while(offset<4){
631
        mem_write(s,1,address+offset,(data>>24) & 0xff,0);
632
        data = data << 8;
633
        offset++;
634
    }
635
}
636
 
637
void mem_swr(t_state *s, uint32_t address, uint32_t value, uint32_t log){
638
    uint32_t data, offset;
639
 
640
    if(!s->do_unaligned) return unimplemented(s, "SWR");
641
 
642
    offset = (address & 0x03);
643
    address = (address & (~0x03));
644
    data = value;
645
 
646
    while(offset>=0){
647
        mem_write(s,1,address+offset,data & 0xff,0);
648
        data = data >> 8;
649
        offset--;
650
    }
651
}
652
 
653
void mem_lwr(t_state *s, uint32_t address, uint32_t reg_index, uint32_t log){
654
    uint32_t offset, data;
655
    uint32_t disp[4] = {24,         16,         8,          0};
656
    uint32_t mask[4] = {0x000000ff, 0x0000ffff, 0x00ffffff, 0xffffffff};
657
 
658
    if(!s->do_unaligned) return unimplemented(s, "LWR");
659
 
660
    offset = (address & 0x03);
661
    address = (address & (~0x03));
662
 
663
    data = mem_read(s, 4, address, 0);
664
    data = (data >> disp[offset]) & mask[offset];
665
 
666
    s->r[reg_index] = (s->r[reg_index] & (~mask[offset])) | data;
667
}
668
 
669
void mem_lwl(t_state *s, uint32_t address, uint32_t reg_index, uint32_t log){
670
    uint32_t offset, data;
671
    uint32_t disp[4] = {0,          8,          16,         24};
672
    uint32_t mask[4] = {0xffffffff, 0xffffff00, 0xffff0000, 0xff000000};
673
 
674
    if(!s->do_unaligned) return unimplemented(s, "LWL");
675
 
676
    offset = (address & 0x03);
677
    address = (address & (~0x03));
678
 
679
    data = mem_read(s, 4, address, 0);
680
    data = (data << disp[offset]) & mask[offset];
681
 
682
    s->r[reg_index] = (s->r[reg_index] & (~mask[offset])) | data;
683
}
684
 
685
 
686 2 ja_rd
/*---- Optional MMU and cache implementation ---------------------------------*/
687
 
688
/*
689
   The actual core does not have a cache so all of the original Plasma mlite.c
690
   code for cache simulation has been removed.
691
*/
692
 
693
/*---- End optional cache implementation -------------------------------------*/
694
 
695
 
696
/** Simulates MIPS-I multiplier unsigned behavior*/
697
void mult_big(unsigned int a,
698
              unsigned int b,
699
              unsigned int *hi,
700 31 ja_rd
              unsigned int *lo){
701
    unsigned int ahi, alo, bhi, blo;
702
    unsigned int c0, c1, c2;
703
    unsigned int c1_a, c1_b;
704 2 ja_rd
 
705 31 ja_rd
    ahi = a >> 16;
706
    alo = a & 0xffff;
707
    bhi = b >> 16;
708
    blo = b & 0xffff;
709 2 ja_rd
 
710 31 ja_rd
    c0 = alo * blo;
711
    c1_a = ahi * blo;
712
    c1_b = alo * bhi;
713
    c2 = ahi * bhi;
714 2 ja_rd
 
715 31 ja_rd
    c2 += (c1_a >> 16) + (c1_b >> 16);
716
    c1 = (c1_a & 0xffff) + (c1_b & 0xffff) + (c0 >> 16);
717
    c2 += (c1 >> 16);
718
    c0 = (c1 << 16) + (c0 & 0xffff);
719
    *hi = c2;
720
    *lo = c0;
721 2 ja_rd
}
722
 
723
/** Simulates MIPS-I multiplier signed behavior*/
724
void mult_big_signed(int a,
725
                     int b,
726
                     unsigned int *hi,
727 31 ja_rd
                     unsigned int *lo){
728
    int64_t xa, xb, xr, temp;
729
    int32_t rh, rl;
730 11 ja_rd
 
731 31 ja_rd
    xa = a;
732
    xb = b;
733
    xr = xa * xb;
734 11 ja_rd
 
735 31 ja_rd
    temp = (xr >> 32) & 0xffffffff;
736
    rh = temp;
737
    temp = (xr >> 0) & 0xffffffff;
738
    rl = temp;
739 11 ja_rd
 
740 31 ja_rd
    *hi = rh;
741
    *lo = rl;
742 2 ja_rd
}
743
 
744
/** Load data from memory (used to simulate load delay slots) */
745 53 ja_rd
void start_load(t_state *s, uint32_t addr, int rt, int data){
746 31 ja_rd
    /* load delay slot not simulated */
747 53 ja_rd
    log_read(s, addr, data, 1, 1);
748 31 ja_rd
    s->r[rt] = data;
749 2 ja_rd
}
750
 
751
/** Execute one cycle of the CPU (including any interlock stall cycles) */
752 31 ja_rd
void cycle(t_state *s, int show_mode){
753
    unsigned int opcode;
754
    int delay_slot = 0; /* 1 of this instruction is a branch */
755
    unsigned int op, rs, rt, rd, re, func, imm, target;
756
    int trap_cause = 0;
757
    int imm_shift, branch=0, lbranch=2, skip2=0;
758
    int *r=s->r;
759
    unsigned int *u=(unsigned int*)s->r;
760
    unsigned int ptr, epc, rSave;
761 2 ja_rd
 
762 93 ja_rd
    /* fetch and decode instruction */
763 31 ja_rd
    opcode = mem_read(s, 4, s->pc, 0);
764
    op = (opcode >> 26) & 0x3f;
765
    rs = (opcode >> 21) & 0x1f;
766
    rt = (opcode >> 16) & 0x1f;
767
    rd = (opcode >> 11) & 0x1f;
768
    re = (opcode >> 6) & 0x1f;
769
    func = opcode & 0x3f;
770
    imm = opcode & 0xffff;
771
    imm_shift = (((int)(short)imm) << 2) - 4;
772
    target = (opcode << 6) >> 4;
773
    ptr = (short)imm + r[rs];
774
    r[0] = 0;
775
 
776 93 ja_rd
    /* Trigger log if we fetch from trigger address */
777
    if(s->pc == s->t.log_trigger_address){
778
        trigger_log(s);
779
    }
780
 
781 31 ja_rd
    /* if we are priting state to console, do it now */
782
    if(show_mode){
783
        printf("%8.8x %8.8x ", s->pc, opcode);
784
        if(op == 0){
785
            printf("%8s ", special_string[func]);
786
        }
787
        else if(op == 1){
788
            printf("%8s ", regimm_string[rt]);
789
        }
790
        else{
791
            printf("%8s ", opcode_string[op]);
792
        }
793 2 ja_rd
 
794 31 ja_rd
        printf("$%2.2d $%2.2d $%2.2d $%2.2d ", rs, rt, rd, re);
795
        printf("%4.4x", imm);
796
        if(show_mode == 1){
797
            printf(" r[%2.2d]=%8.8x r[%2.2d]=%8.8x", rs, r[rs], rt, r[rt]);
798
        }
799
        printf("\n");
800
    }
801
 
802
    /* if we're just showing state to console, quit and don't run instruction */
803
    if(show_mode > 5){
804
        return;
805
    }
806
 
807
    /* epc will point to the victim instruction, i.e. THIS instruction */
808
    epc = s->pc;
809 32 ja_rd
 
810
    /* If we catch a jump instruction jumping to itself, assume we hit the
811
       and of the program and quit. */
812
    if(s->pc == s->pc_next+4){
813
        printf("\n\nEndless loop at 0x%08x\n\n", s->pc-4);
814
        s->wakeup = 1;
815 53 ja_rd
    }
816
    s->op_addr = s->pc;
817 31 ja_rd
    s->pc = s->pc_next;
818
    s->pc_next = s->pc_next + 4;
819
    if(s->skip){
820
        s->skip = 0;
821
        return;
822
    }
823
    rSave = r[rt];
824
 
825
    switch(op){
826
    case 0x00:/*SPECIAL*/
827
        switch(func){
828
        case 0x00:/*SLL*/  r[rd]=r[rt]<<re;          break;
829
        case 0x02:/*SRL*/  r[rd]=u[rt]>>re;          break;
830
        case 0x03:/*SRA*/  r[rd]=r[rt]>>re;          break;
831
        case 0x04:/*SLLV*/ r[rd]=r[rt]<<r[rs];       break;
832
        case 0x06:/*SRLV*/ r[rd]=u[rt]>>r[rs];       break;
833
        case 0x07:/*SRAV*/ r[rd]=r[rt]>>r[rs];       break;
834
        case 0x08:/*JR*/   delay_slot=1;
835
                           s->pc_next=r[rs];         break;
836
        case 0x09:/*JALR*/ delay_slot=1;
837
                           r[rd]=s->pc_next;
838
                           s->pc_next=r[rs]; break;
839
        case 0x0a:/*MOVZ*/ if(!r[rt]) r[rd]=r[rs];   break;  /*IV*/
840
        case 0x0b:/*MOVN*/ if(r[rt]) r[rd]=r[rs];    break;  /*IV*/
841 147 ja_rd
        case 0x0c:/*SYSCALL*/ trap_cause = 8;
842
                              s->exceptionId=1;
843 105 ja_rd
                              /*
844
                              FIXME enable when running uClinux
845
                              printf("SYSCALL (%08x)\n", s->pc);
846
                              */
847
                              break;
848 147 ja_rd
        case 0x0d:/*BREAK*/   trap_cause = 9;
849
                              s->exceptionId=1;
850 105 ja_rd
                              /*
851
                              FIXME enable when running uClinux
852
                              printf("BREAK (%08x)\n", s->pc);
853
                              */
854
                              break;
855 31 ja_rd
        case 0x0f:/*SYNC*/ s->wakeup=1;              break;
856
        case 0x10:/*MFHI*/ r[rd]=s->hi;              break;
857
        case 0x11:/*FTHI*/ s->hi=r[rs];              break;
858
        case 0x12:/*MFLO*/ r[rd]=s->lo;              break;
859
        case 0x13:/*MTLO*/ s->lo=r[rs];              break;
860
        case 0x18:/*MULT*/ mult_big_signed(r[rs],r[rt],&s->hi,&s->lo); break;
861
        case 0x19:/*MULTU*/ mult_big(r[rs],r[rt],&s->hi,&s->lo); break;
862
        case 0x1a:/*DIV*/  s->lo=r[rs]/r[rt]; s->hi=r[rs]%r[rt]; break;
863
        case 0x1b:/*DIVU*/ s->lo=u[rs]/u[rt]; s->hi=u[rs]%u[rt]; break;
864
        case 0x20:/*ADD*/  r[rd]=r[rs]+r[rt];        break;
865
        case 0x21:/*ADDU*/ r[rd]=r[rs]+r[rt];        break;
866
        case 0x22:/*SUB*/  r[rd]=r[rs]-r[rt];        break;
867
        case 0x23:/*SUBU*/ r[rd]=r[rs]-r[rt];        break;
868
        case 0x24:/*AND*/  r[rd]=r[rs]&r[rt];        break;
869
        case 0x25:/*OR*/   r[rd]=r[rs]|r[rt];        break;
870
        case 0x26:/*XOR*/  r[rd]=r[rs]^r[rt];        break;
871
        case 0x27:/*NOR*/  r[rd]=~(r[rs]|r[rt]);     break;
872
        case 0x2a:/*SLT*/  r[rd]=r[rs]<r[rt];        break;
873
        case 0x2b:/*SLTU*/ r[rd]=u[rs]<u[rt];        break;
874
        case 0x2d:/*DADDU*/r[rd]=r[rs]+u[rt];        break;
875
        case 0x31:/*TGEU*/ break;
876
        case 0x32:/*TLT*/  break;
877
        case 0x33:/*TLTU*/ break;
878
        case 0x34:/*TEQ*/  break;
879
        case 0x36:/*TNE*/  break;
880
        default: printf("ERROR0(*0x%x~0x%x)\n", s->pc, opcode);
881
           s->wakeup=1;
882
        }
883
        break;
884
    case 0x01:/*REGIMM*/
885
        switch(rt){
886 2 ja_rd
            case 0x10:/*BLTZAL*/ r[31]=s->pc_next;
887
            case 0x00:/*BLTZ*/   branch=r[rs]<0;    break;
888
            case 0x11:/*BGEZAL*/ r[31]=s->pc_next;
889
            case 0x01:/*BGEZ*/   branch=r[rs]>=0;   break;
890
            case 0x12:/*BLTZALL*/r[31]=s->pc_next;
891
            case 0x02:/*BLTZL*/  lbranch=r[rs]<0;   break;
892
            case 0x13:/*BGEZALL*/r[31]=s->pc_next;
893
            case 0x03:/*BGEZL*/  lbranch=r[rs]>=0;  break;
894
            default: printf("ERROR1\n"); s->wakeup=1;
895 31 ja_rd
        }
896
        break;
897
    case 0x03:/*JAL*/    r[31]=s->pc_next;
898
    case 0x02:/*J*/      delay_slot=1;
899
                       s->pc_next=(s->pc&0xf0000000)|target; break;
900
    case 0x04:/*BEQ*/    branch=r[rs]==r[rt];     break;
901
    case 0x05:/*BNE*/    branch=r[rs]!=r[rt];     break;
902
    case 0x06:/*BLEZ*/   branch=r[rs]<=0;         break;
903
    case 0x07:/*BGTZ*/   branch=r[rs]>0;          break;
904
    case 0x08:/*ADDI*/   r[rt]=r[rs]+(short)imm;  break;
905
    case 0x09:/*ADDIU*/  u[rt]=u[rs]+(short)imm;  break;
906
    case 0x0a:/*SLTI*/   r[rt]=r[rs]<(short)imm;  break;
907
    case 0x0b:/*SLTIU*/  u[rt]=u[rs]<(unsigned int)(short)imm; break;
908
    case 0x0c:/*ANDI*/   r[rt]=r[rs]&imm;         break;
909
    case 0x0d:/*ORI*/    r[rt]=r[rs]|imm;         break;
910
    case 0x0e:/*XORI*/   r[rt]=r[rs]^imm;         break;
911
    case 0x0f:/*LUI*/    r[rt]=(imm<<16);         break;
912
    case 0x10:/*COP0*/
913 105 ja_rd
        if((opcode & (1<<23)) == 0){  //move from CP0 (mfc0)
914
            switch(rd){
915 147 ja_rd
                case 12: r[rt]=s->status & 0xffff; break;
916 105 ja_rd
                case 13: r[rt]=s->cp0_cause; break;
917
                case 14: r[rt]=s->epc; break;
918
                case 15: r[rt]=0x00000200; break;
919
                default:
920
                    //printf("mfco [%02d]\n", rd);
921
                    break;
922 27 ja_rd
            }
923 31 ja_rd
        }
924 147 ja_rd
        else{                         //move to CP0 (mtc0)
925
            /* FIXME check CF= reg address */
926
            s->status=r[rt];
927 31 ja_rd
            if(s->processId && (r[rt]&2)){
928
                s->userMode|=r[rt]&2;
929
                //printf("CpuStatus=%d %d %d\n", r[rt], s->status, s->userMode);
930
                //s->wakeup = 1;
931
                //printf("pc=0x%x\n", epc);
932 2 ja_rd
            }
933 31 ja_rd
        }
934
        break;
935 105 ja_rd
    case 0x11:/*COP1*/  unimplemented(s,"COP1");
936
                        break;
937 2 ja_rd
//      case 0x12:/*COP2*/ break;
938
//      case 0x13:/*COP3*/ break;
939 31 ja_rd
    case 0x14:/*BEQL*/  lbranch=r[rs]==r[rt];    break;
940
    case 0x15:/*BNEL*/  lbranch=r[rs]!=r[rt];    break;
941
    case 0x16:/*BLEZL*/ lbranch=r[rs]<=0;        break;
942
    case 0x17:/*BGTZL*/ lbranch=r[rs]>0;         break;
943 2 ja_rd
//      case 0x1c:/*MAD*/  break;   /*IV*/
944 31 ja_rd
    case 0x20:/*LB*/    //r[rt]=(signed char)mem_read(s,1,ptr,1);  break;
945 53 ja_rd
                        start_load(s, ptr, rt,(signed char)mem_read(s,1,ptr,1));
946 31 ja_rd
                        break;
947 2 ja_rd
 
948 31 ja_rd
    case 0x21:/*LH*/    //r[rt]=(signed short)mem_read(s,2,ptr,1); break;
949 53 ja_rd
                        start_load(s, ptr, rt, (signed short)mem_read(s,2,ptr,1));
950 31 ja_rd
                        break;
951 105 ja_rd
    case 0x22:/*LWL*/   mem_lwl(s, ptr, rt, 1);
952
                        //printf("LWL\n");
953 31 ja_rd
                        break;
954
    case 0x23:/*LW*/    //r[rt]=mem_read(s,4,ptr,1);   break;
955 53 ja_rd
                        start_load(s, ptr, rt, mem_read(s,4,ptr,1));
956 31 ja_rd
                        break;
957
    case 0x24:/*LBU*/   //r[rt]=(unsigned char)mem_read(s,1,ptr,1); break;
958 53 ja_rd
                        start_load(s, ptr, rt, (unsigned char)mem_read(s,1,ptr,1));
959 31 ja_rd
                        break;
960
    case 0x25:/*LHU*/   //r[rt]= (unsigned short)mem_read(s,2,ptr,1);
961 53 ja_rd
                        start_load(s, ptr, rt, (unsigned short)mem_read(s,2,ptr,1));
962 31 ja_rd
                        break;
963 105 ja_rd
    case 0x26:/*LWR*/   mem_lwr(s, ptr, rt, 1);
964
                        //printf("LWR\n");
965 31 ja_rd
                        break;
966
    case 0x28:/*SB*/    mem_write(s,1,ptr,r[rt],1);  break;
967
    case 0x29:/*SH*/    mem_write(s,2,ptr,r[rt],1);  break;
968 105 ja_rd
    case 0x2a:/*SWL*/   mem_swl(s, ptr, r[rt], 1);
969
                        //printf("SWL\n");
970
                        break;
971 31 ja_rd
    case 0x2b:/*SW*/    mem_write(s,4,ptr,r[rt],1);  break;
972 105 ja_rd
    case 0x2e:/*SWR*/   mem_swr(s, ptr, r[rt], 1);
973
                        //printf("SWR\n");
974
                        break;
975
    case 0x2f:/*CACHE*/ unimplemented(s,"CACHE");
976
                        break;
977
    case 0x30:/*LL*/    //unimplemented(s,"LL");
978 53 ja_rd
                        start_load(s, ptr, rt, mem_read(s,4,ptr,1));
979 31 ja_rd
                        break;
980 2 ja_rd
//      case 0x31:/*LWC1*/ break;
981
//      case 0x32:/*LWC2*/ break;
982
//      case 0x33:/*LWC3*/ break;
983
//      case 0x35:/*LDC1*/ break;
984
//      case 0x36:/*LDC2*/ break;
985
//      case 0x37:/*LDC3*/ break;
986
//      case 0x38:/*SC*/     *(int*)ptr=r[rt]; r[rt]=1; break;
987 31 ja_rd
    case 0x38:/*SC*/    mem_write(s,4,ptr,r[rt],1); r[rt]=1; break;
988 2 ja_rd
//      case 0x39:/*SWC1*/ break;
989
//      case 0x3a:/*SWC2*/ break;
990
//      case 0x3b:/*SWC3*/ break;
991
//      case 0x3d:/*SDC1*/ break;
992
//      case 0x3e:/*SDC2*/ break;
993
//      case 0x3f:/*SDC3*/ break;
994 31 ja_rd
    default:
995 147 ja_rd
        ;
996 31 ja_rd
        /* FIXME should trap unimplemented opcodes */
997 147 ja_rd
        /* FIXME newlib */
998 31 ja_rd
        printf("ERROR2 address=0x%x opcode=0x%x\n", s->pc, opcode);
999
        s->wakeup=1;
1000
    }
1001 53 ja_rd
 
1002
    /* adjust next PC if this was a ajump instruction */
1003 31 ja_rd
    s->pc_next += (branch || lbranch == 1) ? imm_shift : 0;
1004
    s->pc_next &= ~3;
1005
    s->skip = (lbranch == 0) | skip2;
1006 2 ja_rd
 
1007 31 ja_rd
    /* If there was trouble (failed assertions), log it */
1008
    if(s->failed_assertions!=0){
1009
        log_failed_assertions(s);
1010
        s->failed_assertions=0;
1011
    }
1012 5 ja_rd
 
1013 31 ja_rd
    /* if there's a delayed load pending, do it now: load reg with memory data*/
1014
    /* load delay slots not simulated */
1015 2 ja_rd
 
1016 31 ja_rd
    /* Handle exceptions */
1017
   if(s->exceptionId){
1018
        r[rt] = rSave;
1019
        s->cp0_cause = (s->delay_slot & 0x1) << 31 | (trap_cause & 0x1f);
1020
        /* adjust epc if we (i.e. the victim instruction) are in a delay slot */
1021
        if(s->delay_slot){
1022 27 ja_rd
        epc = epc - 4;
1023 31 ja_rd
        }
1024
        s->epc = epc;
1025 61 ja_rd
        s->pc_next = VECTOR_TRAP;
1026 31 ja_rd
        s->skip = 1;
1027
        s->exceptionId = 0;
1028
        s->userMode = 0;
1029
        //s->wakeup = 1;
1030
    }
1031 27 ja_rd
 
1032 53 ja_rd
    /* if we're NOT showing output to console, log state of CPU to file */
1033
    if(!show_mode){
1034
        log_cycle(s);
1035
    }
1036
 
1037
 
1038
 
1039 31 ja_rd
    /* if this instruction was any kind of branch that actually jumped, then
1040
       the next instruction will be in a delay slot. Remember it. */
1041
    delay_slot = ((lbranch==1) || branch || delay_slot);
1042
    s->delay_slot = delay_slot;
1043 2 ja_rd
}
1044
 
1045
/** Dump CPU state to console */
1046 31 ja_rd
void show_state(t_state *s){
1047
    int i,j;
1048
    printf("pid=%d userMode=%d, epc=0x%x\n", s->processId, s->userMode, s->epc);
1049
    printf("hi=0x%08x lo=0x%08x\n", s->hi, s->lo);
1050
    for(i = 0; i < 4; ++i){
1051
        printf("%2.2d ", i * 8);
1052
        for(j = 0; j < 8; ++j){
1053
            printf("%8.8x ", s->r[i*8+j]);
1054
        }
1055
        printf("\n");
1056
    }
1057
    //printf("%8.8lx %8.8lx %8.8lx %8.8lx\n", s->pc, s->pc_next, s->hi, s->lo);
1058
    j = s->pc;
1059
    for(i = -4; i <= 8; ++i){
1060
        printf("%c", i==0 ? '*' : ' ');
1061
        s->pc = j + i * 4;
1062
        cycle(s, 10);
1063
    }
1064
    s->pc = j;
1065 2 ja_rd
}
1066
 
1067
/** Show debug monitor prompt and execute user command */
1068 105 ja_rd
void do_debug(t_state *s, uint32_t no_prompt){
1069 31 ja_rd
    int ch;
1070 105 ja_rd
    int i, j=0, watch=0, addr;
1071
    j = s->breakpoint;
1072 31 ja_rd
    s->pc_next = s->pc + 4;
1073
    s->skip = 0;
1074 105 ja_rd
    s->wakeup = 0;
1075
 
1076
    printf("Starting simulation.\n");
1077
 
1078
    if(no_prompt){
1079
        ch = '5'; /* 'go' command */
1080
        printf("\n\n");
1081
    }
1082
    else{
1083
        show_state(s);
1084
        ch = ' ';
1085
    }
1086
 
1087 31 ja_rd
    for(;;){
1088 105 ja_rd
        if(ch != 'n' && !no_prompt){
1089 31 ja_rd
            if(watch){
1090
                printf("0x%8.8x=0x%8.8x\n", watch, mem_read(s, 4, watch,0));
1091 2 ja_rd
            }
1092 31 ja_rd
            printf("1=Debug 2=t_trace 3=Step 4=BreakPt 5=Go 6=Memory ");
1093 93 ja_rd
            printf("7=Watch 8=Jump 9=Quit A=Dump\n");
1094
            printf("L=LogTrigger > ");
1095 31 ja_rd
        }
1096 105 ja_rd
        if(ch==' ') ch = getch();
1097 31 ja_rd
        if(ch != 'n'){
1098
            printf("\n");
1099
        }
1100
        switch(ch){
1101
        case 'a': case 'A':
1102
            dump_trace_buffer(s); break;
1103
        case '1': case 'd': case ' ':
1104
            cycle(s, 0); show_state(s); break;
1105
        case 'n':
1106
            cycle(s, 1); break;
1107
        case '2': case 't':
1108
            cycle(s, 0); printf("*"); cycle(s, 10); break;
1109
        case '3': case 's':
1110
            printf("Count> ");
1111
            scanf("%d", &j);
1112
            for(i = 0; i < j; ++i){
1113
                cycle(s, 1);
1114
            }
1115
            show_state(s);
1116
            break;
1117
        case '4': case 'b':
1118
            printf("Line> ");
1119
            scanf("%x", &j);
1120
            printf("break point=0x%x\n", j);
1121
            break;
1122
        case '5': case 'g':
1123
            s->wakeup = 0;
1124 2 ja_rd
            cycle(s, 0);
1125 31 ja_rd
            while(s->wakeup == 0){
1126
                if(s->pc == j){
1127
                    printf("\n\nStop: pc = 0x%08x\n\n", j);
1128
                    break;
1129
                }
1130
                cycle(s, 0);
1131 105 ja_rd
            }
1132
            if(no_prompt) return;
1133 31 ja_rd
            show_state(s);
1134
            break;
1135
        case 'G':
1136
            s->wakeup = 0;
1137 2 ja_rd
            cycle(s, 1);
1138 31 ja_rd
            while(s->wakeup == 0){
1139
                if(s->pc == j){
1140
                    break;
1141
                }
1142
                cycle(s, 1);
1143
            }
1144
            show_state(s);
1145
            break;
1146
        case '6': case 'm':
1147
            printf("Memory> ");
1148
            scanf("%x", &j);
1149
            for(i = 0; i < 8; ++i){
1150
                printf("%8.8x ", mem_read(s, 4, j+i*4, 0));
1151
            }
1152
            printf("\n");
1153
            break;
1154
        case '7': case 'w':
1155
            printf("Watch> ");
1156
            scanf("%x", &watch);
1157
            break;
1158
        case '8': case 'j':
1159
            printf("Jump> ");
1160
            scanf("%x", &addr);
1161
            s->pc = addr;
1162
            s->pc_next = addr + 4;
1163
            show_state(s);
1164 93 ja_rd
            break;
1165
        case '9': case 'q':
1166
            return;
1167
        case 'l':
1168
            printf("Address> ");
1169
            scanf("%x", &(s->t.log_trigger_address));
1170
            printf("Log trigger address=0x%x\n", s->t.log_trigger_address);
1171 31 ja_rd
            break;
1172 105 ja_rd
        }
1173
        ch = ' ';
1174 31 ja_rd
    }
1175 2 ja_rd
}
1176
 
1177
/** Read binary code and data files */
1178 61 ja_rd
int read_binary_files(t_state *s, t_args *args){
1179 31 ja_rd
    FILE *in;
1180 105 ja_rd
    uint8_t *target;
1181
    uint32_t bytes=0, i, files_read=0;
1182 2 ja_rd
 
1183 31 ja_rd
    for(i=0;i<NUM_MEM_BLOCKS;i++){
1184 105 ja_rd
        bytes = 0;
1185 61 ja_rd
        if(args->bin_filename[i]!=NULL){
1186
 
1187
            in = fopen(args->bin_filename[i], "rb");
1188 31 ja_rd
            if(in == NULL){
1189 44 ja_rd
                free_cpu(s);
1190 61 ja_rd
                printf("Can't open file %s, quitting!\n",args->bin_filename[i]);
1191
                return(0);
1192 31 ja_rd
            }
1193 2 ja_rd
 
1194 105 ja_rd
            /* FIXME load offset 0x2000 for linux kernel hardcoded! */
1195
            //bytes = fread((s->blocks[i].mem + 0x2000), 1, s->blocks[i].size, in);
1196
            target = (uint8_t *)(s->blocks[i].mem + args->offset[i]);
1197
            while(!feof(in) &&
1198
                  ((bytes+1024+args->offset[i]) < (s->blocks[i].size))){
1199
                bytes += fread(&(target[bytes]), 1, 1024, in);
1200
                if(errno!=0){
1201
                    printf("ERROR: file load failed with code %d ('%s')\n",
1202
                        errno, strerror(errno));
1203
                    free_cpu(s);
1204
                    return 0;
1205
                }
1206
            }
1207
 
1208 31 ja_rd
            fclose(in);
1209 105 ja_rd
 
1210
            /* Now reverse the endianness of the data we just read, if it's
1211
             necessary. */
1212
             /* FIXME add cmd line param, etc. */
1213
            //reverse_endianess(target, bytes);
1214
 
1215 31 ja_rd
            files_read++;
1216
        }
1217 105 ja_rd
        printf("%-16s [size= %6dKB, start= 0x%08x] loaded %d bytes.\n",
1218
                s->blocks[i].area_name,
1219
                s->blocks[i].size/1024,
1220
                s->blocks[i].start,
1221
                bytes);
1222 31 ja_rd
    }
1223
 
1224
    if(!files_read){
1225 44 ja_rd
        free_cpu(s);
1226 31 ja_rd
        printf("No binary object files read, quitting\n");
1227 44 ja_rd
        return 0;
1228 31 ja_rd
    }
1229
 
1230 44 ja_rd
    return files_read;
1231 2 ja_rd
}
1232 105 ja_rd
 
1233
void reverse_endianess(uint8_t *data, uint32_t bytes){
1234
    uint8_t w[4];
1235
    uint32_t i, j;
1236
 
1237
    for(i=0;i<bytes;i=i+4){
1238
        for(j=0;j<4;j++){
1239
            w[3-j] = data[i+j];
1240
        }
1241
        for(j=0;j<4;j++){
1242
            data[i+j] = w[j];
1243
        }
1244
    }
1245
}
1246
 
1247 2 ja_rd
 
1248
/*----------------------------------------------------------------------------*/
1249
 
1250 31 ja_rd
int main(int argc,char *argv[]){
1251
    t_state state, *s=&state;
1252 105 ja_rd
 
1253
    /* Parse command line and pass any relevant arguments to CPU record */
1254
    if(parse_cmd_line(argc,argv, &cmd_line_args)==0){
1255
        return 0;
1256
    }
1257 2 ja_rd
 
1258 61 ja_rd
    printf("MIPS-I emulator (" __DATE__ ")\n\n");
1259 105 ja_rd
    if(!init_cpu(s, &cmd_line_args)){
1260 44 ja_rd
        printf("Trouble allocating memory, quitting!\n");
1261
        return 1;
1262
    };
1263 61 ja_rd
 
1264 93 ja_rd
    /* Read binary object files into memory*/
1265 61 ja_rd
    if(!read_binary_files(s, &cmd_line_args)){
1266 31 ja_rd
        return 2;
1267
    }
1268 61 ja_rd
    printf("\n\n");
1269 2 ja_rd
 
1270 93 ja_rd
    init_trace_buffer(s, &cmd_line_args);
1271 2 ja_rd
 
1272 31 ja_rd
    /* NOTE: Original mlite supported loading little-endian code, which this
1273 2 ja_rd
      program doesn't. The endianess-conversion code has been removed.
1274 31 ja_rd
    */
1275 2 ja_rd
 
1276 31 ja_rd
    /* Simulate a CPU reset */
1277 105 ja_rd
    reset_cpu(s);
1278
 
1279
    /* Simulate the work of the uClinux bootloader */
1280
    if(cmd_line_args.memory_map == MAP_UCLINUX){
1281
        /* FIXME this is a stub, flesh it out */
1282
        s->pc = 0x80002400;
1283
    }
1284 2 ja_rd
 
1285 31 ja_rd
    /* Enter debug command interface; will only exit clean with user command */
1286 105 ja_rd
    do_debug(s, cmd_line_args.no_prompt);
1287 2 ja_rd
 
1288 31 ja_rd
    /* Close and deallocate everything and quit */
1289
    close_trace_buffer(s);
1290
    free_cpu(s);
1291
    return(0);
1292 2 ja_rd
}
1293
 
1294
/*----------------------------------------------------------------------------*/
1295
 
1296
 
1297 93 ja_rd
void init_trace_buffer(t_state *s, t_args *args){
1298 31 ja_rd
    int i;
1299 2 ja_rd
 
1300
#if FILE_LOGGING_DISABLED
1301 31 ja_rd
    s->t.log = NULL;
1302 93 ja_rd
    s->t.log_triggered = 0;
1303 31 ja_rd
    return;
1304 2 ja_rd
#else
1305 93 ja_rd
    /* clear trace buffer */
1306 31 ja_rd
    for(i=0;i<TRACE_BUFFER_SIZE;i++){
1307
        s->t.buf[i]=0xffffffff;
1308
    }
1309
    s->t.next = 0;
1310 2 ja_rd
 
1311 31 ja_rd
    /* if file logging is enabled, open log file */
1312 93 ja_rd
    if(args->log_file_name!=NULL){
1313
        s->t.log = fopen(args->log_file_name, "w");
1314 31 ja_rd
        if(s->t.log==NULL){
1315
            printf("Error opening log file '%s', file logging disabled\n",
1316 93 ja_rd
                    args->log_file_name);
1317 31 ja_rd
        }
1318
    }
1319
    else{
1320
        s->t.log = NULL;
1321
    }
1322 93 ja_rd
 
1323
    /* Setup log trigger */
1324
    s->t.log_triggered = 0;
1325
    s->t.log_trigger_address = args->log_trigger_address;
1326 2 ja_rd
#endif
1327
}
1328
 
1329
/** Dumps last jump targets as a chunk of hex numbers (older is left top) */
1330 31 ja_rd
void dump_trace_buffer(t_state *s){
1331
    int i, col;
1332 2 ja_rd
 
1333 31 ja_rd
    for(i=0, col=0;i<TRACE_BUFFER_SIZE;i++, col++){
1334
        printf("%08x ", s->t.buf[s->t.next + i]);
1335
        if((col % 8)==7){
1336
            printf("\n");
1337
        }
1338
    }
1339 2 ja_rd
}
1340
 
1341
/** Logs last cycle's activity (changes in state and/or loads/stores) */
1342 31 ja_rd
void log_cycle(t_state *s){
1343
    static unsigned int last_pc = 0;
1344
    int i;
1345 53 ja_rd
    uint32_t log_pc;
1346 2 ja_rd
 
1347 31 ja_rd
    /* store PC in trace buffer only if there was a jump */
1348
    if(s->pc != (last_pc+4)){
1349
        s->t.buf[s->t.next] = s->pc;
1350
        s->t.next = (s->t.next + 1) % TRACE_BUFFER_SIZE;
1351
    }
1352
    last_pc = s->pc;
1353 2 ja_rd
 
1354 31 ja_rd
    /* if file logging is enabled, dump a trace log to file */
1355 93 ja_rd
    if(log_enabled(s)){
1356 53 ja_rd
        log_pc = s->op_addr;
1357
 
1358 147 ja_rd
        /* skip register zero which does not change */
1359
        for(i=1;i<32;i++){
1360 31 ja_rd
            if(s->t.pr[i] != s->r[i]){
1361 53 ja_rd
                fprintf(s->t.log, "(%08X) [%02X]=%08X\n", log_pc, i, s->r[i]);
1362 31 ja_rd
            }
1363
            s->t.pr[i] = s->r[i];
1364
        }
1365
        if(s->lo != s->t.lo){
1366 147 ja_rd
            //fprintf(s->t.log, "(%08X) [LO]=%08X\n", log_pc, s->lo);
1367 31 ja_rd
        }
1368
        s->t.lo = s->lo;
1369 2 ja_rd
 
1370 31 ja_rd
        if(s->hi != s->t.hi){
1371 147 ja_rd
            //fprintf(s->t.log, "(%08X) [HI]=%08X\n", log_pc, s->hi);
1372 31 ja_rd
        }
1373
        s->t.hi = s->hi;
1374 2 ja_rd
 
1375 53 ja_rd
        /* */
1376
        /* FIXME epc may change by direct write too, handle case */
1377 31 ja_rd
        if(s->epc != s->t.epc){
1378 53 ja_rd
            fprintf(s->t.log, "(%08X) [EP]=%08X\n", log_pc, s->epc);
1379 31 ja_rd
        }
1380
        s->t.epc = s->epc;
1381
    }
1382 2 ja_rd
}
1383
 
1384
/** Frees debug buffers and closes log file */
1385 31 ja_rd
void close_trace_buffer(t_state *s){
1386
    if(s->t.log){
1387
        fclose(s->t.log);
1388
    }
1389 2 ja_rd
}
1390 5 ja_rd
 
1391
/** Logs a message for each failed assertion, each in a line */
1392 31 ja_rd
void log_failed_assertions(t_state *s){
1393
    unsigned bitmap = s->failed_assertions;
1394
    int i = 0;
1395 5 ja_rd
 
1396 31 ja_rd
    /* This loop will crash the program if the message table is too short...*/
1397
    if(s->t.log != NULL){
1398
        for(i=0;i<32;i++){
1399
            if(bitmap & 0x1){
1400
                fprintf(s->t.log, "ASSERTION FAILED: [%08x] %s\n",
1401
                        s->faulty_address,
1402
                        assertion_messages[i]);
1403
            }
1404
            bitmap = bitmap >> 1;
1405
        }
1406
    }
1407 5 ja_rd
}
1408 31 ja_rd
 
1409 93 ja_rd
uint32_t log_enabled(t_state *s){
1410
    return ((s->t.log != NULL) && (s->t.log_triggered!=0));
1411
}
1412
 
1413
void trigger_log(t_state *s){
1414
    uint32_t i;
1415
 
1416
    s->t.log_triggered = 1;
1417
 
1418
    for(i=0;i<32;i++){
1419
        s->t.pr[i] = s->r[i];
1420
    }
1421
 
1422
    s->t.lo = s->lo;
1423
    s->t.hi = s->hi;
1424
    s->t.epc = s->epc;
1425
}
1426
 
1427 31 ja_rd
void free_cpu(t_state *s){
1428
    int i;
1429
 
1430
    for(i=0;i<NUM_MEM_BLOCKS;i++){
1431
        free(s->blocks[i].mem);
1432
        s->blocks[i].mem = NULL;
1433
    }
1434
}
1435
 
1436
void reset_cpu(t_state *s){
1437
    s->pc = VECTOR_RESET;     /* reset start vector */
1438
    s->delay_slot = 0;
1439
    s->failed_assertions = 0; /* no failed assertions pending */
1440
}
1441 105 ja_rd
 
1442
void unimplemented(t_state *s, const char *txt){
1443
    /* FIXME unimplemented opcode trap */
1444
    printf("UNIMPLEMENTED: %s\n", txt);
1445
}
1446 31 ja_rd
 
1447 105 ja_rd
int init_cpu(t_state *s, t_args *args){
1448
    int i, j;
1449
    uint32_t k = args->memory_map;
1450 44 ja_rd
 
1451 31 ja_rd
    memset(s, 0, sizeof(t_state));
1452
    s->big_endian = 1;
1453 61 ja_rd
 
1454 105 ja_rd
    s->do_unaligned = args->do_unaligned;
1455
    s->breakpoint = args->breakpoint;
1456
 
1457 61 ja_rd
    /* Initialize memory map */
1458 31 ja_rd
    for(i=0;i<NUM_MEM_BLOCKS;i++){
1459 105 ja_rd
        s->blocks[i].start =        memory_maps[k].blocks[i].start;
1460
        s->blocks[i].size =         memory_maps[k].blocks[i].size;
1461
        s->blocks[i].area_name =    memory_maps[k].blocks[i].area_name;
1462
        s->blocks[i].mask =         memory_maps[k].blocks[i].mask;
1463
        s->blocks[i].read_only =    memory_maps[k].blocks[i].read_only;
1464 44 ja_rd
 
1465
        s->blocks[i].mem = (unsigned char*)malloc(s->blocks[i].size);
1466
 
1467
        if(s->blocks[i].mem == NULL){
1468
            for(j=0;j<i;j++){
1469
                free(s->blocks[j].mem);
1470
            }
1471
            return 0;
1472
        }
1473
        memset(s->blocks[i].mem, 0, s->blocks[i].size);
1474 105 ja_rd
    }
1475 44 ja_rd
    return NUM_MEM_BLOCKS;
1476 31 ja_rd
}
1477 61 ja_rd
 
1478
int32_t parse_cmd_line(uint32_t argc, char **argv, t_args *args){
1479
    uint32_t i;
1480
 
1481 105 ja_rd
    /* fill cmd line args with default values */
1482
    args->memory_map = MAP_DEFAULT;
1483
    args->do_unaligned = 0;
1484
    args->no_prompt = 0;
1485
    args->breakpoint = 0xffffffff;
1486
    args->log_file_name = "sw_sim_log.txt";
1487
    args->log_trigger_address = VECTOR_RESET;
1488 61 ja_rd
    for(i=0;i<NUM_MEM_BLOCKS;i++){
1489
        args->bin_filename[i] = NULL;
1490 105 ja_rd
        args->offset[i] = 0;
1491 61 ja_rd
    }
1492
 
1493
    /* parse actual cmd line args */
1494
    for(i=1;i<argc;i++){
1495
        if(strcmp(argv[i],"--plasma")==0){
1496 105 ja_rd
            /* plasma simulation not supported, error*/
1497
            printf("Error: program compiled for compatibility to MIPS-I\n");
1498
            return 0;
1499
        }
1500
        else if(strcmp(argv[i],"--uclinux")==0){
1501
            args->memory_map = MAP_UCLINUX;
1502
            /* FIXME selecting uClinux enables unaligned L/S emulation */
1503
            args->do_unaligned = 1;
1504 61 ja_rd
        }
1505 108 ja_rd
        else if(strcmp(argv[i],"--small")==0){
1506
            args->memory_map = MAP_SMALL;
1507
        }
1508 105 ja_rd
        else if(strcmp(argv[i],"--unaligned")==0){
1509
            args->do_unaligned = 1;
1510
        }
1511
        else if(strcmp(argv[i],"--noprompt")==0){
1512
            args->no_prompt = 1;
1513
        }
1514 61 ja_rd
        else if(strncmp(argv[i],"--bram=", strlen("--bram="))==0){
1515
            args->bin_filename[0] = &(argv[i][strlen("--bram=")]);
1516
        }
1517
        else if(strncmp(argv[i],"--flash=", strlen("--flash="))==0){
1518 105 ja_rd
            args->bin_filename[3] = &(argv[i][strlen("--flash=")]);
1519 61 ja_rd
        }
1520
        else if(strncmp(argv[i],"--xram=", strlen("--xram="))==0){
1521
            args->bin_filename[1] = &(argv[i][strlen("--xram=")]);
1522
        }
1523 105 ja_rd
        else if(strncmp(argv[i],"--kernel=", strlen("--kernel="))==0){
1524
            args->bin_filename[1] = &(argv[i][strlen("--kernel=")]);
1525
            /* FIXME uClinux kernel 'offset' hardcoded */
1526
            args->offset[1] = 0x2000;
1527
        }
1528 93 ja_rd
        else if(strncmp(argv[i],"--trigger=", strlen("--trigger="))==0){
1529
            sscanf(&(argv[i][strlen("--trigger=")]), "%x", &(args->log_trigger_address));
1530
        }
1531 105 ja_rd
        else if(strncmp(argv[i],"--breakpoint=", strlen("--breakpoint="))==0){
1532
            sscanf(&(argv[i][strlen("--breakpoint=")]), "%x", &(args->breakpoint));
1533
        }
1534 61 ja_rd
        else if((strcmp(argv[i],"--help")==0)||(strcmp(argv[i],"-h")==0)){
1535
            usage();
1536
            return 0;
1537
        }
1538
        else{
1539
            printf("unknown argument '%s'\n\n",argv[i]);
1540
            usage();
1541
            return 0;
1542
        }
1543
    }
1544
 
1545
    return 1;
1546
}
1547
 
1548
void usage(void){
1549
    printf("Usage:");
1550
    printf("    slite file.exe [arguments]\n");
1551
    printf("Arguments:\n");
1552
    printf("--bram=<file name>      : BRAM initialization file\n");
1553
    printf("--xram=<file name>      : XRAM initialization file\n");
1554 105 ja_rd
    printf("--kernel=<file name>    : XRAM initialization file for uClinux kernel\n");
1555
    printf("                          (loads at block offset 0x2000)\n");
1556 61 ja_rd
    printf("--flash=<file name>     : FLASH initialization file\n");
1557 93 ja_rd
    printf("--trigger=<hex number>  : Log trigger address\n");
1558 61 ja_rd
    printf("--plasma                : Simulate Plasma instead of MIPS-I\n");
1559 105 ja_rd
    printf("--uclinux               : Use memory map tailored to uClinux\n");
1560
    printf("--unaligned             : Implement unaligned load/store instructions\n");
1561
    printf("--noprompt              : Run in batch mode\n");
1562
    printf("--stop_at_zero          : Stop simulation when fetching from address 0x0\n");
1563 61 ja_rd
    printf("--help, -h              : Show this usage text\n");
1564
}
1565 105 ja_rd
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.