Revision 4a08d475 target-arm/translate-a64.c

b/target-arm/translate-a64.c
99 99
    cpu_fprintf(f, "\n");
100 100
}
101 101

  
102
static int get_mem_index(DisasContext *s)
103
{
104
#ifdef CONFIG_USER_ONLY
105
    return 1;
106
#else
107
    return s->user;
108
#endif
109
}
110

  
102 111
void gen_a64_set_pc_im(uint64_t val)
103 112
{
104 113
    tcg_gen_movi_i64(cpu_pc, val);
......
250 259
    return v;
251 260
}
252 261

  
262
static TCGv_i64 read_cpu_reg_sp(DisasContext *s, int reg, int sf)
263
{
264
    TCGv_i64 v = new_tmp_a64(s);
265
    if (sf) {
266
        tcg_gen_mov_i64(v, cpu_X[reg]);
267
    } else {
268
        tcg_gen_ext32u_i64(v, cpu_X[reg]);
269
    }
270
    return v;
271
}
272

  
253 273
/* Set ZF and NF based on a 64 bit result. This is alas fiddlier
254 274
 * than the 32 bit equivalent.
255 275
 */
......
278 298
}
279 299

  
280 300
/*
301
 * Load/Store generators
302
 */
303

  
304
/*
305
 * Store from GPR register to memory
306
 */
307
static void do_gpr_st(DisasContext *s, TCGv_i64 source,
308
                      TCGv_i64 tcg_addr, int size)
309
{
310
    g_assert(size <= 3);
311
    tcg_gen_qemu_st_i64(source, tcg_addr, get_mem_index(s), MO_TE + size);
312
}
313

  
314
/*
315
 * Load from memory to GPR register
316
 */
317
static void do_gpr_ld(DisasContext *s, TCGv_i64 dest, TCGv_i64 tcg_addr,
318
                      int size, bool is_signed, bool extend)
319
{
320
    TCGMemOp memop = MO_TE + size;
321

  
322
    g_assert(size <= 3);
323

  
324
    if (is_signed) {
325
        memop += MO_SIGN;
326
    }
327

  
328
    tcg_gen_qemu_ld_i64(dest, tcg_addr, get_mem_index(s), memop);
329

  
330
    if (extend && is_signed) {
331
        g_assert(size < 3);
332
        tcg_gen_ext32u_i64(dest, dest);
333
    }
334
}
335

  
336
/*
337
 * Store from FP register to memory
338
 */
339
static void do_fp_st(DisasContext *s, int srcidx, TCGv_i64 tcg_addr, int size)
340
{
341
    /* This writes the bottom N bits of a 128 bit wide vector to memory */
342
    int freg_offs = offsetof(CPUARMState, vfp.regs[srcidx * 2]);
343
    TCGv_i64 tmp = tcg_temp_new_i64();
344

  
345
    if (size < 4) {
346
        switch (size) {
347
        case 0:
348
            tcg_gen_ld8u_i64(tmp, cpu_env, freg_offs);
349
            break;
350
        case 1:
351
            tcg_gen_ld16u_i64(tmp, cpu_env, freg_offs);
352
            break;
353
        case 2:
354
            tcg_gen_ld32u_i64(tmp, cpu_env, freg_offs);
355
            break;
356
        case 3:
357
            tcg_gen_ld_i64(tmp, cpu_env, freg_offs);
358
            break;
359
        }
360
        tcg_gen_qemu_st_i64(tmp, tcg_addr, get_mem_index(s), MO_TE + size);
361
    } else {
362
        TCGv_i64 tcg_hiaddr = tcg_temp_new_i64();
363
        tcg_gen_ld_i64(tmp, cpu_env, freg_offs);
364
        tcg_gen_qemu_st_i64(tmp, tcg_addr, get_mem_index(s), MO_TEQ);
365
        tcg_gen_qemu_st64(tmp, tcg_addr, get_mem_index(s));
366
        tcg_gen_ld_i64(tmp, cpu_env, freg_offs + sizeof(float64));
367
        tcg_gen_addi_i64(tcg_hiaddr, tcg_addr, 8);
368
        tcg_gen_qemu_st_i64(tmp, tcg_hiaddr, get_mem_index(s), MO_TEQ);
369
        tcg_temp_free_i64(tcg_hiaddr);
370
    }
371

  
372
    tcg_temp_free_i64(tmp);
373
}
374

  
375
/*
376
 * Load from memory to FP register
377
 */
