/[qemu]/qemu/target-arm/translate.c
ViewVC logotype

Diff of /qemu/target-arm/translate.c

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

revision 1.17 by bellard, Mon Feb 7 23:10:07 2005 UTC revision 1.18 by bellard, Tue Feb 22 19:27:29 2005 UTC
# Line 2  Line 2 
2   *  ARM translation   *  ARM translation
3   *   *
4   *  Copyright (c) 2003 Fabrice Bellard   *  Copyright (c) 2003 Fabrice Bellard
5     *  Copyright (c) 2005 CodeSourcery, LLC
6   *   *
7   * This library is free software; you can redistribute it and/or   * This library is free software; you can redistribute it and/or
8   * modify it under the terms of the GNU Lesser General Public   * modify it under the terms of the GNU Lesser General Public
# Line 354  static inline void gen_add_datah_offset( Line 355  static inline void gen_add_datah_offset(
355      }      }
356  }  }
357    
358  static void disas_arm_insn(DisasContext *s)  #define VFP_OP(name)                      \
359    static inline void gen_vfp_##name(int dp) \
360    {                                         \
361        if (dp)                               \
362            gen_op_vfp_##name##d();           \
363        else                                  \
364            gen_op_vfp_##name##s();           \
365    }
366    
367    VFP_OP(add)
368    VFP_OP(sub)
369    VFP_OP(mul)
370    VFP_OP(div)
371    VFP_OP(neg)
372    VFP_OP(abs)
373    VFP_OP(sqrt)
374    VFP_OP(cmp)
375    VFP_OP(cmpe)
376    VFP_OP(F1_ld0)
377    VFP_OP(uito)
378    VFP_OP(sito)
379    VFP_OP(toui)
380    VFP_OP(touiz)
381    VFP_OP(tosi)
382    VFP_OP(tosiz)
383    VFP_OP(ld)
384    VFP_OP(st)
385    
386    #undef VFP_OP
387    
388    static inline void gen_mov_F0_vreg(int dp, int reg)
389    {
390        if (dp)
391            gen_op_vfp_getreg_F0d(offsetof(CPUARMState, vfp.regs.d[reg]));
392        else
393            gen_op_vfp_getreg_F0s(offsetof(CPUARMState, vfp.regs.s[reg]));
394    }
395    
396    static inline void gen_mov_F1_vreg(int dp, int reg)
397    {
398        if (dp)
399            gen_op_vfp_getreg_F1d(offsetof(CPUARMState, vfp.regs.d[reg]));
400        else
401            gen_op_vfp_getreg_F1s(offsetof(CPUARMState, vfp.regs.s[reg]));
402    }
403    
404    static inline void gen_mov_vreg_F0(int dp, int reg)
405    {
406        if (dp)
407            gen_op_vfp_setreg_F0d(offsetof(CPUARMState, vfp.regs.d[reg]));
408        else
409            gen_op_vfp_setreg_F0s(offsetof(CPUARMState, vfp.regs.s[reg]));
410    }
411    
412    /* Disassemble a VFP instruction.  Returns nonzero if an error occured
413       (ie. an undefined instruction).  */
414    static int disas_vfp_insn(CPUState * env, DisasContext *s, uint32_t insn)
415    {
416        uint32_t rd, rn, rm, op, i, n, offset, delta_d, delta_m, bank_mask;
417        int dp, veclen;
418    
419        dp = ((insn & 0xf00) == 0xb00);
420        switch ((insn >> 24) & 0xf) {
421        case 0xe:
422            if (insn & (1 << 4)) {
423                /* single register transfer */
424                if ((insn & 0x6f) != 0x00)
425                    return 1;
426                rd = (insn >> 12) & 0xf;
427                if (dp) {
428                    if (insn & 0x80)
429                        return 1;
430                    rn = (insn >> 16) & 0xf;
431                    /* Get the existing value even for arm->vfp moves because
432                       we only set half the register.  */
433                    gen_mov_F0_vreg(1, rn);
434                    gen_op_vfp_mrrd();
435                    if (insn & (1 << 20)) {
436                        /* vfp->arm */
437                        if (insn & (1 << 21))
438                            gen_movl_reg_T1(s, rd);
439                        else
440                            gen_movl_reg_T0(s, rd);
441                    } else {
442                        /* arm->vfp */
443                        if (insn & (1 << 21))
444                            gen_movl_T1_reg(s, rd);
445                        else
446                            gen_movl_T0_reg(s, rd);
447                        gen_op_vfp_mdrr();
448                        gen_mov_vreg_F0(dp, rn);
449                    }
450                } else {
451                    rn = ((insn >> 15) & 0x1e) | ((insn >> 7) & 1);
452                    if (insn & (1 << 20)) {
453                        /* vfp->arm */
454                        if (insn & (1 << 21)) {
455                            /* system register */
456                            switch (rn) {
457                            case 0: /* fpsid */
458                                n = 0x0091A0000;
459                                break;
460                            case 2: /* fpscr */
461                                if (rd == 15)
462                                    gen_op_vfp_movl_T0_fpscr_flags();
463                                else
464                                    gen_op_vfp_movl_T0_fpscr();
465                                break;
466                            default:
467                                return 1;
468                            }
469                        } else {
470                            gen_mov_F0_vreg(0, rn);
471                            gen_op_vfp_mrs();
472                        }
473                        if (rd == 15) {
474                            /* This will only set the 4 flag bits */
475                            gen_op_movl_psr_T0();
476                        } else
477                            gen_movl_reg_T0(s, rd);
478                    } else {
479                        /* arm->vfp */
480                        gen_movl_T0_reg(s, rd);
481                        if (insn & (1 << 21)) {
482                            /* system register */
483                            switch (rn) {
484                            case 0: /* fpsid */
485                                /* Writes are ignored.  */
486                                break;
487                            case 2: /* fpscr */
488                                gen_op_vfp_movl_fpscr_T0();
489                                /* This could change vector settings, so jump to
490                                   the next instuction.  */
491                                gen_op_movl_T0_im(s->pc);
492                                gen_movl_reg_T0(s, 15);
493                                s->is_jmp = DISAS_UPDATE;
494                                break;
495                            default:
496                                return 1;
497                            }
498                        } else {
499                            gen_op_vfp_msr();
500                            gen_mov_vreg_F0(0, rn);
501                        }
502                    }
503                }
504            } else {
505                /* data processing */
506                /* The opcode is in bits 23, 21, 20 and 6.  */
507                op = ((insn >> 20) & 8) | ((insn >> 19) & 6) | ((insn >> 6) & 1);
508                if (dp) {
509                    if (op == 15) {
510                        /* rn is opcode */
511                        rn = ((insn >> 15) & 0x1e) | ((insn >> 7) & 1);
512                    } else {
513                        /* rn is register number */
514                        if (insn & (1 << 7))
515                            return 1;
516                        rn = (insn >> 16) & 0xf;
517                    }
518    
519                    if (op == 15 && (rn == 15 || rn > 17)) {
520                        /* Integer or single precision destination.  */
521                        rd = ((insn >> 11) & 0x1e) | ((insn >> 22) & 1);
522                    } else {
523                        if (insn & (1 << 22))
524                            return 1;
525                        rd = (insn >> 12) & 0xf;
526                    }
527    
528                    if (op == 15 && (rn == 16 || rn == 17)) {
529                        /* Integer source.  */
530                        rm = ((insn << 1) & 0x1e) | ((insn >> 5) & 1);
531                    } else {
532                        if (insn & (1 << 5))
533                            return 1;
534                        rm = insn & 0xf;
535                    }
536                } else {
537                    rn = ((insn >> 15) & 0x1e) | ((insn >> 7) & 1);
538                    if (op == 15 && rn == 15) {
539                        /* Double precision destination.  */
540                        if (insn & (1 << 22))
541                            return 1;
542                        rd = (insn >> 12) & 0xf;
543                    } else
544                        rd = ((insn >> 11) & 0x1e) | ((insn >> 22) & 1);
545                    rm = ((insn << 1) & 0x1e) | ((insn >> 5) & 1);
546                }
547    
548                veclen = env->vfp.vec_len;
549                if (op == 15 && rn > 3)
550                    veclen = 0;
551    
552                /* Shut up compiler warnings.  */
553                delta_m = 0;
554                delta_d = 0;
555                bank_mask = 0;
556                
557                if (veclen > 0) {
558                    if (dp)
559                        bank_mask = 0xc;
560                    else
561                        bank_mask = 0x18;
562    
563                    /* Figure out what type of vector operation this is.  */
564                    if ((rd & bank_mask) == 0) {
565                        /* scalar */
566                        veclen = 0;
567                    } else {
568                        if (dp)
569                            delta_d = (env->vfp.vec_stride >> 1) + 1;
570                        else
571                            delta_d = env->vfp.vec_stride + 1;
572    
573                        if ((rm & bank_mask) == 0) {
574                            /* mixed scalar/vector */
575                            delta_m = 0;
576                        } else {
577                            /* vector */
578                            delta_m = delta_d;
579                        }
580                    }
581                }
582    
583                /* Load the initial operands.  */
584                if (op == 15) {
585                    switch (rn) {
586                    case 16:
587                    case 17:
588                        /* Integer source */
589                        gen_mov_F0_vreg(0, rm);
590                        break;
591                    case 8:
592                    case 9:
593                        /* Compare */
594                        gen_mov_F0_vreg(dp, rd);
595                        gen_mov_F1_vreg(dp, rm);
596                        break;
597                    case 10:
598                    case 11:
599                        /* Compare with zero */
600                        gen_mov_F0_vreg(dp, rd);
601                        gen_vfp_F1_ld0(dp);
602                        break;
603                    default:
604                        /* One source operand.  */
605                        gen_mov_F0_vreg(dp, rm);
606                    }
607                } else {
608                    /* Two source operands.  */
609                    gen_mov_F0_vreg(dp, rn);
610                    gen_mov_F1_vreg(dp, rm);
611                }
612    
613                for (;;) {
614                    /* Perform the calculation.  */
615                    switch (op) {
616                    case 0: /* mac: fd + (fn * fm) */
617                        gen_vfp_mul(dp);
618                        gen_mov_F1_vreg(dp, rd);
619                        gen_vfp_add(dp);
620                        break;
621                    case 1: /* nmac: fd - (fn * fm) */
622                        gen_vfp_mul(dp);
623                        gen_vfp_neg(dp);
624                        gen_mov_F1_vreg(dp, rd);
625                        gen_vfp_add(dp);
626                        break;
627                    case 2: /* msc: -fd + (fn * fm) */
628                        gen_vfp_mul(dp);
629                        gen_mov_F1_vreg(dp, rd);
630                        gen_vfp_sub(dp);
631                        break;
632                    case 3: /* nmsc: -fd - (fn * fm)  */
633                        gen_vfp_mul(dp);
634                        gen_mov_F1_vreg(dp, rd);
635                        gen_vfp_add(dp);
636                        gen_vfp_neg(dp);
637                        break;
638                    case 4: /* mul: fn * fm */
639                        gen_vfp_mul(dp);
640                        break;
641                    case 5: /* nmul: -(fn * fm) */
642                        gen_vfp_mul(dp);
643                        gen_vfp_neg(dp);
644                        break;
645                    case 6: /* add: fn + fm */
646                        gen_vfp_add(dp);
647                        break;
648                    case 7: /* sub: fn - fm */
649                        gen_vfp_sub(dp);
650                        break;
651                    case 8: /* div: fn / fm */
652                        gen_vfp_div(dp);
653                        break;
654                    case 15: /* extension space */
655                        switch (rn) {
656                        case 0: /* cpy */
657                            /* no-op */
658                            break;
659                        case 1: /* abs */
660                            gen_vfp_abs(dp);
661                            break;
662                        case 2: /* neg */
663                            gen_vfp_neg(dp);
664                            break;
665                        case 3: /* sqrt */
666                            gen_vfp_sqrt(dp);
667                            break;
668                        case 8: /* cmp */
669                            gen_vfp_cmp(dp);
670                            break;
671                        case 9: /* cmpe */
672                            gen_vfp_cmpe(dp);
673                            break;
674                        case 10: /* cmpz */
675                            gen_vfp_cmp(dp);
676                            break;
677                        case 11: /* cmpez */
678                            gen_vfp_F1_ld0(dp);
679                            gen_vfp_cmpe(dp);
680                            break;
681                        case 15: /* single<->double conversion */
682                            if (dp)
683                                gen_op_vfp_fcvtsd();
684                            else
685                                gen_op_vfp_fcvtds();
686                            break;
687                        case 16: /* fuito */
688                            gen_vfp_uito(dp);
689                            break;
690                        case 17: /* fsito */
691                            gen_vfp_sito(dp);
692                            break;
693                        case 24: /* ftoui */
694                            gen_vfp_toui(dp);
695                            break;
696                        case 25: /* ftouiz */
697                            gen_vfp_touiz(dp);
698                            break;
699                        case 26: /* ftosi */
700                            gen_vfp_tosi(dp);
701                            break;
702                        case 27: /* ftosiz */
703                            gen_vfp_tosiz(dp);
704                            break;
705                        default: /* undefined */
706                            printf ("rn:%d\n", rn);
707                            return 1;
708                        }
709                        break;
710                    default: /* undefined */
711                        printf ("op:%d\n", op);
712                        return 1;
713                    }
714    
715                    /* Write back the result.  */
716                    if (op == 15 && (rn >= 8 && rn <= 11))
717                        ; /* Comparison, do nothing.  */
718                    else if (op == 15 && rn > 17)
719                        /* Integer result.  */
720                        gen_mov_vreg_F0(0, rd);
721                    else if (op == 15 && rn == 15)
722                        /* conversion */
723                        gen_mov_vreg_F0(!dp, rd);
724                    else
725                        gen_mov_vreg_F0(dp, rd);
726    
727                    /* break out of the loop if we have finished  */
728                    if (veclen == 0)
729                        break;
730    
731                    if (op == 15 && delta_m == 0) {
732                        /* single source one-many */
733                        while (veclen--) {
734                            rd = ((rd + delta_d) & (bank_mask - 1))
735                                 | (rd & bank_mask);
736                            gen_mov_vreg_F0(dp, rd);
737                        }
738                        break;
739                    }
740                    /* Setup the next operands.  */
741                    veclen--;
742                    rd = ((rd + delta_d) & (bank_mask - 1))
743                         | (rd & bank_mask);
744    
745                    if (op == 15) {
746                        /* One source operand.  */
747                        rm = ((rm + delta_m) & (bank_mask - 1))
748                             | (rm & bank_mask);
749                        gen_mov_F0_vreg(dp, rm);
750                    } else {
751                        /* Two source operands.  */
752                        rn = ((rn + delta_d) & (bank_mask - 1))
753                             | (rn & bank_mask);
754                        gen_mov_F0_vreg(dp, rn);
755                        if (delta_m) {
756                            rm = ((rm + delta_m) & (bank_mask - 1))
757                                 | (rm & bank_mask);
758                            gen_mov_F1_vreg(dp, rm);
759                        }
760                    }
761                }
762            }
763            break;
764        case 0xc:
765        case 0xd:
766            if (dp && (insn & (1 << 22))) {
767                /* two-register transfer */
768                rn = (insn >> 16) & 0xf;
769                rd = (insn >> 12) & 0xf;
770                if (dp) {
771                    if (insn & (1 << 5))
772                        return 1;
773                    rm = insn & 0xf;
774                } else
775                    rm = ((insn << 1) & 0x1e) | ((insn >> 5) & 1);
776    
777                if (insn & (1 << 20)) {
778                    /* vfp->arm */
779                    if (dp) {
780                        gen_mov_F0_vreg(1, rm);
781                        gen_op_vfp_mrrd();
782                        gen_movl_reg_T0(s, rd);
783                        gen_movl_reg_T1(s, rn);
784                    } else {
785                        gen_mov_F0_vreg(0, rm);
786                        gen_op_vfp_mrs();
787                        gen_movl_reg_T0(s, rn);
788                        gen_mov_F0_vreg(0, rm + 1);
789                        gen_op_vfp_mrs();
790                        gen_movl_reg_T0(s, rd);
791                    }
792                } else {
793                    /* arm->vfp */
794                    if (dp) {
795                        gen_movl_T0_reg(s, rd);
796                        gen_movl_T1_reg(s, rn);
797                        gen_op_vfp_mdrr();
798                        gen_mov_vreg_F0(1, rm);
799                    } else {
800                        gen_movl_T0_reg(s, rn);
801                        gen_op_vfp_msr();
802                        gen_mov_vreg_F0(0, rm);
803                        gen_movl_T0_reg(s, rd);
804                        gen_op_vfp_msr();
805                        gen_mov_vreg_F0(0, rm + 1);
806                    }
807                }
808            } else {
809                /* Load/store */
810                rn = (insn >> 16) & 0xf;
811                if (dp)
812                    rd = (insn >> 12) & 0xf;
813                else
814                    rd = ((insn >> 11) & 0x1e) | ((insn >> 22) & 1);
815                gen_movl_T1_reg(s, rn);
816                if ((insn & 0x01200000) == 0x01000000) {
817                    /* Single load/store */
818                    offset = (insn & 0xff) << 2;
819                    if ((insn & (1 << 23)) == 0)
820                        offset = -offset;
821                    gen_op_addl_T1_im(offset);
822                    if (insn & (1 << 20)) {
823                        gen_vfp_ld(dp);
824                        gen_mov_vreg_F0(dp, rd);
825                    } else {
826                        gen_mov_F0_vreg(dp, rd);
827                        gen_vfp_st(dp);
828                    }
829                } else {
830                    /* load/store multiple */
831                    if (dp)
832                        n = (insn >> 1) & 0x7f;
833                    else
834                        n = insn & 0xff;
835    
836                    if (insn & (1 << 24)) /* pre-decrement */
837                        gen_op_addl_T1_im(-((insn & 0xff) << 2));
838    
839                    if (dp)
840                        offset = 8;
841                    else
842                        offset = 4;
843                    for (i = 0; i < n; i++) {
844                        if (insn & (1 << 20)) {
845                            /* load */
846                            gen_vfp_ld(dp);
847                            gen_mov_vreg_F0(dp, rd + i);
848                        } else {
849                            /* store */
850                            gen_mov_F0_vreg(dp, rd + i);
851                            gen_vfp_st(dp);
852                        }
853                        gen_op_addl_T1_im(offset);
854                    }
855                    if (insn & (1 << 21)) {
856                        /* writeback */
857                        if (insn & (1 << 24))
858                            offset = -offset * n;
859                        else if (dp && (insn & 1))
860                            offset = 4;
861                        else
862                            offset = 0;
863    
864                        if (offset != 0)
865                            gen_op_addl_T1_im(offset);
866                        gen_movl_reg_T1(s, rn);
867                    }
868                }
869            }
870            break;
871        default:
872            /* Should never happen.  */
873            return 1;
874        }
875        return 0;
876    }
877    
878    static void disas_arm_insn(CPUState * env, DisasContext *s)
879  {  {
880      unsigned int cond, insn, val, op1, i, shift, rm, rs, rn, rd, sh;      unsigned int cond, insn, val, op1, i, shift, rm, rs, rn, rd, sh;
881            
# Line 363  static void disas_arm_insn(DisasContext Line 884  static void disas_arm_insn(DisasContext
884            
885      cond = insn >> 28;      cond = insn >> 28;
886      if (cond == 0xf){      if (cond == 0xf){
887            /* Unconditional instructions.  */
888          if ((insn & 0x0d70f000) == 0x0550f000)          if ((insn & 0x0d70f000) == 0x0550f000)
889              return; /* PLD */              return; /* PLD */
890          else if ((insn & 0x0e000000) == 0x0a000000) {          else if ((insn & 0x0e000000) == 0x0a000000) {
# Line 381  static void disas_arm_insn(DisasContext Line 903  static void disas_arm_insn(DisasContext
903              gen_op_movl_T0_im(val);              gen_op_movl_T0_im(val);
904              gen_bx(s);              gen_bx(s);
905              return;              return;
906            } else if ((insn & 0x0fe00000) == 0x0c400000) {
907                /* Coprocessor double register transfer.  */
908            } else if ((insn & 0x0f000010) == 0x0e000010) {
909                /* Additional coprocessor register transfer.  */
910          }          }
911          goto illegal_op;          goto illegal_op;
912      }      }
# Line 934  static void disas_arm_insn(DisasContext Line 1460  static void disas_arm_insn(DisasContext
1460                  s->is_jmp = DISAS_TB_JUMP;                  s->is_jmp = DISAS_TB_JUMP;
1461              }              }
1462              break;              break;
1463            case 0xc:
1464            case 0xd:
1465            case 0xe:
1466                /* Coprocessor.  */
1467                op1 = (insn >> 8) & 0xf;
1468                switch (op1) {
1469                case 10:
1470                case 11:
1471                    if (disas_vfp_insn (env, s, insn))
1472                        goto illegal_op;
1473                    break;
1474                default:
1475                    /* unknown coprocessor.  */
1476                    goto illegal_op;
1477                }
1478                break;
1479          case 0xf:          case 0xf:
1480              /* swi */              /* swi */
1481              gen_op_movl_T0_im((long)s->pc);              gen_op_movl_T0_im((long)s->pc);
# Line 1484  static inline int gen_intermediate_code_ Line 2026  static inline int gen_intermediate_code_
2026          if (env->thumb)          if (env->thumb)
2027            disas_thumb_insn(dc);            disas_thumb_insn(dc);
2028          else          else
2029            disas_arm_insn(dc);            disas_arm_insn(env, dc);
2030      } while (!dc->is_jmp && gen_opc_ptr < gen_opc_end &&      } while (!dc->is_jmp && gen_opc_ptr < gen_opc_end &&
2031               (dc->pc - pc_start) < (TARGET_PAGE_SIZE - 32));               (dc->pc - pc_start) < (TARGET_PAGE_SIZE - 32));
2032      switch(dc->is_jmp) {      switch(dc->is_jmp) {
# Line 1557  void cpu_dump_state(CPUState *env, FILE Line 2099  void cpu_dump_state(CPUState *env, FILE
2099                      int flags)                      int flags)
2100  {  {
2101      int i;      int i;
2102        struct {
2103            uint32_t i;
2104            float s;
2105        } s0, s1;
2106        CPU_DoubleU d;
2107    
2108      for(i=0;i<16;i++) {      for(i=0;i<16;i++) {
2109          cpu_fprintf(f, "R%02d=%08x", i, env->regs[i]);          cpu_fprintf(f, "R%02d=%08x", i, env->regs[i]);
# Line 1566  void cpu_dump_state(CPUState *env, FILE Line 2113  void cpu_dump_state(CPUState *env, FILE
2113              cpu_fprintf(f, " ");              cpu_fprintf(f, " ");
2114      }      }
2115      cpu_fprintf(f, "PSR=%08x %c%c%c%c\n",      cpu_fprintf(f, "PSR=%08x %c%c%c%c\n",
2116              env->cpsr,               env->cpsr,
2117              env->cpsr & (1 << 31) ? 'N' : '-',              env->cpsr & (1 << 31) ? 'N' : '-',
2118              env->cpsr & (1 << 30) ? 'Z' : '-',              env->cpsr & (1 << 30) ? 'Z' : '-',
2119              env->cpsr & (1 << 29) ? 'C' : '-',              env->cpsr & (1 << 29) ? 'C' : '-',
2120              env->cpsr & (1 << 28) ? 'V' : '-');              env->cpsr & (1 << 28) ? 'V' : '-');
2121    
2122        for (i = 0; i < 16; i++) {
2123            s0.s = env->vfp.regs.s[i * 2];
2124            s1.s = env->vfp.regs.s[i * 2 + 1];
2125            d.d = env->vfp.regs.d[i];
2126            cpu_fprintf(f, "s%02d=%08x(%8f) s%02d=%08x(%8f) d%02d=%08x%08x(%8f)\n",
2127                        i * 2, (int)s0.i, s0.s,
2128                        i * 2 + 1, (int)s0.i, s0.s,
2129                        i, (int)(uint32_t)d.l.upper, (int)(uint32_t)d.l.lower,
2130                        d.d);
2131            cpu_fprintf(f, "FPSCR: %08x\n", (int)env->vfp.fpscr);
2132        }
2133  }  }
2134    
2135  target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr)  target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr)

Legend:
Removed from v.1.17  
changed lines
  Added in v.1.18

savannah-hackers-public@gnu.org
ViewVC Help
Powered by ViewVC 1.1.26