/[gxemul]/trunk/src/cpus/cpu_arm_instr.c
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Diff of /trunk/src/cpus/cpu_arm_instr.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 17 by dpavlin, Mon Oct 8 16:19:01 2007 UTC revision 18 by dpavlin, Mon Oct 8 16:19:11 2007 UTC
# Line 25  Line 25 
25   *  SUCH DAMAGE.   *  SUCH DAMAGE.
26   *   *
27   *   *
28   *  $Id: cpu_arm_instr.c,v 1.29 2005/10/11 03:31:28 debug Exp $   *  $Id: cpu_arm_instr.c,v 1.39 2005/10/27 14:01:13 debug Exp $
29   *   *
30   *  ARM instructions.   *  ARM instructions.
31   *   *
# Line 36  Line 36 
36   */   */
37    
38    
39    #include "arm_quick_pc_to_pointers.h"
40    
41    /*  #define GATHER_BDT_STATISTICS  */
42    
43    
44    #ifdef GATHER_BDT_STATISTICS
45    /*
46     *  update_bdt_statistics():
47     *
48     *  Gathers statistics about load/store multiple instructions.
49     *
50     *  NOTE/TODO: Perhaps it would be more memory efficient to swap the high
51     *  and low parts of the instruction word, so that the lllllll bits become
52     *  the high bits; this would cause fewer host pages to be used. Anyway, the
53     *  current implementation works on hosts with lots of RAM.
54     *
55     *  The resulting file, bdt_statistics.txt, should then be processed like
56     *  this to give a new cpu_arm_multi.txt:
57     *
58     *  uniq -c bdt_statistics.txt|sort -nr|head -256|cut -f 2 > cpu_arm_multi.txt
59     */
60    static void update_bdt_statistics(uint32_t iw)
61    {
62            static FILE *f = NULL;
63            static long long *counts;
64            static char *counts_used;
65            static long long n = 0;
66    
67            if (f == NULL) {
68                    size_t s = (1 << 24) * sizeof(long long);
69                    f = fopen("bdt_statistics.txt", "w");
70                    if (f == NULL) {
71                            fprintf(stderr, "update_bdt_statistics(): :-(\n");
72                            exit(1);
73                    }
74                    counts = zeroed_alloc(s);
75                    counts_used = zeroed_alloc(65536);
76            }
77    
78            /*  Drop the s-bit: xxxx100P USWLnnnn llllllll llllllll  */
79            iw = ((iw & 0x01800000) >> 1) | (iw & 0x003fffff);
80    
81            counts_used[iw & 0xffff] = 1;
82            counts[iw] ++;
83    
84            n ++;
85            if ((n % 500000) == 0) {
86                    int i;
87                    long long j;
88                    fatal("[ update_bdt_statistics(): n = %lli ]\n", (long long) n);
89                    fseek(f, 0, SEEK_SET);
90                    for (i=0; i<0x1000000; i++)
91                            if (counts_used[i & 0xffff] && counts[i] != 0) {
92                                    /*  Recreate the opcode:  */
93                                    uint32_t opcode = ((i & 0x00c00000) << 1)
94                                        | (i & 0x003fffff) | 0x08000000;
95                                    for (j=0; j<counts[i]; j++)
96                                            fprintf(f, "0x%08x\n", opcode);
97                            }
98                    fflush(f);
99            }
100    }
101    #endif
102    
103    
104    /*****************************************************************************/
105    
106    
107  /*  /*
108   *  Helper definitions:   *  Helper definitions:
109   *   *
# Line 51  Line 119 
119   *  condition code. (The NV condition code is not included, and the AL code   *  condition code. (The NV condition code is not included, and the AL code
120   *  uses the main foo function.)  Y also defines an array with pointers to   *  uses the main foo function.)  Y also defines an array with pointers to
121   *  all of these functions.   *  all of these functions.
122     *
123     *  If the compiler is good enough (i.e. allows long enough code sequences
124     *  to be inlined), then the Y functions will be compiled as full (inlined)
125     *  functions, otherwise they will simply call the X function.
126   */   */
127    
128  #define Y(n) void arm_instr_ ## n ## __eq(struct cpu *cpu,              \  #define Y(n) void arm_instr_ ## n ## __eq(struct cpu *cpu,              \
# Line 176  X(b) Line 248  X(b)
248          cpu->pc = cpu->cd.arm.r[ARM_PC];          cpu->pc = cpu->cd.arm.r[ARM_PC];
249    
250          /*  Find the new physical page and update the translation pointers:  */          /*  Find the new physical page and update the translation pointers:  */
251          arm_pc_to_pointers(cpu);          quick_pc_to_pointers(cpu);
252  }  }
253  Y(b)  Y(b)
254    
# Line 208  X(bx) Line 280  X(bx)
280          cpu->pc &= ~3;          cpu->pc &= ~3;
281    
282          /*  Find the new physical page and update the translation pointers:  */          /*  Find the new physical page and update the translation pointers:  */
283          arm_pc_to_pointers(cpu);          quick_pc_to_pointers(cpu);
284  }  }
285  Y(bx)  Y(bx)
286    
# Line 230  X(bx_trace) Line 302  X(bx_trace)
302          cpu_functioncall_trace_return(cpu);          cpu_functioncall_trace_return(cpu);
303    
304          /*  Find the new physical page and update the translation pointers:  */          /*  Find the new physical page and update the translation pointers:  */
305          arm_pc_to_pointers(cpu);          quick_pc_to_pointers(cpu);
306  }  }
307  Y(bx_trace)  Y(bx_trace)
308    
# Line 258  X(bl) Line 330  X(bl)
330          cpu->pc = cpu->cd.arm.r[ARM_PC] = lr - 4 + (int32_t)ic->arg[0];          cpu->pc = cpu->cd.arm.r[ARM_PC] = lr - 4 + (int32_t)ic->arg[0];
331    
332          /*  Find the new physical page and update the translation pointers:  */          /*  Find the new physical page and update the translation pointers:  */
333          arm_pc_to_pointers(cpu);          quick_pc_to_pointers(cpu);
334  }  }
335  Y(bl)  Y(bl)
336    
# Line 290  X(blx) Line 362  X(blx)
362          cpu->pc &= ~3;          cpu->pc &= ~3;
363    
364          /*  Find the new physical page and update the translation pointers:  */          /*  Find the new physical page and update the translation pointers:  */
365          arm_pc_to_pointers(cpu);          quick_pc_to_pointers(cpu);
366  }  }
367  Y(blx)  Y(blx)
368    
# Line 320  X(bl_trace) Line 392  X(bl_trace)
392          cpu_functioncall_trace(cpu, cpu->pc);          cpu_functioncall_trace(cpu, cpu->pc);
393    
394          /*  Find the new physical page and update the translation pointers:  */          /*  Find the new physical page and update the translation pointers:  */
395          arm_pc_to_pointers(cpu);          quick_pc_to_pointers(cpu);
396  }  }
397  Y(bl_trace)  Y(bl_trace)
398    
# Line 383  X(bl_samepage_trace) Line 455  X(bl_samepage_trace)
455  Y(bl_samepage_trace)  Y(bl_samepage_trace)
456    
457    
458    #include "cpu_arm_instr_misc.c"
459    
460    
461  /*  /*
462   *  mul: Multiplication   *  mul: Multiplication
463   *   *
# Line 397  X(mul) Line 472  X(mul)
472  Y(mul)  Y(mul)
473  X(muls)  X(muls)
474  {  {
475          uint32_t result = reg(ic->arg[1]) * reg(ic->arg[2]);          uint32_t result;
476            result = reg(ic->arg[1]) * reg(ic->arg[2]);
477          cpu->cd.arm.cpsr &= ~(ARM_FLAG_Z | ARM_FLAG_N);          cpu->cd.arm.cpsr &= ~(ARM_FLAG_Z | ARM_FLAG_N);
478          if (result == 0)          if (result == 0)
479                  cpu->cd.arm.cpsr |= ARM_FLAG_Z;                  cpu->cd.arm.cpsr |= ARM_FLAG_Z;
# Line 417  X(mla) Line 493  X(mla)
493  {  {
494          /*  xxxx0000 00ASdddd nnnnssss 1001mmmm (Rd,Rm,Rs[,Rn])  */          /*  xxxx0000 00ASdddd nnnnssss 1001mmmm (Rd,Rm,Rs[,Rn])  */
495          uint32_t iw = ic->arg[0];          uint32_t iw = ic->arg[0];
496          int rd = (iw >> 16) & 15, rn = (iw >> 12) & 15,          int rd, rs, rn, rm;
497              rs = (iw >> 8) & 15,  rm = iw & 15;          rd = (iw >> 16) & 15; rn = (iw >> 12) & 15,
498            rs = (iw >> 8) & 15;  rm = iw & 15;
499          cpu->cd.arm.r[rd] = cpu->cd.arm.r[rm] * cpu->cd.arm.r[rs]          cpu->cd.arm.r[rd] = cpu->cd.arm.r[rm] * cpu->cd.arm.r[rs]
500              + cpu->cd.arm.r[rn];              + cpu->cd.arm.r[rn];
501  }  }
# Line 427  X(mlas) Line 504  X(mlas)
504  {  {
505          /*  xxxx0000 00ASdddd nnnnssss 1001mmmm (Rd,Rm,Rs[,Rn])  */          /*  xxxx0000 00ASdddd nnnnssss 1001mmmm (Rd,Rm,Rs[,Rn])  */
506          uint32_t iw = ic->arg[0];          uint32_t iw = ic->arg[0];
507          int rd = (iw >> 16) & 15, rn = (iw >> 12) & 15,          int rd, rs, rn, rm;
508              rs = (iw >> 8) & 15,  rm = iw & 15;          rd = (iw >> 16) & 15; rn = (iw >> 12) & 15,
509            rs = (iw >> 8) & 15;  rm = iw & 15;
510          cpu->cd.arm.r[rd] = cpu->cd.arm.r[rm] * cpu->cd.arm.r[rs]          cpu->cd.arm.r[rd] = cpu->cd.arm.r[rm] * cpu->cd.arm.r[rs]
511              + cpu->cd.arm.r[rn];              + cpu->cd.arm.r[rn];
512          cpu->cd.arm.cpsr &= ~(ARM_FLAG_Z | ARM_FLAG_N);          cpu->cd.arm.cpsr &= ~(ARM_FLAG_Z | ARM_FLAG_N);
# Line 448  Y(mlas) Line 526  Y(mlas)
526  X(mull)  X(mull)
527  {  {
528          /*  xxxx0000 1UAShhhh llllssss 1001mmmm  */          /*  xxxx0000 1UAShhhh llllssss 1001mmmm  */
529          uint32_t iw = ic->arg[0];          uint32_t iw; uint64_t tmp; int u_bit, a_bit;
530          int u_bit = (iw >> 22) & 1, a_bit = (iw >> 21) & 1;          iw = ic->arg[0];
531          uint64_t tmp = cpu->cd.arm.r[iw & 15];          u_bit = (iw >> 22) & 1; a_bit = (iw >> 21) & 1;
532            tmp = cpu->cd.arm.r[iw & 15];
533          if (u_bit)          if (u_bit)
534                  tmp = (int64_t)(int32_t)tmp                  tmp = (int64_t)(int32_t)tmp
535                      * (int64_t)(int32_t)cpu->cd.arm.r[(iw >> 8) & 15];                      * (int64_t)(int32_t)cpu->cd.arm.r[(iw >> 8) & 15];
# Line 485  Y(mov_reg_reg) Line 564  Y(mov_reg_reg)
564    
565  /*  /*
566   *  ret_trace:  "mov pc,lr" with trace enabled   *  ret_trace:  "mov pc,lr" with trace enabled
567     *  ret:  "mov pc,lr" without trace enabled
568   *   *
569   *  arg[0] = ignored   *  arg[0] = ignored
570   */   */
571  X(ret_trace)  X(ret_trace)
572  {  {
573          uint32_t old_pc = cpu->cd.arm.r[ARM_PC];          uint32_t old_pc, mask_within_page;
574          uint32_t mask_within_page = ((ARM_IC_ENTRIES_PER_PAGE-1)          old_pc = cpu->cd.arm.r[ARM_PC];
575            mask_within_page = ((ARM_IC_ENTRIES_PER_PAGE-1)
576              << ARM_INSTR_ALIGNMENT_SHIFT) |              << ARM_INSTR_ALIGNMENT_SHIFT) |
577              ((1 << ARM_INSTR_ALIGNMENT_SHIFT) - 1);              ((1 << ARM_INSTR_ALIGNMENT_SHIFT) - 1);
578    
# Line 509  X(ret_trace) Line 590  X(ret_trace)
590                      ((cpu->pc & mask_within_page) >> ARM_INSTR_ALIGNMENT_SHIFT);                      ((cpu->pc & mask_within_page) >> ARM_INSTR_ALIGNMENT_SHIFT);
591          } else {          } else {
592                  /*  Find the new physical page and update pointers:  */                  /*  Find the new physical page and update pointers:  */
593                  arm_pc_to_pointers(cpu);                  quick_pc_to_pointers(cpu);
594          }          }
595  }  }
596  Y(ret_trace)  Y(ret_trace)
597    X(ret)
598    {
599            cpu->pc = cpu->cd.arm.r[ARM_PC] = cpu->cd.arm.r[ARM_LR];
600            quick_pc_to_pointers(cpu);
601    }
602    Y(ret)
603    
604    
605  /*  /*
# Line 672  X(openfirmware) Line 759  X(openfirmware)
759          cpu->pc = cpu->cd.arm.r[ARM_PC] = cpu->cd.arm.r[ARM_LR];          cpu->pc = cpu->cd.arm.r[ARM_PC] = cpu->cd.arm.r[ARM_LR];
760          if (cpu->machine->show_trace_tree)          if (cpu->machine->show_trace_tree)
761                  cpu_functioncall_trace_return(cpu);                  cpu_functioncall_trace_return(cpu);
762          arm_pc_to_pointers(cpu);          quick_pc_to_pointers(cpu);
763  }  }
764    
765    
# Line 700  X(swi_useremul) Line 787  X(swi_useremul)
787          } else if (cpu->pc != old_pc) {          } else if (cpu->pc != old_pc) {
788                  /*  PC was changed by the SWI call. Find the new physical                  /*  PC was changed by the SWI call. Find the new physical
789                      page and update the translation pointers:  */                      page and update the translation pointers:  */
790                  arm_pc_to_pointers(cpu);                  quick_pc_to_pointers(cpu);
791          }          }
792  }  }
793  Y(swi_useremul)  Y(swi_useremul)
# Line 792  extern void (*arm_load_store_instr[1024] Line 879  extern void (*arm_load_store_instr[1024]
879          struct arm_instr_call *);          struct arm_instr_call *);
880  X(store_w0_byte_u1_p0_imm);  X(store_w0_byte_u1_p0_imm);
881  X(store_w0_word_u1_p0_imm);  X(store_w0_word_u1_p0_imm);
882    X(load_w0_word_u1_p0_imm);
883    X(load_w0_byte_u1_p1_imm);
884    X(load_w0_byte_u1_p1_reg);
885    
886  extern void (*arm_load_store_instr_pc[1024])(struct cpu *,  extern void (*arm_load_store_instr_pc[1024])(struct cpu *,
887          struct arm_instr_call *);          struct arm_instr_call *);
# Line 808  extern void (*arm_dpi_instr[2 * 2 * 2 * Line 898  extern void (*arm_dpi_instr[2 * 2 * 2 *
898          struct arm_instr_call *);          struct arm_instr_call *);
899  X(cmps);  X(cmps);
900  X(sub);  X(sub);
901    X(add);
902  X(subs);  X(subs);
903    
904    
# Line 832  X(bdt_load) Line 923  X(bdt_load)
923          int i, return_flag = 0;          int i, return_flag = 0;
924          uint32_t new_values[16];          uint32_t new_values[16];
925    
926    #ifdef GATHER_BDT_STATISTICS
927            if (!s_bit)
928                    update_bdt_statistics(iw);
929    #endif
930    
931          /*  Synchronize the program counter:  */          /*  Synchronize the program counter:  */
932          low_pc = ((size_t)ic - (size_t)          low_pc = ((size_t)ic - (size_t)
933              cpu->cd.arm.cur_ic_page) / sizeof(struct arm_instr_call);              cpu->cd.arm.cur_ic_page) / sizeof(struct arm_instr_call);
# Line 990  X(bdt_load) Line 1086  X(bdt_load)
1086                      same page!  */                      same page!  */
1087                  /*  Find the new physical page and update the                  /*  Find the new physical page and update the
1088                      translation pointers:  */                      translation pointers:  */
1089                  arm_pc_to_pointers(cpu);                  quick_pc_to_pointers(cpu);
1090          }          }
1091  }  }
1092  Y(bdt_load)  Y(bdt_load)
# Line 1015  X(bdt_store) Line 1111  X(bdt_store)
1111          int w_bit = iw & 0x00200000;          int w_bit = iw & 0x00200000;
1112          int i;          int i;
1113    
1114    #ifdef GATHER_BDT_STATISTICS
1115            if (!s_bit)
1116                    update_bdt_statistics(iw);
1117    #endif
1118    
1119          /*  Synchronize the program counter:  */          /*  Synchronize the program counter:  */
1120          low_pc = ((size_t)ic - (size_t)          low_pc = ((size_t)ic - (size_t)
1121              cpu->cd.arm.cur_ic_page) / sizeof(struct arm_instr_call);              cpu->cd.arm.cur_ic_page) / sizeof(struct arm_instr_call);
# Line 1108  X(bdt_store) Line 1209  X(bdt_store)
1209  Y(bdt_store)  Y(bdt_store)
1210    
1211    
1212    /*  Various load/store multiple instructions:  */
1213    #include "tmp_arm_multi.c"
1214    
1215    
1216  /*****************************************************************************/  /*****************************************************************************/
1217    
1218    
# Line 1256  restart_loop: Line 1361  restart_loop:
1361  }  }
1362    
1363    
1364    /*
1365     *  netbsd_memset:
1366     *
1367     *  The core of a NetBSD/arm memset.
1368     *
1369     *  f01bc420:  e25XX080     subs    rX,rX,#0x80
1370     *  f01bc424:  a8ac000c     stmgeia ip!,{r2,r3}   (16 of these)
1371     *  ..
1372     *  f01bc464:  caffffed     bgt     0xf01bc420      <memset+0x38>
1373     */
1374    X(netbsd_memset)
1375    {
1376            unsigned char *page;
1377            uint32_t addr;
1378    
1379            do {
1380                    addr = cpu->cd.arm.r[ARM_IP];
1381    
1382                    instr(subs)(cpu, ic);
1383    
1384                    if (((cpu->cd.arm.cpsr & ARM_FLAG_N)?1:0) !=
1385                        ((cpu->cd.arm.cpsr & ARM_FLAG_V)?1:0)) {
1386                            cpu->n_translated_instrs += 16;
1387                            /*  Skip the store multiples:  */
1388                            cpu->cd.arm.next_ic = &ic[17];
1389                            return;
1390                    }
1391    
1392                    /*  Crossing a page boundary? Then continue non-combined.  */
1393                    if ((addr & 0xfff) + 128 > 0x1000)
1394                            return;
1395    
1396                    /*  R2/R3 non-zero? Not allowed here.  */
1397                    if (cpu->cd.arm.r[2] != 0 || cpu->cd.arm.r[3] != 0)
1398                            return;
1399    
1400                    /*  printf("addr = 0x%08x\n", addr);  */
1401    
1402                    page = cpu->cd.arm.host_store[addr >> 12];
1403                    /*  No page translation? Continue non-combined.  */
1404                    if (page == NULL)
1405                            return;
1406    
1407                    /*  Clear:  */
1408                    memset(page + (addr & 0xfff), 0, 128);
1409                    cpu->cd.arm.r[ARM_IP] = addr + 128;
1410                    cpu->n_translated_instrs += 16;
1411    
1412                    /*  Branch back if greater:  */
1413                    cpu->n_translated_instrs += 1;
1414            } while (((cpu->cd.arm.cpsr & ARM_FLAG_N)?1:0) ==
1415                ((cpu->cd.arm.cpsr & ARM_FLAG_V)?1:0) &&
1416                !(cpu->cd.arm.cpsr & ARM_FLAG_Z));
1417    
1418            /*  Continue at the instruction after the bgt:  */
1419            cpu->cd.arm.next_ic = &ic[18];
1420    }
1421    
1422    
1423    /*
1424     *  netbsd_memcpy:
1425     *
1426     *  The core of a NetBSD/arm memcpy.
1427     *
1428     *  f01bc530:  e8b15018     ldmia   r1!,{r3,r4,ip,lr}
1429     *  f01bc534:  e8a05018     stmia   r0!,{r3,r4,ip,lr}
1430     *  f01bc538:  e8b15018     ldmia   r1!,{r3,r4,ip,lr}
1431     *  f01bc53c:  e8a05018     stmia   r0!,{r3,r4,ip,lr}
1432     *  f01bc540:  e2522020     subs    r2,r2,#0x20
1433     *  f01bc544:  aafffff9     bge     0xf01bc530
1434     */
1435    X(netbsd_memcpy)
1436    {
1437            unsigned char *page_0, *page_1;
1438            uint32_t addr_r0, addr_r1;
1439    
1440            do {
1441                    addr_r0 = cpu->cd.arm.r[0];
1442                    addr_r1 = cpu->cd.arm.r[1];
1443    
1444                    /*  printf("addr_r0 = %08x  r1 = %08x\n", addr_r0, addr_r1);  */
1445    
1446                    /*  Crossing a page boundary? Then continue non-combined.  */
1447                    if ((addr_r0 & 0xfff) + 32 > 0x1000 ||
1448                        (addr_r1 & 0xfff) + 32 > 0x1000) {
1449                            instr(multi_0x08b15018)(cpu, ic);
1450                            return;
1451                    }
1452    
1453                    page_0 = cpu->cd.arm.host_store[addr_r0 >> 12];
1454                    page_1 = cpu->cd.arm.host_store[addr_r1 >> 12];
1455    
1456                    /*  No page translations? Continue non-combined.  */
1457                    if (page_0 == NULL || page_1 == NULL) {
1458                            instr(multi_0x08b15018)(cpu, ic);
1459                            return;
1460                    }
1461    
1462                    memcpy(page_0 + (addr_r0 & 0xfff),
1463                        page_1 + (addr_r1 & 0xfff), 32);
1464                    cpu->cd.arm.r[0] = addr_r0 + 32;
1465                    cpu->cd.arm.r[1] = addr_r1 + 32;
1466    
1467                    cpu->n_translated_instrs += 4;
1468    
1469                    instr(subs)(cpu, ic + 4);
1470                    cpu->n_translated_instrs ++;
1471    
1472                    /*  Loop while greater or equal:  */
1473                    cpu->n_translated_instrs ++;
1474            } while (((cpu->cd.arm.cpsr & ARM_FLAG_N)?1:0) ==
1475                ((cpu->cd.arm.cpsr & ARM_FLAG_V)?1:0));
1476    
1477            /*  Continue at the instruction after the bge:  */
1478            cpu->cd.arm.next_ic = &ic[6];
1479            cpu->n_translated_instrs --;
1480    }
1481    
1482    
1483    /*
1484     *  netbsd_cacheclean:
1485     *
1486     *  The core of a NetBSD/arm cache clean routine, variant 1:
1487     *
1488     *  f015f88c:  e4902020     ldr     r2,[r0],#32
1489     *  f015f890:  e2511020     subs    r1,r1,#0x20
1490     *  f015f894:  1afffffc     bne     0xf015f88c
1491     *  f015f898:  ee070f9a     mcr     15,0,r0,cr7,cr10,4
1492     */
1493    X(netbsd_cacheclean)
1494    {
1495            uint32_t r1 = cpu->cd.arm.r[1];
1496            cpu->n_translated_instrs += ((r1 >> 5) * 3);
1497            cpu->cd.arm.next_ic = &ic[4];
1498    }
1499    
1500    
1501    /*
1502     *  netbsd_cacheclean2:
1503     *
1504     *  The core of a NetBSD/arm cache clean routine, variant 2:
1505     *
1506     *  f015f93c:  ee070f3a     mcr     15,0,r0,cr7,cr10,1
1507     *  f015f940:  ee070f36     mcr     15,0,r0,cr7,cr6,1
1508     *  f015f944:  e2800020     add     r0,r0,#0x20
1509     *  f015f948:  e2511020     subs    r1,r1,#0x20
1510     *  f015f94c:  8afffffa     bhi     0xf015f93c
1511     */
1512    X(netbsd_cacheclean2)
1513    {
1514            cpu->n_translated_instrs += ((cpu->cd.arm.r[1] >> 5) * 5) - 1;
1515            cpu->cd.arm.next_ic = &ic[5];
1516    }
1517    
1518    
1519    /*
1520     *  netbsd_scanc:
1521     *
1522     *  f01bccbc:  e5d13000     ldrb    r3,[r1]
1523     *  f01bccc0:  e7d23003     ldrb    r3,[r2,r3]
1524     *  f01bccc4:  e113000c     tsts    r3,ip
1525     */
1526    X(netbsd_scanc)
1527    {
1528            unsigned char *page = cpu->cd.arm.host_load[cpu->cd.arm.r[1] >> 12];
1529            uint32_t t;
1530    
1531            if (page == NULL) {
1532                    instr(load_w0_byte_u1_p1_imm)(cpu, ic);
1533                    return;
1534            }
1535    
1536            t = page[cpu->cd.arm.r[1] & 0xfff];
1537            t += cpu->cd.arm.r[2];
1538            page = cpu->cd.arm.host_load[t >> 12];
1539    
1540            if (page == NULL) {
1541                    instr(load_w0_byte_u1_p1_imm)(cpu, ic);
1542                    return;
1543            }
1544    
1545            cpu->cd.arm.r[3] = page[t & 0xfff];
1546    
1547            t = cpu->cd.arm.r[3] & cpu->cd.arm.r[ARM_IP];
1548            cpu->cd.arm.cpsr &= ~(ARM_FLAG_Z | ARM_FLAG_N);
1549            if (t == 0)
1550                    cpu->cd.arm.cpsr |= ARM_FLAG_Z;
1551    
1552            cpu->n_translated_instrs += 2;
1553            cpu->cd.arm.next_ic = &ic[3];
1554    }
1555    
1556    
1557  /*****************************************************************************/  /*****************************************************************************/
1558    
1559    
# Line 1269  X(end_of_page) Line 1567  X(end_of_page)
1567          cpu->pc = cpu->cd.arm.r[ARM_PC];          cpu->pc = cpu->cd.arm.r[ARM_PC];
1568    
1569          /*  Find the new physical page and update the translation pointers:  */          /*  Find the new physical page and update the translation pointers:  */
1570          arm_pc_to_pointers(cpu);          quick_pc_to_pointers(cpu);
1571    
1572          /*  end_of_page doesn't count as an executed instruction:  */          /*  end_of_page doesn't count as an executed instruction:  */
1573          cpu->n_translated_instrs --;          cpu->n_translated_instrs --;
# Line 1280  X(end_of_page) Line 1578  X(end_of_page)
1578    
1579    
1580  /*  /*
1581   *  arm_combine_instructions():   *  arm_combine_netbsd_memset():
1582     *
1583     *  Check for the core of a NetBSD/arm memset; large memsets use a sequence
1584     *  of 16 store-multiple instructions, each storing 2 registers at a time.
1585     */
1586    void arm_combine_netbsd_memset(struct cpu *cpu, struct arm_instr_call *ic,
1587            int low_addr)
1588    {
1589            int n_back = (low_addr >> ARM_INSTR_ALIGNMENT_SHIFT)
1590                & (ARM_IC_ENTRIES_PER_PAGE-1);
1591    
1592            if (n_back >= 17) {
1593                    int i;
1594                    for (i=-16; i<=-1; i++)
1595                            if (ic[i].f != instr(multi_0x08ac000c__ge))
1596                                    return;
1597                    if (ic[-17].f == instr(subs) &&
1598                        ic[-17].arg[0]==ic[-17].arg[2] && ic[-17].arg[1] == 128 &&
1599                        ic[ 0].f == instr(b_samepage__gt) &&
1600                        ic[ 0].arg[0] == (size_t)&ic[-17]) {
1601                            ic[-17].f = instr(netbsd_memset);
1602                            combined;
1603                    }
1604            }
1605    }
1606    
1607    
1608    /*
1609     *  arm_combine_netbsd_memcpy():
1610     *
1611     *  Check for the core of a NetBSD/arm memcpy; large memcpys use a
1612     *  sequence of ldmia instructions.
1613     */
1614    void arm_combine_netbsd_memcpy(struct cpu *cpu, struct arm_instr_call *ic,
1615            int low_addr)
1616    {
1617            int n_back = (low_addr >> ARM_INSTR_ALIGNMENT_SHIFT)
1618                & (ARM_IC_ENTRIES_PER_PAGE-1);
1619    
1620            if (n_back >= 5) {
1621                    if (ic[-5].f==instr(multi_0x08b15018) &&
1622                        ic[-4].f==instr(multi_0x08a05018) &&
1623                        ic[-3].f==instr(multi_0x08b15018) &&
1624                        ic[-2].f==instr(multi_0x08a05018) &&
1625                        ic[-1].f == instr(subs) &&
1626                        ic[-1].arg[0]==ic[-1].arg[2] && ic[-1].arg[1] == 0x20 &&
1627                        ic[ 0].f == instr(b_samepage__ge) &&
1628                        ic[ 0].arg[0] == (size_t)&ic[-5]) {
1629                            ic[-5].f = instr(netbsd_memcpy);
1630                            combined;
1631                    }
1632            }
1633    }
1634    
1635    
1636    /*
1637     *  arm_combine_netbsd_cacheclean():
1638     *
1639     *  Check for the core of a NetBSD/arm cache clean. (There are two variants.)
1640     */
1641    void arm_combine_netbsd_cacheclean(struct cpu *cpu, struct arm_instr_call *ic,
1642            int low_addr)
1643    {
1644            int n_back = (low_addr >> ARM_INSTR_ALIGNMENT_SHIFT)
1645                & (ARM_IC_ENTRIES_PER_PAGE-1);
1646    
1647            if (n_back >= 3) {
1648                    if (ic[-3].f==instr(load_w0_word_u1_p0_imm) &&
1649                        ic[-2].f == instr(subs) &&
1650                        ic[-2].arg[0]==ic[-2].arg[2] && ic[-2].arg[1] == 0x20 &&
1651                        ic[-1].f == instr(b_samepage__ne) &&
1652                        ic[-1].arg[0] == (size_t)&ic[-3]) {
1653                            ic[-3].f = instr(netbsd_cacheclean);
1654                            combined;
1655                    }
1656            }
1657    }
1658    
1659    
1660    /*
1661     *  arm_combine_netbsd_cacheclean2():
1662   *   *
1663   *  Combine two or more instructions, if possible, into a single function call.   *  Check for the core of a NetBSD/arm cache clean. (Second variant.)
1664   */   */
1665  void arm_combine_instructions(struct cpu *cpu, struct arm_instr_call *ic,  void arm_combine_netbsd_cacheclean2(struct cpu *cpu, struct arm_instr_call *ic,
1666          uint32_t addr)          int low_addr)
1667  {  {
1668          int n_back;          int n_back = (low_addr >> ARM_INSTR_ALIGNMENT_SHIFT)
1669          n_back = (addr >> ARM_INSTR_ALIGNMENT_SHIFT)              & (ARM_IC_ENTRIES_PER_PAGE-1);
1670    
1671            if (n_back >= 4) {
1672                    if (ic[-4].f == instr(mcr_mrc) && ic[-4].arg[0] == 0xee070f3a &&
1673                        ic[-3].f == instr(mcr_mrc) && ic[-3].arg[0] == 0xee070f36 &&
1674                        ic[-2].f == instr(add) &&
1675                        ic[-2].arg[0]==ic[-2].arg[2] && ic[-2].arg[1] == 0x20 &&
1676                        ic[-1].f == instr(subs) &&
1677                        ic[-1].arg[0]==ic[-1].arg[2] && ic[-1].arg[1] == 0x20) {
1678                            ic[-4].f = instr(netbsd_cacheclean2);
1679                            combined;
1680                    }
1681            }
1682    }
1683    
1684    
1685    /*
1686     *  arm_combine_netbsd_scanc():
1687     */
1688    void arm_combine_netbsd_scanc(struct cpu *cpu, struct arm_instr_call *ic,
1689            int low_addr)
1690    {
1691            int n_back = (low_addr >> ARM_INSTR_ALIGNMENT_SHIFT)
1692                & (ARM_IC_ENTRIES_PER_PAGE-1);
1693    
1694            if (n_back >= 2) {
1695                    if (ic[-2].f == instr(load_w0_byte_u1_p1_imm) &&
1696                        ic[-1].f == instr(load_w0_byte_u1_p1_reg)) {
1697                            ic[-2].f = instr(netbsd_scanc);
1698                            combined;
1699                    }
1700            }
1701    }
1702    
1703    
1704    /*
1705     *  arm_combine_test2():
1706     */
1707    void arm_combine_test2(struct cpu *cpu, struct arm_instr_call *ic, int low_addr)
1708    {
1709            int n_back = (low_addr >> ARM_INSTR_ALIGNMENT_SHIFT)
1710              & (ARM_IC_ENTRIES_PER_PAGE-1);              & (ARM_IC_ENTRIES_PER_PAGE-1);
1711    
1712          if (n_back >= 2) {          if (n_back >= 2) {
# Line 1299  void arm_combine_instructions(struct cpu Line 1717  void arm_combine_instructions(struct cpu
1717                      ic[ 0].f == instr(b_samepage__gt) &&                      ic[ 0].f == instr(b_samepage__gt) &&
1718                      ic[ 0].arg[0] == (size_t)&ic[-2]) {                      ic[ 0].arg[0] == (size_t)&ic[-2]) {
1719                          ic[-2].f = instr(fill_loop_test2);                          ic[-2].f = instr(fill_loop_test2);
1720    printf("YO test2\n");
1721                          combined;                          combined;
1722                  }                  }
1723          }          }
1724    }
1725    
1726    
1727    #if 0
1728            /*  TODO: This is another test hack.  */
1729    
1730          if (n_back >= 3) {          if (n_back >= 3) {
1731                  if (ic[-3].f == instr(cmps) &&                  if (ic[-3].f == instr(cmps) &&
# Line 1317  void arm_combine_instructions(struct cpu Line 1741  void arm_combine_instructions(struct cpu
1741                          combined;                          combined;
1742                  }                  }
1743          }          }
   