378
static void do_fp_ld(DisasContext *s, int destidx, TCGv_i64 tcg_addr, int size)
379
{
380
    /* This always zero-extends and writes to a full 128 bit wide vector */
381
    int freg_offs = offsetof(CPUARMState, vfp.regs[destidx * 2]);
382
    TCGv_i64 tmplo = tcg_temp_new_i64();
383
    TCGv_i64 tmphi;
384

  
385
    if (size < 4) {
386
        TCGMemOp memop = MO_TE + size;
387
        tmphi = tcg_const_i64(0);
388
        tcg_gen_qemu_ld_i64(tmplo, tcg_addr, get_mem_index(s), memop);
389
    } else {
390
        TCGv_i64 tcg_hiaddr;
391
        tmphi = tcg_temp_new_i64();
392
        tcg_hiaddr = tcg_temp_new_i64();
393

  
394
        tcg_gen_qemu_ld_i64(tmplo, tcg_addr, get_mem_index(s), MO_TEQ);
395
        tcg_gen_addi_i64(tcg_hiaddr, tcg_addr, 8);
396
        tcg_gen_qemu_ld_i64(tmphi, tcg_hiaddr, get_mem_index(s), MO_TEQ);
397
        tcg_temp_free_i64(tcg_hiaddr);
398
    }
399

  
400
    tcg_gen_st_i64(tmplo, cpu_env, freg_offs);
401
    tcg_gen_st_i64(tmphi, cpu_env, freg_offs + sizeof(float64));
402

  
403
    tcg_temp_free_i64(tmplo);
404
    tcg_temp_free_i64(tmphi);
405
}
406

  
407
static inline void gen_check_sp_alignment(DisasContext *s)
408
{
409
    /* The AArch64 architecture mandates that (if enabled via PSTATE
410
     * or SCTLR bits) there is a check that SP is 16-aligned on every
411
     * SP-relative load or store (with an exception generated if it is not).
412
     * In line with general QEMU practice regarding misaligned accesses,
413
     * we omit these checks for the sake of guest program performance.
414
     * This function is provided as a hook so we can more easily add these
415
     * checks in future (possibly as a "favour catching guest program bugs
416
     * over speed" user selectable option).
417
     */
418
}
419

  
420
/*
281 421
 * the instruction disassembly implemented here matches
282 422
 * the instruction encoding classifications in chapter 3 (C3)
283 423
 * of the ARM Architecture Reference Manual (DDI0487A_a)
......
620 760
    unsupported_encoding(s, insn);
621 761
}
622 762

  
623
/* Load/store pair (all forms) */
763
/*
764
 * C5.6.80 LDNP (Load Pair - non-temporal hint)
765
 * C5.6.81 LDP (Load Pair - non vector)
766
 * C5.6.82 LDPSW (Load Pair Signed Word - non vector)
767
 * C5.6.176 STNP (Store Pair - non-temporal hint)
768
 * C5.6.177 STP (Store Pair - non vector)
769
 * C6.3.165 LDNP (Load Pair of SIMD&FP - non-temporal hint)
770
 * C6.3.165 LDP (Load Pair of SIMD&FP)
771
 * C6.3.284 STNP (Store Pair of SIMD&FP - non-temporal hint)
772
 * C6.3.284 STP (Store Pair of SIMD&FP)
773
 *
774
 *  31 30 29   27  26  25 24   23  22 21   15 14   10 9    5 4    0
775
 * +-----+-------+---+---+-------+---+-----------------------------+
776
 * | opc | 1 0 1 | V | 0 | index | L |  imm7 |  Rt2  |  Rn  | Rt   |
777
 * +-----+-------+---+---+-------+---+-------+-------+------+------+
778
 *
779
 * opc: LDP/STP/LDNP/STNP        00 -> 32 bit, 10 -> 64 bit
780
 *      LDPSW                    01
781
 *      LDP/STP/LDNP/STNP (SIMD) 00 -> 32 bit, 01 -> 64 bit, 10 -> 128 bit
782
 *   V: 0 -> GPR, 1 -> Vector
783
 * idx: 00 -> signed offset with non-temporal hint, 01 -> post-index,
784
 *      10 -> signed offset, 11 -> pre-index
785
 *   L: 0 -> Store 1 -> Load
786
 *
787
 * Rt, Rt2 = GPR or SIMD registers to be stored
788
 * Rn = general purpose register containing address
789
 * imm7 = signed offset (multiple of 4 or 8 depending on size)
790
 */