1744          /*  TODO: Combine forward as well  */          /*  TODO: Combine forward as well  */
1745  }  #endif
1746    
1747    
1748  /*****************************************************************************/  /*****************************************************************************/
# Line 1339  X(to_be_translated) Line 1762  X(to_be_translated)
1762          unsigned char *page;          unsigned char *page;
1763          unsigned char ib[4];          unsigned char ib[4];
1764          int condition_code, main_opcode, secondary_opcode, s_bit, rn, rd, r8;          int condition_code, main_opcode, secondary_opcode, s_bit, rn, rd, r8;
1765          int p_bit, u_bit, b_bit, w_bit, l_bit, regform, rm, c, t;          int p_bit, u_bit, b_bit, w_bit, l_bit, regform, rm, c, t, any_pc_reg;
         int any_pc_reg;  
1766          void (*samepage_function)(struct cpu *, struct arm_instr_call *);          void (*samepage_function)(struct cpu *, struct arm_instr_call *);
1767    
1768          /*  Figure out the address of the instruction:  */          /*  Figure out the address of the instruction:  */
# Line 1363  X(to_be_translated) Line 1785  X(to_be_translated)
1785                      sizeof(ib), MEM_READ, CACHE_INSTRUCTION)) {                      sizeof(ib), MEM_READ, CACHE_INSTRUCTION)) {
1786                          fatal("to_be_translated(): "                          fatal("to_be_translated(): "
1787                              "read failed: TODO\n");                              "read failed: TODO\n");
1788                          goto bad;                          return;
1789                  }                  }
1790          }          }
1791    
# Line 1561  X(to_be_translated) Line 1983  X(to_be_translated)
1983                          goto bad;                          goto bad;
1984                  }                  }
1985    
1986                  /*  "mov pc,lr" with trace enabled:  */                  /*  "mov pc,lr":  */
1987                  if ((iword & 0x0fffffff) == 0x01a0f00e &&                  if ((iword & 0x0fffffff) == 0x01a0f00e) {
1988                      cpu->machine->show_trace_tree) {                          if (cpu->machine->show_trace_tree)
1989                          ic->f = cond_instr(ret_trace);                                  ic->f = cond_instr(ret_trace);
1990                            else
1991                                    ic->f = cond_instr(ret);
1992                          break;                          break;
1993                  }                  }
1994    
# Line 1577  X(to_be_translated) Line 2001  X(to_be_translated)
2001                          break;                          break;
2002                  }                  }
2003    
2004                    /*  "mov reg,#0":  */
2005                    if ((iword & 0x0fff0fff) == 0x03a03000 && rd != ARM_PC) {
2006                            switch (rd) {
2007                            case  0: ic->f = cond_instr(clear_r0); break;
2008                            case  1: ic->f = cond_instr(clear_r1); break;
2009                            case  2: ic->f = cond_instr(clear_r2); break;
2010                            case  3: ic->f = cond_instr(clear_r3); break;
2011                            case  4: ic->f = cond_instr(clear_r4); break;
2012                            case  5: ic->f = cond_instr(clear_r5); break;
2013                            case  6: ic->f = cond_instr(clear_r6); break;
2014                            case  7: ic->f = cond_instr(clear_r7); break;
2015                            case  8: ic->f = cond_instr(clear_r8); break;
2016                            case  9: ic->f = cond_instr(clear_r9); break;
2017                            case 10: ic->f = cond_instr(clear_r10); break;
2018                            case 11: ic->f = cond_instr(clear_r11); break;
2019                            case 12: ic->f = cond_instr(clear_r12); break;
2020                            case 13: ic->f = cond_instr(clear_r13); break;
2021                            case 14: ic->f = cond_instr(clear_r14); break;
2022                            }
2023                            break;
2024                    }
2025    
2026                    /*  "mov reg,#1":  */
2027                    if ((iword & 0x0fff0fff) == 0x03a03001 && rd != ARM_PC) {
2028                            switch (rd) {
2029                            case  0: ic->f = cond_instr(mov1_r0); break;
2030                            case  1: ic->f = cond_instr(mov1_r1); break;
2031                            case  2: ic->f = cond_instr(mov1_r2); break;
2032                            case  3: ic->f = cond_instr(mov1_r3); break;
2033                            case  4: ic->f = cond_instr(mov1_r4); break;
2034                            case  5: ic->f = cond_instr(mov1_r5); break;
2035                            case  6: ic->f = cond_instr(mov1_r6); break;
2036                            case  7: ic->f = cond_instr(mov1_r7); break;
2037                            case  8: ic->f = cond_instr(mov1_r8); break;
2038                            case  9: ic->f = cond_instr(mov1_r9); break;
2039                            case 10: ic->f = cond_instr(mov1_r10); break;
2040                            case 11: ic->f = cond_instr(mov1_r11); break;
2041                            case 12: ic->f = cond_instr(mov1_r12); break;
2042                            case 13: ic->f = cond_instr(mov1_r13); break;
2043                            case 14: ic->f = cond_instr(mov1_r14); break;
2044                            }
2045                            break;
2046                    }
2047    
2048                  /*                  /*
2049                   *  Generic Data Processing Instructions:                   *  Generic Data Processing Instructions:
2050                   */                   */
# Line 1613  X(to_be_translated) Line 2081  X(to_be_translated)
2081                  ic->f = arm_dpi_instr[condition_code +                  ic->f = arm_dpi_instr[condition_code +
2082                      16 * secondary_opcode + (s_bit? 256 : 0) +                      16 * secondary_opcode + (s_bit? 256 : 0) +
2083                      (any_pc_reg? 512 : 0) + (regform? 1024 : 0)];                      (any_pc_reg? 512 : 0) + (regform? 1024 : 0)];
2084    
2085                    if (iword == 0xe113000c)
2086                            cpu->combination_check = arm_combine_netbsd_scanc;
2087                  break;                  break;
2088    
2089          case 0x4:       /*  Load and store...  */          case 0x4:       /*  Load and store...  */
# Line 1645  X(to_be_translated) Line 2116  X(to_be_translated)
2116    
2117          case 0x8:       /*  Multiple load/store...  (Block data transfer)  */          case 0x8:       /*  Multiple load/store...  (Block data transfer)  */
2118          case 0x9:       /*  xxxx100P USWLnnnn llllllll llllllll  */          case 0x9:       /*  xxxx100P USWLnnnn llllllll llllllll  */
2119                    ic->arg[0] = (size_t)(&cpu->cd.arm.r[rn]);
2120                    ic->arg[1] = (size_t)iword;
2121                    /*  Generic case:  */
2122                  if (l_bit)                  if (l_bit)
2123                          ic->f = cond_instr(bdt_load);                          ic->f = cond_instr(bdt_load);
2124                  else                  else
2125                          ic->f = cond_instr(bdt_store);                          ic->f = cond_instr(bdt_store);
2126                  ic->arg[0] = (size_t)(&cpu->cd.arm.r[rn]);  #if defined(HOST_LITTLE_ENDIAN) && !defined(GATHER_BDT_STATISTICS)
2127                  ic->arg[1] = (size_t)iword;                  /*
2128                     *  Check for availability of optimized implementation:
2129                     *  xxxx100P USWLnnnn llllllll llllllll
2130                     *           ^  ^ ^ ^        ^  ^ ^ ^   (0x00950154)
2131                     *  These bits are used to select which list to scan, and then
2132                     *  the list is scanned linearly.
2133                     *
2134                     *  The optimized functions do not support show_trace_tree,
2135                     *  but it's ok to use the unoptimized version in that case.
2136                     */
2137                    if (!cpu->machine->show_trace_tree) {
2138                            int i = 0, j = iword;
2139                            j = ((j & 0x00800000) >> 16) | ((j & 0x00100000) >> 14)
2140                              | ((j & 0x00040000) >> 13) | ((j & 0x00010000) >> 12)
2141                              | ((j & 0x00000100) >>  5) | ((j & 0x00000040) >>  4)
2142                              | ((j & 0x00000010) >>  3) | ((j & 0x00000004) >>  2);
2143                            while (multi_opcode[j][i] != 0) {
2144                                    if ((iword & 0x0fffffff) ==
2145                                        multi_opcode[j][i]) {
2146                                            ic->f = multi_opcode_f[j]
2147                                                [i*16 + condition_code];
2148                                            break;
2149                                    }
2150                                    i ++;
2151                            }
2152                    }
2153    #endif
2154                  if (rn == ARM_PC) {                  if (rn == ARM_PC) {
2155                          fatal("TODO: bdt with PC as base\n");                          fatal("TODO: bdt with PC as base\n");
2156                          goto bad;                          goto bad;
# Line 1662  X(to_be_translated) Line 2162  X(to_be_translated)
2162                  if (main_opcode == 0x0a) {                  if (main_opcode == 0x0a) {
2163                          ic->f = cond_instr(b);                          ic->f = cond_instr(b);
2164                          samepage_function = cond_instr(b_samepage);                          samepage_function = cond_instr(b_samepage);
2165                            /*  if (iword == 0xcafffffc)
2166                                    cpu->combination_check = arm_combine_test2;  */
2167                            if (iword == 0xcaffffed)
2168                                    cpu->combination_check =
2169                                        arm_combine_netbsd_memset;
2170                            if (iword == 0xaafffff9)
2171                                    cpu->combination_check =
2172                                        arm_combine_netbsd_memcpy;
2173                  } else {                  } else {
2174                          if (cpu->machine->show_trace_tree) {                          if (cpu->machine->show_trace_tree) {
2175                                  ic->f = cond_instr(bl_trace);                                  ic->f = cond_instr(bl_trace);
# Line 1699  X(to_be_translated) Line 2207  X(to_be_translated)
2207                                      ARM_INSTR_ALIGNMENT_SHIFT));                                      ARM_INSTR_ALIGNMENT_SHIFT));
2208                          }                          }
2209                  }                  }
2210    
2211    #if 0
2212                    /*  Hm. This doesn't really increase performance.  */
2213                    if (iword == 0x8afffffa)
2214                            cpu->combination_check = arm_combine_netbsd_cacheclean2;
2215    #endif
2216                  break;                  break;
2217    
2218          case 0xe:          case 0xe:
# Line 1711  X(to_be_translated) Line 2225  X(to_be_translated)
2225                          ic->arg[0] = iword;                          ic->arg[0] = iword;
2226                          ic->f = cond_instr(cdp);                          ic->f = cond_instr(cdp);
2227                  }                  }
2228                    if (iword == 0xee070f9a)
2229                            cpu->combination_check = arm_combine_netbsd_cacheclean;
2230                  break;                  break;
2231    
2232          case 0xf:          case 0xf:

Legend:
Removed from v.17  
changed lines
  Added in v.18

  ViewVC Help
Powered by ViewVC 1.1.26