624 791
static void disas_ldst_pair(DisasContext *s, uint32_t insn)
625 792
{
626
    unsupported_encoding(s, insn);
793
    int rt = extract32(insn, 0, 5);
794
    int rn = extract32(insn, 5, 5);
795
    int rt2 = extract32(insn, 10, 5);
796
    int64_t offset = sextract32(insn, 15, 7);
797
    int index = extract32(insn, 23, 2);
798
    bool is_vector = extract32(insn, 26, 1);
799
    bool is_load = extract32(insn, 22, 1);
800
    int opc = extract32(insn, 30, 2);
801

  
802
    bool is_signed = false;
803
    bool postindex = false;
804
    bool wback = false;
805

  
806
    TCGv_i64 tcg_addr; /* calculated address */
807
    int size;
808

  
809
    if (opc == 3) {
810
        unallocated_encoding(s);
811
        return;
812
    }
813

  
814
    if (is_vector) {
815
        size = 2 + opc;
816
    } else {
817
        size = 2 + extract32(opc, 1, 1);
818
        is_signed = extract32(opc, 0, 1);
819
        if (!is_load && is_signed) {
820
            unallocated_encoding(s);
821
            return;
822
        }
823
    }
824

  
825
    switch (index) {
826
    case 1: /* post-index */
827
        postindex = true;
828
        wback = true;
829
        break;
830
    case 0:
831
        /* signed offset with "non-temporal" hint. Since we don't emulate
832
         * caches we don't care about hints to the cache system about
833
         * data access patterns, and handle this identically to plain
834
         * signed offset.
835
         */
836
        if (is_signed) {
837
            /* There is no non-temporal-hint version of LDPSW */
838
            unallocated_encoding(s);
839
            return;
840
        }
841
        postindex = false;
842
        break;
843
    case 2: /* signed offset, rn not updated */
844
        postindex = false;
845
        break;
846
    case 3: /* pre-index */
847
        postindex = false;
848
        wback = true;
849
        break;
850
    }
851

  
852
    offset <<= size;
853

  
854
    if (rn == 31) {
855
        gen_check_sp_alignment(s);
856
    }
857

  
858
    tcg_addr = read_cpu_reg_sp(s, rn, 1);
859

  
860
    if (!postindex) {
861
        tcg_gen_addi_i64(tcg_addr, tcg_addr, offset);
862
    }
863

  
864
    if (is_vector) {
865
        if (is_load) {
866
            do_fp_ld(s, rt, tcg_addr, size);
867
        } else {
868
            do_fp_st(s, rt, tcg_addr, size);
869
        }
870
    } else {
871
        TCGv_i64 tcg_rt = cpu_reg(s, rt);
872
        if (is_load) {
873
            do_gpr_ld(s, tcg_rt, tcg_addr, size, is_signed, false);
874
        } else {
875
            do_gpr_st(s, tcg_rt, tcg_addr, size);
876
        }
877
    }
878
    tcg_gen_addi_i64(tcg_addr, tcg_addr, 1 << size);
879
    if (is_vector) {
880
        if (is_load) {
881
            do_fp_ld(s, rt2, tcg_addr, size);
882
        } else {
883
            do_fp_st(s, rt2, tcg_addr, size);
884
        }
885
    } else {
886
        TCGv_i64 tcg_rt2 = cpu_reg(s, rt2);
887
        if (is_load) {
888
            do_gpr_ld(s, tcg_rt2, tcg_addr, size, is_signed, false);
889
        } else {
890
            do_gpr_st(s, tcg_rt2, tcg_addr, size);
891
        }
892
    }
893

  
894
    if (wback) {
895
        if (postindex) {
896
            tcg_gen_addi_i64(tcg_addr, tcg_addr, offset - (1 << size));
897
        } else {
898
            tcg_gen_subi_i64(tcg_addr, tcg_addr, 1 << size);
899
        }
900
        tcg_gen_mov_i64(cpu_reg_sp(s, rn), tcg_addr);
901
    }
627 902
}
628 903

  
629 904
/* Load/store register (all forms) */

Also available in: Unified diff