110
static int raw_read(CPUARMState *env, const ARMCPRegInfo *ri,
117
static uint64_t raw_read(CPUARMState *env, const ARMCPRegInfo *ri)
113
if (ri->type & ARM_CP_64BIT) {
114
*value = CPREG_FIELD64(env, ri);
119
if (cpreg_field_is_64bit(ri)) {
120
return CPREG_FIELD64(env, ri);
116
*value = CPREG_FIELD32(env, ri);
122
return CPREG_FIELD32(env, ri);
121
static int raw_write(CPUARMState *env, const ARMCPRegInfo *ri,
126
static void raw_write(CPUARMState *env, const ARMCPRegInfo *ri,
124
if (ri->type & ARM_CP_64BIT) {
129
if (cpreg_field_is_64bit(ri)) {
125
130
CPREG_FIELD64(env, ri) = value;
127
132
CPREG_FIELD32(env, ri) = value;
132
static bool read_raw_cp_reg(CPUARMState *env, const ARMCPRegInfo *ri,
136
static uint64_t read_raw_cp_reg(CPUARMState *env, const ARMCPRegInfo *ri)
135
/* Raw read of a coprocessor register (as needed for migration, etc)
136
* return true on success, false if the read is impossible for some reason.
138
/* Raw read of a coprocessor register (as needed for migration, etc). */
138
139
if (ri->type & ARM_CP_CONST) {
140
return ri->resetvalue;
140
141
} else if (ri->raw_readfn) {
141
return (ri->raw_readfn(env, ri, v) == 0);
142
return ri->raw_readfn(env, ri);
142
143
} else if (ri->readfn) {
143
return (ri->readfn(env, ri, v) == 0);
144
return ri->readfn(env, ri);
145
raw_read(env, ri, v);
146
return raw_read(env, ri);
150
static bool write_raw_cp_reg(CPUARMState *env, const ARMCPRegInfo *ri,
150
static void write_raw_cp_reg(CPUARMState *env, const ARMCPRegInfo *ri,
153
153
/* Raw write of a coprocessor register (as needed for migration, etc).
154
* Return true on success, false if the write is impossible for some reason.
155
154
* Note that constant registers are treated as write-ignored; the
156
155
* caller should check for success by whether a readback gives the
159
158
if (ri->type & ARM_CP_CONST) {
161
160
} else if (ri->raw_writefn) {
162
return (ri->raw_writefn(env, ri, v) == 0);
161
ri->raw_writefn(env, ri, v);
163
162
} else if (ri->writefn) {
164
return (ri->writefn(env, ri, v) == 0);
163
ri->writefn(env, ri, v);
166
165
raw_write(env, ri, v);
171
169
bool write_cpustate_to_list(ARMCPU *cpu)
309
301
g_list_free(keys);
312
static int dacr_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value)
304
static void dacr_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value)
306
ARMCPU *cpu = arm_env_get_cpu(env);
314
308
env->cp15.c3 = value;
315
tlb_flush(env, 1); /* Flush TLB as domain not tracked in TLB */
309
tlb_flush(CPU(cpu), 1); /* Flush TLB as domain not tracked in TLB */
319
static int fcse_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value)
312
static void fcse_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value)
314
ARMCPU *cpu = arm_env_get_cpu(env);
321
316
if (env->cp15.c13_fcse != value) {
322
317
/* Unlike real hardware the qemu TLB uses virtual addresses,
323
318
* not modified virtual addresses, so this causes a TLB flush.
320
tlb_flush(CPU(cpu), 1);
326
321
env->cp15.c13_fcse = value;
330
static int contextidr_write(CPUARMState *env, const ARMCPRegInfo *ri,
325
static void contextidr_write(CPUARMState *env, const ARMCPRegInfo *ri,
328
ARMCPU *cpu = arm_env_get_cpu(env);
333
330
if (env->cp15.c13_context != value && !arm_feature(env, ARM_FEATURE_MPU)) {
334
331
/* For VMSA (when not using the LPAE long descriptor page table
335
332
* format) this register includes the ASID, so do a TLB flush.
336
333
* For PMSA it is purely a process ID and no action is needed.
335
tlb_flush(CPU(cpu), 1);
340
337
env->cp15.c13_context = value;
344
static int tlbiall_write(CPUARMState *env, const ARMCPRegInfo *ri,
340
static void tlbiall_write(CPUARMState *env, const ARMCPRegInfo *ri,
347
343
/* Invalidate all (TLBIALL) */
344
ARMCPU *cpu = arm_env_get_cpu(env);
346
tlb_flush(CPU(cpu), 1);
352
static int tlbimva_write(CPUARMState *env, const ARMCPRegInfo *ri,
349
static void tlbimva_write(CPUARMState *env, const ARMCPRegInfo *ri,
355
352
/* Invalidate single TLB entry by MVA and ASID (TLBIMVA) */
356
tlb_flush_page(env, value & TARGET_PAGE_MASK);
353
ARMCPU *cpu = arm_env_get_cpu(env);
355
tlb_flush_page(CPU(cpu), value & TARGET_PAGE_MASK);
360
static int tlbiasid_write(CPUARMState *env, const ARMCPRegInfo *ri,
358
static void tlbiasid_write(CPUARMState *env, const ARMCPRegInfo *ri,
363
361
/* Invalidate by ASID (TLBIASID) */
364
tlb_flush(env, value == 0);
362
ARMCPU *cpu = arm_env_get_cpu(env);
364
tlb_flush(CPU(cpu), value == 0);
368
static int tlbimvaa_write(CPUARMState *env, const ARMCPRegInfo *ri,
367
static void tlbimvaa_write(CPUARMState *env, const ARMCPRegInfo *ri,
371
370
/* Invalidate single entry by MVA, all ASIDs (TLBIMVAA) */
372
tlb_flush_page(env, value & TARGET_PAGE_MASK);
371
ARMCPU *cpu = arm_env_get_cpu(env);
373
tlb_flush_page(CPU(cpu), value & TARGET_PAGE_MASK);
376
376
static const ARMCPRegInfo cp_reginfo[] = {
480
480
{ .name = "WFAR", .cp = 15, .crn = 6, .crm = 0, .opc1 = 0, .opc2 = 1,
481
481
.access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0, },
482
{ .name = "CPACR", .cp = 15, .crn = 1, .crm = 0, .opc1 = 0, .opc2 = 2,
482
{ .name = "CPACR", .state = ARM_CP_STATE_BOTH, .opc0 = 3,
483
.crn = 1, .crm = 0, .opc1 = 0, .opc2 = 2,
483
484
.access = PL1_RW, .fieldoffset = offsetof(CPUARMState, cp15.c1_coproc),
484
485
.resetvalue = 0, .writefn = cpacr_write },
489
static int pmreg_read(CPUARMState *env, const ARMCPRegInfo *ri,
489
static CPAccessResult pmreg_access(CPUARMState *env, const ARMCPRegInfo *ri)
492
/* Generic performance monitor register read function for where
493
* user access may be allowed by PMUSERENR.
491
/* Performance monitor registers user accessibility is controlled
495
494
if (arm_current_pl(env) == 0 && !env->cp15.c9_pmuserenr) {
495
return CP_ACCESS_TRAP;
498
*value = CPREG_FIELD32(env, ri);
502
static int pmcr_write(CPUARMState *env, const ARMCPRegInfo *ri,
500
#ifndef CONFIG_USER_ONLY
501
static void pmcr_write(CPUARMState *env, const ARMCPRegInfo *ri,
505
if (arm_current_pl(env) == 0 && !env->cp15.c9_pmuserenr) {
504
/* Don't computer the number of ticks in user mode */
507
temp_ticks = qemu_clock_get_us(QEMU_CLOCK_VIRTUAL) *
508
get_ticks_per_sec() / 1000000;
510
if (env->cp15.c9_pmcr & PMCRE) {
511
/* If the counter is enabled */
512
if (env->cp15.c9_pmcr & PMCRD) {
513
/* Increment once every 64 processor clock cycles */
514
env->cp15.c15_ccnt = (temp_ticks/64) - env->cp15.c15_ccnt;
516
env->cp15.c15_ccnt = temp_ticks - env->cp15.c15_ccnt;
521
/* The counter has been reset */
522
env->cp15.c15_ccnt = 0;
508
525
/* only the DP, X, D and E bits are writable */
509
526
env->cp15.c9_pmcr &= ~0x39;
510
527
env->cp15.c9_pmcr |= (value & 0x39);
514
static int pmcntenset_write(CPUARMState *env, const ARMCPRegInfo *ri,
529
if (env->cp15.c9_pmcr & PMCRE) {
530
if (env->cp15.c9_pmcr & PMCRD) {
531
/* Increment once every 64 processor clock cycles */
534
env->cp15.c15_ccnt = temp_ticks - env->cp15.c15_ccnt;
538
static uint64_t pmccntr_read(CPUARMState *env, const ARMCPRegInfo *ri)
540
uint32_t total_ticks;
542
if (!(env->cp15.c9_pmcr & PMCRE)) {
543
/* Counter is disabled, do not change value */
544
return env->cp15.c15_ccnt;
547
total_ticks = qemu_clock_get_us(QEMU_CLOCK_VIRTUAL) *
548
get_ticks_per_sec() / 1000000;
550
if (env->cp15.c9_pmcr & PMCRD) {
551
/* Increment once every 64 processor clock cycles */
554
return total_ticks - env->cp15.c15_ccnt;
557
static void pmccntr_write(CPUARMState *env, const ARMCPRegInfo *ri,
560
uint32_t total_ticks;
562
if (!(env->cp15.c9_pmcr & PMCRE)) {
563
/* Counter is disabled, set the absolute value */
564
env->cp15.c15_ccnt = value;
568
total_ticks = qemu_clock_get_us(QEMU_CLOCK_VIRTUAL) *
569
get_ticks_per_sec() / 1000000;
571
if (env->cp15.c9_pmcr & PMCRD) {
572
/* Increment once every 64 processor clock cycles */
575
env->cp15.c15_ccnt = total_ticks - value;
579
static void pmcntenset_write(CPUARMState *env, const ARMCPRegInfo *ri,
517
if (arm_current_pl(env) == 0 && !env->cp15.c9_pmuserenr) {
520
582
value &= (1 << 31);
521
583
env->cp15.c9_pmcnten |= value;
525
static int pmcntenclr_write(CPUARMState *env, const ARMCPRegInfo *ri,
586
static void pmcntenclr_write(CPUARMState *env, const ARMCPRegInfo *ri,
528
if (arm_current_pl(env) == 0 && !env->cp15.c9_pmuserenr) {
531
589
value &= (1 << 31);
532
590
env->cp15.c9_pmcnten &= ~value;
536
static int pmovsr_write(CPUARMState *env, const ARMCPRegInfo *ri,
593
static void pmovsr_write(CPUARMState *env, const ARMCPRegInfo *ri,
539
if (arm_current_pl(env) == 0 && !env->cp15.c9_pmuserenr) {
542
596
env->cp15.c9_pmovsr &= ~value;
546
static int pmxevtyper_write(CPUARMState *env, const ARMCPRegInfo *ri,
599
static void pmxevtyper_write(CPUARMState *env, const ARMCPRegInfo *ri,
549
if (arm_current_pl(env) == 0 && !env->cp15.c9_pmuserenr) {
552
602
env->cp15.c9_pmxevtyper = value & 0xff;
556
static int pmuserenr_write(CPUARMState *env, const ARMCPRegInfo *ri,
605
static void pmuserenr_write(CPUARMState *env, const ARMCPRegInfo *ri,
559
608
env->cp15.c9_pmuserenr = value & 1;
563
static int pmintenset_write(CPUARMState *env, const ARMCPRegInfo *ri,
611
static void pmintenset_write(CPUARMState *env, const ARMCPRegInfo *ri,
566
614
/* We have no event counters so only the C bit can be changed */
567
615
value &= (1 << 31);
568
616
env->cp15.c9_pminten |= value;
572
static int pmintenclr_write(CPUARMState *env, const ARMCPRegInfo *ri,
619
static void pmintenclr_write(CPUARMState *env, const ARMCPRegInfo *ri,
575
622
value &= (1 << 31);
576
623
env->cp15.c9_pminten &= ~value;
580
static int ccsidr_read(CPUARMState *env, const ARMCPRegInfo *ri,
626
static void vbar_write(CPUARMState *env, const ARMCPRegInfo *ri,
629
/* Note that even though the AArch64 view of this register has bits
630
* [10:0] all RES0 we can only mask the bottom 5, to comply with the
631
* architectural requirements for bits which are RES0 only in some
632
* contexts. (ARMv8 would permit us to do no masking at all, but ARMv7
633
* requires the bottom five bits to be RAZ/WI because they're UNK/SBZP.)
635
env->cp15.c12_vbar = value & ~0x1Ful;
638
static uint64_t ccsidr_read(CPUARMState *env, const ARMCPRegInfo *ri)
583
640
ARMCPU *cpu = arm_env_get_cpu(env);
584
*value = cpu->ccsidr[env->cp15.c0_cssel];
641
return cpu->ccsidr[env->cp15.c0_cssel];
588
static int csselr_write(CPUARMState *env, const ARMCPRegInfo *ri,
644
static void csselr_write(CPUARMState *env, const ARMCPRegInfo *ri,
591
647
env->cp15.c0_cssel = value & 0xf;
595
650
static const ARMCPRegInfo v7_cp_reginfo[] = {
617
672
{ .name = "PMCNTENSET", .cp = 15, .crn = 9, .crm = 12, .opc1 = 0, .opc2 = 1,
618
673
.access = PL0_RW, .resetvalue = 0,
619
674
.fieldoffset = offsetof(CPUARMState, cp15.c9_pmcnten),
620
.readfn = pmreg_read, .writefn = pmcntenset_write,
621
.raw_readfn = raw_read, .raw_writefn = raw_write },
675
.writefn = pmcntenset_write,
676
.accessfn = pmreg_access,
677
.raw_writefn = raw_write },
622
678
{ .name = "PMCNTENCLR", .cp = 15, .crn = 9, .crm = 12, .opc1 = 0, .opc2 = 2,
623
679
.access = PL0_RW, .fieldoffset = offsetof(CPUARMState, cp15.c9_pmcnten),
624
.readfn = pmreg_read, .writefn = pmcntenclr_write,
680
.accessfn = pmreg_access,
681
.writefn = pmcntenclr_write,
625
682
.type = ARM_CP_NO_MIGRATE },
626
683
{ .name = "PMOVSR", .cp = 15, .crn = 9, .crm = 12, .opc1 = 0, .opc2 = 3,
627
684
.access = PL0_RW, .fieldoffset = offsetof(CPUARMState, cp15.c9_pmovsr),
628
.readfn = pmreg_read, .writefn = pmovsr_write,
629
.raw_readfn = raw_read, .raw_writefn = raw_write },
630
/* Unimplemented so WI. Strictly speaking write accesses in PL0 should
685
.accessfn = pmreg_access,
686
.writefn = pmovsr_write,
687
.raw_writefn = raw_write },
688
/* Unimplemented so WI. */
633
689
{ .name = "PMSWINC", .cp = 15, .crn = 9, .crm = 12, .opc1 = 0, .opc2 = 4,
634
.access = PL0_W, .type = ARM_CP_NOP },
690
.access = PL0_W, .accessfn = pmreg_access, .type = ARM_CP_NOP },
635
691
/* Since we don't implement any events, writing to PMSELR is UNPREDICTABLE.
636
* We choose to RAZ/WI. XXX should respect PMUSERENR.
692
* We choose to RAZ/WI.
638
694
{ .name = "PMSELR", .cp = 15, .crn = 9, .crm = 12, .opc1 = 0, .opc2 = 5,
639
.access = PL0_RW, .type = ARM_CP_CONST, .resetvalue = 0 },
640
/* Unimplemented, RAZ/WI. XXX PMUSERENR */
695
.access = PL0_RW, .type = ARM_CP_CONST, .resetvalue = 0,
696
.accessfn = pmreg_access },
697
#ifndef CONFIG_USER_ONLY
641
698
{ .name = "PMCCNTR", .cp = 15, .crn = 9, .crm = 13, .opc1 = 0, .opc2 = 0,
642
.access = PL0_RW, .type = ARM_CP_CONST, .resetvalue = 0 },
699
.access = PL0_RW, .resetvalue = 0, .type = ARM_CP_IO,
700
.readfn = pmccntr_read, .writefn = pmccntr_write,
701
.accessfn = pmreg_access },
643
703
{ .name = "PMXEVTYPER", .cp = 15, .crn = 9, .crm = 13, .opc1 = 0, .opc2 = 1,
644
704
.access = PL0_RW,
645
705
.fieldoffset = offsetof(CPUARMState, cp15.c9_pmxevtyper),
646
.readfn = pmreg_read, .writefn = pmxevtyper_write,
647
.raw_readfn = raw_read, .raw_writefn = raw_write },
648
/* Unimplemented, RAZ/WI. XXX PMUSERENR */
706
.accessfn = pmreg_access, .writefn = pmxevtyper_write,
707
.raw_writefn = raw_write },
708
/* Unimplemented, RAZ/WI. */
649
709
{ .name = "PMXEVCNTR", .cp = 15, .crn = 9, .crm = 13, .opc1 = 0, .opc2 = 2,
650
.access = PL0_RW, .type = ARM_CP_CONST, .resetvalue = 0 },
710
.access = PL0_RW, .type = ARM_CP_CONST, .resetvalue = 0,
711
.accessfn = pmreg_access },
651
712
{ .name = "PMUSERENR", .cp = 15, .crn = 9, .crm = 14, .opc1 = 0, .opc2 = 0,
652
713
.access = PL0_R | PL1_RW,
653
714
.fieldoffset = offsetof(CPUARMState, cp15.c9_pmuserenr),
673
744
{ .name = "AIDR", .cp = 15, .crn = 0, .crm = 0, .opc1 = 1, .opc2 = 7,
674
745
.access = PL1_R, .type = ARM_CP_CONST, .resetvalue = 0 },
746
/* MAIR can just read-as-written because we don't implement caches
747
* and so don't need to care about memory attributes.
749
{ .name = "MAIR_EL1", .state = ARM_CP_STATE_AA64,
750
.opc0 = 3, .opc1 = 0, .crn = 10, .crm = 2, .opc2 = 0,
751
.access = PL1_RW, .fieldoffset = offsetof(CPUARMState, cp15.mair_el1),
753
/* For non-long-descriptor page tables these are PRRR and NMRR;
754
* regardless they still act as reads-as-written for QEMU.
755
* The override is necessary because of the overly-broad TLB_LOCKDOWN
758
{ .name = "MAIR0", .state = ARM_CP_STATE_AA32, .type = ARM_CP_OVERRIDE,
759
.cp = 15, .opc1 = 0, .crn = 10, .crm = 2, .opc2 = 0, .access = PL1_RW,
760
.fieldoffset = offsetoflow32(CPUARMState, cp15.mair_el1),
761
.resetfn = arm_cp_reset_ignore },
762
{ .name = "MAIR1", .state = ARM_CP_STATE_AA32, .type = ARM_CP_OVERRIDE,
763
.cp = 15, .opc1 = 0, .crn = 10, .crm = 2, .opc2 = 1, .access = PL1_RW,
764
.fieldoffset = offsetofhigh32(CPUARMState, cp15.mair_el1),
765
.resetfn = arm_cp_reset_ignore },
678
static int teecr_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value)
769
static void teecr_write(CPUARMState *env, const ARMCPRegInfo *ri,
681
773
env->teecr = value;
685
static int teehbr_read(CPUARMState *env, const ARMCPRegInfo *ri,
688
/* This is a helper function because the user access rights
689
* depend on the value of the TEECR.
691
if (arm_current_pl(env) == 0 && (env->teecr & 1)) {
694
*value = env->teehbr;
698
static int teehbr_write(CPUARMState *env, const ARMCPRegInfo *ri,
701
if (arm_current_pl(env) == 0 && (env->teecr & 1)) {
776
static CPAccessResult teehbr_access(CPUARMState *env, const ARMCPRegInfo *ri)
778
if (arm_current_pl(env) == 0 && (env->teecr & 1)) {
779
return CP_ACCESS_TRAP;
708
784
static const ARMCPRegInfo t2ee_cp_reginfo[] = {
807
924
timer_del(cpu->gt_timer[timeridx]);
810
static int gt_cnt_read(CPUARMState *env, const ARMCPRegInfo *ri,
813
int timeridx = ri->opc1 & 1;
815
if (arm_current_pl(env) == 0 &&
816
!extract32(env->cp15.c14_cntkctl, timeridx, 1)) {
819
*value = gt_get_countervalue(env);
823
static int gt_cval_read(CPUARMState *env, const ARMCPRegInfo *ri,
826
int timeridx = ri->opc1 & 1;
828
if (arm_current_pl(env) == 0 &&
829
!extract32(env->cp15.c14_cntkctl, 9 - timeridx, 1)) {
832
*value = env->cp15.c14_timer[timeridx].cval;
836
static int gt_cval_write(CPUARMState *env, const ARMCPRegInfo *ri,
927
static uint64_t gt_cnt_read(CPUARMState *env, const ARMCPRegInfo *ri)
929
return gt_get_countervalue(env);
932
static void gt_cval_write(CPUARMState *env, const ARMCPRegInfo *ri,
839
935
int timeridx = ri->opc1 & 1;
841
937
env->cp15.c14_timer[timeridx].cval = value;
842
938
gt_recalc_timer(arm_env_get_cpu(env), timeridx);
845
static int gt_tval_read(CPUARMState *env, const ARMCPRegInfo *ri,
941
static uint64_t gt_tval_read(CPUARMState *env, const ARMCPRegInfo *ri)
848
943
int timeridx = ri->crm & 1;
850
if (arm_current_pl(env) == 0 &&
851
!extract32(env->cp15.c14_cntkctl, 9 - timeridx, 1)) {
854
*value = (uint32_t)(env->cp15.c14_timer[timeridx].cval -
855
gt_get_countervalue(env));
945
return (uint32_t)(env->cp15.c14_timer[timeridx].cval -
946
gt_get_countervalue(env));
859
static int gt_tval_write(CPUARMState *env, const ARMCPRegInfo *ri,
949
static void gt_tval_write(CPUARMState *env, const ARMCPRegInfo *ri,
862
952
int timeridx = ri->crm & 1;
864
954
env->cp15.c14_timer[timeridx].cval = gt_get_countervalue(env) +
865
955
+ sextract64(value, 0, 32);
866
956
gt_recalc_timer(arm_env_get_cpu(env), timeridx);
870
static int gt_ctl_read(CPUARMState *env, const ARMCPRegInfo *ri,
873
int timeridx = ri->crm & 1;
875
if (arm_current_pl(env) == 0 &&
876
!extract32(env->cp15.c14_cntkctl, 9 - timeridx, 1)) {
879
*value = env->cp15.c14_timer[timeridx].ctl;
883
static int gt_ctl_write(CPUARMState *env, const ARMCPRegInfo *ri,
959
static void gt_ctl_write(CPUARMState *env, const ARMCPRegInfo *ri,
886
962
ARMCPU *cpu = arm_env_get_cpu(env);
887
963
int timeridx = ri->crm & 1;
921
996
* Our reset value matches the fixed frequency we implement the timer at.
923
998
{ .name = "CNTFRQ", .cp = 15, .crn = 14, .crm = 0, .opc1 = 0, .opc2 = 0,
924
.access = PL1_RW | PL0_R,
999
.type = ARM_CP_NO_MIGRATE,
1000
.access = PL1_RW | PL0_R, .accessfn = gt_cntfrq_access,
1001
.fieldoffset = offsetoflow32(CPUARMState, cp15.c14_cntfrq),
1002
.resetfn = arm_cp_reset_ignore,
1004
{ .name = "CNTFRQ_EL0", .state = ARM_CP_STATE_AA64,
1005
.opc0 = 3, .opc1 = 3, .crn = 14, .crm = 0, .opc2 = 0,
1006
.access = PL1_RW | PL0_R, .accessfn = gt_cntfrq_access,
925
1007
.fieldoffset = offsetof(CPUARMState, cp15.c14_cntfrq),
926
1008
.resetvalue = (1000 * 1000 * 1000) / GTIMER_SCALE,
927
.readfn = gt_cntfrq_read, .raw_readfn = raw_read,
929
1010
/* overall control: mostly access permissions */
930
{ .name = "CNTKCTL", .cp = 15, .crn = 14, .crm = 1, .opc1 = 0, .opc2 = 0,
1011
{ .name = "CNTKCTL", .state = ARM_CP_STATE_BOTH,
1012
.opc0 = 3, .opc1 = 0, .crn = 14, .crm = 1, .opc2 = 0,
931
1013
.access = PL1_RW,
932
1014
.fieldoffset = offsetof(CPUARMState, cp15.c14_cntkctl),
933
1015
.resetvalue = 0,
935
1017
/* per-timer control */
936
1018
{ .name = "CNTP_CTL", .cp = 15, .crn = 14, .crm = 2, .opc1 = 0, .opc2 = 1,
1019
.type = ARM_CP_IO | ARM_CP_NO_MIGRATE, .access = PL1_RW | PL0_R,
1020
.accessfn = gt_ptimer_access,
1021
.fieldoffset = offsetoflow32(CPUARMState,
1022
cp15.c14_timer[GTIMER_PHYS].ctl),
1023
.resetfn = arm_cp_reset_ignore,
1024
.writefn = gt_ctl_write, .raw_writefn = raw_write,
1026
{ .name = "CNTP_CTL_EL0", .state = ARM_CP_STATE_AA64,
1027
.opc0 = 3, .opc1 = 3, .crn = 14, .crm = 2, .opc2 = 1,
937
1028
.type = ARM_CP_IO, .access = PL1_RW | PL0_R,
1029
.accessfn = gt_ptimer_access,
938
1030
.fieldoffset = offsetof(CPUARMState, cp15.c14_timer[GTIMER_PHYS].ctl),
939
1031
.resetvalue = 0,
940
.readfn = gt_ctl_read, .writefn = gt_ctl_write,
941
.raw_readfn = raw_read, .raw_writefn = raw_write,
1032
.writefn = gt_ctl_write, .raw_writefn = raw_write,
943
1034
{ .name = "CNTV_CTL", .cp = 15, .crn = 14, .crm = 3, .opc1 = 0, .opc2 = 1,
1035
.type = ARM_CP_IO | ARM_CP_NO_MIGRATE, .access = PL1_RW | PL0_R,
1036
.accessfn = gt_vtimer_access,
1037
.fieldoffset = offsetoflow32(CPUARMState,
1038
cp15.c14_timer[GTIMER_VIRT].ctl),
1039
.resetfn = arm_cp_reset_ignore,
1040
.writefn = gt_ctl_write, .raw_writefn = raw_write,
1042
{ .name = "CNTV_CTL_EL0", .state = ARM_CP_STATE_AA64,
1043
.opc0 = 3, .opc1 = 3, .crn = 14, .crm = 3, .opc2 = 1,
944
1044
.type = ARM_CP_IO, .access = PL1_RW | PL0_R,
1045
.accessfn = gt_vtimer_access,
945
1046
.fieldoffset = offsetof(CPUARMState, cp15.c14_timer[GTIMER_VIRT].ctl),
946
1047
.resetvalue = 0,
947
.readfn = gt_ctl_read, .writefn = gt_ctl_write,
948
.raw_readfn = raw_read, .raw_writefn = raw_write,
1048
.writefn = gt_ctl_write, .raw_writefn = raw_write,
950
1050
/* TimerValue views: a 32 bit downcounting view of the underlying state */
951
1051
{ .name = "CNTP_TVAL", .cp = 15, .crn = 14, .crm = 2, .opc1 = 0, .opc2 = 0,
952
1052
.type = ARM_CP_NO_MIGRATE | ARM_CP_IO, .access = PL1_RW | PL0_R,
1053
.accessfn = gt_ptimer_access,
1054
.readfn = gt_tval_read, .writefn = gt_tval_write,
1056
{ .name = "CNTP_TVAL_EL0", .state = ARM_CP_STATE_AA64,
1057
.opc0 = 3, .opc1 = 3, .crn = 14, .crm = 2, .opc2 = 0,
1058
.type = ARM_CP_NO_MIGRATE | ARM_CP_IO, .access = PL1_RW | PL0_R,
953
1059
.readfn = gt_tval_read, .writefn = gt_tval_write,
955
1061
{ .name = "CNTV_TVAL", .cp = 15, .crn = 14, .crm = 3, .opc1 = 0, .opc2 = 0,
956
1062
.type = ARM_CP_NO_MIGRATE | ARM_CP_IO, .access = PL1_RW | PL0_R,
1063
.accessfn = gt_vtimer_access,
1064
.readfn = gt_tval_read, .writefn = gt_tval_write,
1066
{ .name = "CNTV_TVAL_EL0", .state = ARM_CP_STATE_AA64,
1067
.opc0 = 3, .opc1 = 3, .crn = 14, .crm = 3, .opc2 = 0,
1068
.type = ARM_CP_NO_MIGRATE | ARM_CP_IO, .access = PL1_RW | PL0_R,
957
1069
.readfn = gt_tval_read, .writefn = gt_tval_write,
959
1071
/* The counter itself */
960
1072
{ .name = "CNTPCT", .cp = 15, .crm = 14, .opc1 = 0,
961
1073
.access = PL0_R, .type = ARM_CP_64BIT | ARM_CP_NO_MIGRATE | ARM_CP_IO,
1074
.accessfn = gt_pct_access,
1075
.readfn = gt_cnt_read, .resetfn = arm_cp_reset_ignore,
1077
{ .name = "CNTPCT_EL0", .state = ARM_CP_STATE_AA64,
1078
.opc0 = 3, .opc1 = 3, .crn = 14, .crm = 0, .opc2 = 1,
1079
.access = PL0_R, .type = ARM_CP_NO_MIGRATE | ARM_CP_IO,
1080
.accessfn = gt_pct_access,
962
1081
.readfn = gt_cnt_read, .resetfn = gt_cnt_reset,
964
1083
{ .name = "CNTVCT", .cp = 15, .crm = 14, .opc1 = 1,
965
1084
.access = PL0_R, .type = ARM_CP_64BIT | ARM_CP_NO_MIGRATE | ARM_CP_IO,
1085
.accessfn = gt_vct_access,
1086
.readfn = gt_cnt_read, .resetfn = arm_cp_reset_ignore,
1088
{ .name = "CNTVCT_EL0", .state = ARM_CP_STATE_AA64,
1089
.opc0 = 3, .opc1 = 3, .crn = 14, .crm = 0, .opc2 = 2,
1090
.access = PL0_R, .type = ARM_CP_NO_MIGRATE | ARM_CP_IO,
1091
.accessfn = gt_vct_access,
966
1092
.readfn = gt_cnt_read, .resetfn = gt_cnt_reset,
968
1094
/* Comparison value, indicating when the timer goes off */
969
1095
{ .name = "CNTP_CVAL", .cp = 15, .crm = 14, .opc1 = 2,
970
1096
.access = PL1_RW | PL0_R,
971
.type = ARM_CP_64BIT | ARM_CP_IO,
972
.fieldoffset = offsetof(CPUARMState, cp15.c14_timer[GTIMER_PHYS].cval),
974
.readfn = gt_cval_read, .writefn = gt_cval_write,
975
.raw_readfn = raw_read, .raw_writefn = raw_write,
1097
.type = ARM_CP_64BIT | ARM_CP_IO | ARM_CP_NO_MIGRATE,
1098
.fieldoffset = offsetof(CPUARMState, cp15.c14_timer[GTIMER_PHYS].cval),
1099
.accessfn = gt_ptimer_access, .resetfn = arm_cp_reset_ignore,
1100
.writefn = gt_cval_write, .raw_writefn = raw_write,
1102
{ .name = "CNTP_CVAL_EL0", .state = ARM_CP_STATE_AA64,
1103
.opc0 = 3, .opc1 = 3, .crn = 14, .crm = 2, .opc2 = 2,
1104
.access = PL1_RW | PL0_R,
1106
.fieldoffset = offsetof(CPUARMState, cp15.c14_timer[GTIMER_PHYS].cval),
1107
.resetvalue = 0, .accessfn = gt_vtimer_access,
1108
.writefn = gt_cval_write, .raw_writefn = raw_write,
977
1110
{ .name = "CNTV_CVAL", .cp = 15, .crm = 14, .opc1 = 3,
978
1111
.access = PL1_RW | PL0_R,
979
.type = ARM_CP_64BIT | ARM_CP_IO,
980
.fieldoffset = offsetof(CPUARMState, cp15.c14_timer[GTIMER_VIRT].cval),
982
.readfn = gt_cval_read, .writefn = gt_cval_write,
983
.raw_readfn = raw_read, .raw_writefn = raw_write,
1112
.type = ARM_CP_64BIT | ARM_CP_IO | ARM_CP_NO_MIGRATE,
1113
.fieldoffset = offsetof(CPUARMState, cp15.c14_timer[GTIMER_VIRT].cval),
1114
.accessfn = gt_vtimer_access, .resetfn = arm_cp_reset_ignore,
1115
.writefn = gt_cval_write, .raw_writefn = raw_write,
1117
{ .name = "CNTV_CVAL_EL0", .state = ARM_CP_STATE_AA64,
1118
.opc0 = 3, .opc1 = 3, .crn = 14, .crm = 3, .opc2 = 2,
1119
.access = PL1_RW | PL0_R,
1121
.fieldoffset = offsetof(CPUARMState, cp15.c14_timer[GTIMER_VIRT].cval),
1122
.resetvalue = 0, .accessfn = gt_vtimer_access,
1123
.writefn = gt_cval_write, .raw_writefn = raw_write,
985
1125
REGINFO_SENTINEL
1190
1312
.access = PL1_RW,
1191
1313
.fieldoffset = offsetof(CPUARMState, cp15.c2_insn), .resetvalue = 0, },
1192
1314
/* Protection region base and size registers */
1193
{ .name = "946_PRBS", .cp = 15, .crn = 6, .crm = CP_ANY, .opc1 = 0,
1194
.opc2 = CP_ANY, .access = PL1_RW,
1195
.readfn = arm946_prbs_read, .writefn = arm946_prbs_write, },
1315
{ .name = "946_PRBS0", .cp = 15, .crn = 6, .crm = 0, .opc1 = 0,
1316
.opc2 = CP_ANY, .access = PL1_RW, .resetvalue = 0,
1317
.fieldoffset = offsetof(CPUARMState, cp15.c6_region[0]) },
1318
{ .name = "946_PRBS1", .cp = 15, .crn = 6, .crm = 1, .opc1 = 0,
1319
.opc2 = CP_ANY, .access = PL1_RW, .resetvalue = 0,
1320
.fieldoffset = offsetof(CPUARMState, cp15.c6_region[1]) },
1321
{ .name = "946_PRBS2", .cp = 15, .crn = 6, .crm = 2, .opc1 = 0,
1322
.opc2 = CP_ANY, .access = PL1_RW, .resetvalue = 0,
1323
.fieldoffset = offsetof(CPUARMState, cp15.c6_region[2]) },
1324
{ .name = "946_PRBS3", .cp = 15, .crn = 6, .crm = 3, .opc1 = 0,
1325
.opc2 = CP_ANY, .access = PL1_RW, .resetvalue = 0,
1326
.fieldoffset = offsetof(CPUARMState, cp15.c6_region[3]) },
1327
{ .name = "946_PRBS4", .cp = 15, .crn = 6, .crm = 4, .opc1 = 0,
1328
.opc2 = CP_ANY, .access = PL1_RW, .resetvalue = 0,
1329
.fieldoffset = offsetof(CPUARMState, cp15.c6_region[4]) },
1330
{ .name = "946_PRBS5", .cp = 15, .crn = 6, .crm = 5, .opc1 = 0,
1331
.opc2 = CP_ANY, .access = PL1_RW, .resetvalue = 0,
1332
.fieldoffset = offsetof(CPUARMState, cp15.c6_region[5]) },
1333
{ .name = "946_PRBS6", .cp = 15, .crn = 6, .crm = 6, .opc1 = 0,
1334
.opc2 = CP_ANY, .access = PL1_RW, .resetvalue = 0,
1335
.fieldoffset = offsetof(CPUARMState, cp15.c6_region[6]) },
1336
{ .name = "946_PRBS7", .cp = 15, .crn = 6, .crm = 7, .opc1 = 0,
1337
.opc2 = CP_ANY, .access = PL1_RW, .resetvalue = 0,
1338
.fieldoffset = offsetof(CPUARMState, cp15.c6_region[7]) },
1196
1339
REGINFO_SENTINEL
1199
static int vmsa_ttbcr_raw_write(CPUARMState *env, const ARMCPRegInfo *ri,
1342
static void vmsa_ttbcr_raw_write(CPUARMState *env, const ARMCPRegInfo *ri,
1202
1345
int maskshift = extract32(value, 0, 3);
1204
if (arm_feature(env, ARM_FEATURE_LPAE)) {
1347
if (arm_feature(env, ARM_FEATURE_LPAE) && (value & (1 << 31))) {
1205
1348
value &= ~((7 << 19) | (3 << 14) | (0xf << 3));
1243
1411
{ .name = "IFSR", .cp = 15, .crn = 5, .crm = 0, .opc1 = 0, .opc2 = 1,
1244
1412
.access = PL1_RW,
1245
1413
.fieldoffset = offsetof(CPUARMState, cp15.c5_insn), .resetvalue = 0, },
1246
{ .name = "TTBR0", .cp = 15, .crn = 2, .crm = 0, .opc1 = 0, .opc2 = 0,
1248
.fieldoffset = offsetof(CPUARMState, cp15.c2_base0), .resetvalue = 0, },
1249
{ .name = "TTBR1", .cp = 15, .crn = 2, .crm = 0, .opc1 = 0, .opc2 = 1,
1251
.fieldoffset = offsetof(CPUARMState, cp15.c2_base1), .resetvalue = 0, },
1414
{ .name = "TTBR0_EL1", .state = ARM_CP_STATE_BOTH,
1415
.opc0 = 3, .crn = 2, .crm = 0, .opc1 = 0, .opc2 = 0,
1416
.access = PL1_RW, .fieldoffset = offsetof(CPUARMState, cp15.ttbr0_el1),
1417
.writefn = vmsa_ttbr_write, .resetvalue = 0 },
1418
{ .name = "TTBR1_EL1", .state = ARM_CP_STATE_BOTH,
1419
.opc0 = 3, .crn = 2, .crm = 0, .opc1 = 0, .opc2 = 1,
1420
.access = PL1_RW, .fieldoffset = offsetof(CPUARMState, cp15.ttbr1_el1),
1421
.writefn = vmsa_ttbr_write, .resetvalue = 0 },
1422
{ .name = "TCR_EL1", .state = ARM_CP_STATE_AA64,
1423
.opc0 = 3, .crn = 2, .crm = 0, .opc1 = 0, .opc2 = 2,
1424
.access = PL1_RW, .writefn = vmsa_tcr_el1_write,
1425
.resetfn = vmsa_ttbcr_reset, .raw_writefn = raw_write,
1426
.fieldoffset = offsetof(CPUARMState, cp15.c2_control) },
1252
1427
{ .name = "TTBCR", .cp = 15, .crn = 2, .crm = 0, .opc1 = 0, .opc2 = 2,
1253
.access = PL1_RW, .writefn = vmsa_ttbcr_write,
1254
.resetfn = vmsa_ttbcr_reset, .raw_writefn = vmsa_ttbcr_raw_write,
1255
.fieldoffset = offsetof(CPUARMState, cp15.c2_control) },
1428
.access = PL1_RW, .type = ARM_CP_NO_MIGRATE, .writefn = vmsa_ttbcr_write,
1429
.resetfn = arm_cp_reset_ignore, .raw_writefn = vmsa_ttbcr_raw_write,
1430
.fieldoffset = offsetoflow32(CPUARMState, cp15.c2_control) },
1256
1431
{ .name = "DFAR", .cp = 15, .crn = 6, .crm = 0, .opc1 = 0, .opc2 = 0,
1257
1432
.access = PL1_RW, .fieldoffset = offsetof(CPUARMState, cp15.c6_data),
1258
1433
.resetvalue = 0, },
1259
1434
REGINFO_SENTINEL
1262
static int omap_ticonfig_write(CPUARMState *env, const ARMCPRegInfo *ri,
1437
static void omap_ticonfig_write(CPUARMState *env, const ARMCPRegInfo *ri,
1265
1440
env->cp15.c15_ticonfig = value & 0xe7;
1266
1441
/* The OS_TYPE bit in this register changes the reported CPUID! */
1267
1442
env->cp15.c0_cpuid = (value & (1 << 5)) ?
1268
1443
ARM_CPUID_TI915T : ARM_CPUID_TI925T;
1272
static int omap_threadid_write(CPUARMState *env, const ARMCPRegInfo *ri,
1446
static void omap_threadid_write(CPUARMState *env, const ARMCPRegInfo *ri,
1275
1449
env->cp15.c15_threadid = value & 0xffff;
1279
static int omap_wfi_write(CPUARMState *env, const ARMCPRegInfo *ri,
1452
static void omap_wfi_write(CPUARMState *env, const ARMCPRegInfo *ri,
1282
1455
/* Wait-for-interrupt (deprecated) */
1283
1456
cpu_interrupt(CPU(arm_env_get_cpu(env)), CPU_INTERRUPT_HALT);
1287
static int omap_cachemaint_write(CPUARMState *env, const ARMCPRegInfo *ri,
1459
static void omap_cachemaint_write(CPUARMState *env, const ARMCPRegInfo *ri,
1290
1462
/* On OMAP there are registers indicating the max/min index of dcache lines
1291
1463
* containing a dirty line; cache flush operations have to reset these.
1293
1465
env->cp15.c15_i_max = 0x000;
1294
1466
env->cp15.c15_i_min = 0xff0;
1298
1469
static const ARMCPRegInfo omap_cp_reginfo[] = {
1536
1658
.access = PL1_RW, .type = ARM_CP_64BIT,
1537
1659
.readfn = par64_read, .writefn = par64_write, .resetfn = par64_reset },
1538
1660
{ .name = "TTBR0", .cp = 15, .crm = 2, .opc1 = 0,
1539
.access = PL1_RW, .type = ARM_CP_64BIT, .readfn = ttbr064_read,
1540
.writefn = ttbr064_write, .raw_writefn = ttbr064_raw_write,
1541
.resetfn = ttbr064_reset },
1661
.access = PL1_RW, .type = ARM_CP_64BIT | ARM_CP_NO_MIGRATE,
1662
.fieldoffset = offsetof(CPUARMState, cp15.ttbr0_el1),
1663
.writefn = vmsa_ttbr_write, .resetfn = arm_cp_reset_ignore },
1542
1664
{ .name = "TTBR1", .cp = 15, .crm = 2, .opc1 = 1,
1543
.access = PL1_RW, .type = ARM_CP_64BIT, .readfn = ttbr164_read,
1544
.writefn = ttbr164_write, .resetfn = ttbr164_reset },
1548
static int vbar_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value)
1550
CPREG_FIELD32(env, ri) = value & ~0x1f;
1554
static const ARMCPRegInfo trustzone_cp_reginfo[] = {
1555
/* Dummy implementations of registers; we don't enforce the
1556
* 'secure mode only' access checks. TODO: revisit as part of
1557
* proper fake-trustzone support.
1559
{ .name = "SCR", .cp = 15, .crn = 1, .crm = 1, .opc1 = 0, .opc2 = 0,
1560
.access = PL1_RW, .fieldoffset = offsetof(CPUARMState, cp15.c1_scr),
1562
{ .name = "SDER", .cp = 15, .crn = 1, .crm = 1, .opc1 = 0, .opc2 = 1,
1563
.access = PL1_RW, .fieldoffset = offsetof(CPUARMState, cp15.c1_sedbg),
1565
{ .name = "NSACR", .cp = 15, .crn = 1, .crm = 1, .opc1 = 0, .opc2 = 2,
1566
.access = PL1_RW, .fieldoffset = offsetof(CPUARMState, cp15.c1_nseac),
1568
{ .name = "VBAR", .cp = 15, .crn = 12, .crm = 0, .opc1 = 0, .opc2 = 0,
1569
.access = PL1_RW, .writefn = vbar_write,
1570
.fieldoffset = offsetof(CPUARMState, cp15.c12_vbar),
1572
{ .name = "MVBAR", .cp = 15, .crn = 12, .crm = 0, .opc1 = 0, .opc2 = 1,
1573
.access = PL1_RW, .fieldoffset = offsetof(CPUARMState, cp15.c12_mvbar),
1574
.writefn = vbar_write, .resetvalue = 0 },
1578
static int aa64_fpcr_read(CPUARMState *env, const ARMCPRegInfo *ri,
1581
*value = vfp_get_fpcr(env);
1585
static int aa64_fpcr_write(CPUARMState *env, const ARMCPRegInfo *ri,
1665
.access = PL1_RW, .type = ARM_CP_64BIT | ARM_CP_NO_MIGRATE,
1666
.fieldoffset = offsetof(CPUARMState, cp15.ttbr1_el1),
1667
.writefn = vmsa_ttbr_write, .resetfn = arm_cp_reset_ignore },
1671
static uint64_t aa64_fpcr_read(CPUARMState *env, const ARMCPRegInfo *ri)
1673
return vfp_get_fpcr(env);
1676
static void aa64_fpcr_write(CPUARMState *env, const ARMCPRegInfo *ri,
1588
1679
vfp_set_fpcr(env, value);
1592
static int aa64_fpsr_read(CPUARMState *env, const ARMCPRegInfo *ri,
1682
static uint64_t aa64_fpsr_read(CPUARMState *env, const ARMCPRegInfo *ri)
1595
*value = vfp_get_fpsr(env);
1684
return vfp_get_fpsr(env);
1599
static int aa64_fpsr_write(CPUARMState *env, const ARMCPRegInfo *ri,
1687
static void aa64_fpsr_write(CPUARMState *env, const ARMCPRegInfo *ri,
1602
1690
vfp_set_fpsr(env, value);
1693
static CPAccessResult aa64_cacheop_access(CPUARMState *env,
1694
const ARMCPRegInfo *ri)
1696
/* Cache invalidate/clean: NOP, but EL0 must UNDEF unless
1697
* SCTLR_EL1.UCI is set.
1699
if (arm_current_pl(env) == 0 && !(env->cp15.c1_sys & SCTLR_UCI)) {
1700
return CP_ACCESS_TRAP;
1702
return CP_ACCESS_OK;
1705
static void tlbi_aa64_va_write(CPUARMState *env, const ARMCPRegInfo *ri,
1708
/* Invalidate by VA (AArch64 version) */
1709
ARMCPU *cpu = arm_env_get_cpu(env);
1710
uint64_t pageaddr = value << 12;
1711
tlb_flush_page(CPU(cpu), pageaddr);
1714
static void tlbi_aa64_vaa_write(CPUARMState *env, const ARMCPRegInfo *ri,
1717
/* Invalidate by VA, all ASIDs (AArch64 version) */
1718
ARMCPU *cpu = arm_env_get_cpu(env);
1719
uint64_t pageaddr = value << 12;
1720
tlb_flush_page(CPU(cpu), pageaddr);
1723
static void tlbi_aa64_asid_write(CPUARMState *env, const ARMCPRegInfo *ri,
1726
/* Invalidate by ASID (AArch64 version) */
1727
ARMCPU *cpu = arm_env_get_cpu(env);
1728
int asid = extract64(value, 48, 16);
1729
tlb_flush(CPU(cpu), asid == 0);
1606
1732
static const ARMCPRegInfo v8_cp_reginfo[] = {
1630
1749
.opc0 = 3, .opc1 = 3, .opc2 = 7, .crn = 0, .crm = 0,
1631
1750
.access = PL0_R, .type = ARM_CP_CONST,
1632
1751
.resetvalue = 0x10 },
1752
{ .name = "CURRENTEL", .state = ARM_CP_STATE_AA64,
1753
.opc0 = 3, .opc1 = 0, .opc2 = 2, .crn = 4, .crm = 2,
1754
.access = PL1_R, .type = ARM_CP_CURRENTEL },
1755
/* Cache ops: all NOPs since we don't emulate caches */
1756
{ .name = "IC_IALLUIS", .state = ARM_CP_STATE_AA64,
1757
.opc0 = 1, .opc1 = 0, .crn = 7, .crm = 1, .opc2 = 0,
1758
.access = PL1_W, .type = ARM_CP_NOP },
1759
{ .name = "IC_IALLU", .state = ARM_CP_STATE_AA64,
1760
.opc0 = 1, .opc1 = 0, .crn = 7, .crm = 5, .opc2 = 0,
1761
.access = PL1_W, .type = ARM_CP_NOP },
1762
{ .name = "IC_IVAU", .state = ARM_CP_STATE_AA64,
1763
.opc0 = 1, .opc1 = 3, .crn = 7, .crm = 5, .opc2 = 1,
1764
.access = PL0_W, .type = ARM_CP_NOP,
1765
.accessfn = aa64_cacheop_access },
1766
{ .name = "DC_IVAC", .state = ARM_CP_STATE_AA64,
1767
.opc0 = 1, .opc1 = 0, .crn = 7, .crm = 6, .opc2 = 1,
1768
.access = PL1_W, .type = ARM_CP_NOP },
1769
{ .name = "DC_ISW", .state = ARM_CP_STATE_AA64,
1770
.opc0 = 1, .opc1 = 0, .crn = 7, .crm = 6, .opc2 = 2,
1771
.access = PL1_W, .type = ARM_CP_NOP },
1772
{ .name = "DC_CVAC", .state = ARM_CP_STATE_AA64,
1773
.opc0 = 1, .opc1 = 3, .crn = 7, .crm = 10, .opc2 = 1,
1774
.access = PL0_W, .type = ARM_CP_NOP,
1775
.accessfn = aa64_cacheop_access },
1776
{ .name = "DC_CSW", .state = ARM_CP_STATE_AA64,
1777
.opc0 = 1, .opc1 = 0, .crn = 7, .crm = 10, .opc2 = 2,
1778
.access = PL1_W, .type = ARM_CP_NOP },
1779
{ .name = "DC_CVAU", .state = ARM_CP_STATE_AA64,
1780
.opc0 = 1, .opc1 = 3, .crn = 7, .crm = 11, .opc2 = 1,
1781
.access = PL0_W, .type = ARM_CP_NOP,
1782
.accessfn = aa64_cacheop_access },
1783
{ .name = "DC_CIVAC", .state = ARM_CP_STATE_AA64,
1784
.opc0 = 1, .opc1 = 3, .crn = 7, .crm = 14, .opc2 = 1,
1785
.access = PL0_W, .type = ARM_CP_NOP,
1786
.accessfn = aa64_cacheop_access },
1787
{ .name = "DC_CISW", .state = ARM_CP_STATE_AA64,
1788
.opc0 = 1, .opc1 = 0, .crn = 7, .crm = 14, .opc2 = 2,
1789
.access = PL1_W, .type = ARM_CP_NOP },
1790
/* TLBI operations */
1791
{ .name = "TLBI_VMALLE1IS", .state = ARM_CP_STATE_AA64,
1792
.opc0 = 1, .opc2 = 0, .crn = 8, .crm = 3, .opc2 = 0,
1793
.access = PL1_W, .type = ARM_CP_NO_MIGRATE,
1794
.writefn = tlbiall_write },
1795
{ .name = "TLBI_VAE1IS", .state = ARM_CP_STATE_AA64,
1796
.opc0 = 1, .opc2 = 0, .crn = 8, .crm = 3, .opc2 = 1,
1797
.access = PL1_W, .type = ARM_CP_NO_MIGRATE,
1798
.writefn = tlbi_aa64_va_write },
1799
{ .name = "TLBI_ASIDE1IS", .state = ARM_CP_STATE_AA64,
1800
.opc0 = 1, .opc2 = 0, .crn = 8, .crm = 3, .opc2 = 2,
1801
.access = PL1_W, .type = ARM_CP_NO_MIGRATE,
1802
.writefn = tlbi_aa64_asid_write },
1803
{ .name = "TLBI_VAAE1IS", .state = ARM_CP_STATE_AA64,
1804
.opc0 = 1, .opc2 = 0, .crn = 8, .crm = 3, .opc2 = 3,
1805
.access = PL1_W, .type = ARM_CP_NO_MIGRATE,
1806
.writefn = tlbi_aa64_vaa_write },
1807
{ .name = "TLBI_VALE1IS", .state = ARM_CP_STATE_AA64,
1808
.opc0 = 1, .opc2 = 0, .crn = 8, .crm = 3, .opc2 = 5,
1809
.access = PL1_W, .type = ARM_CP_NO_MIGRATE,
1810
.writefn = tlbi_aa64_va_write },
1811
{ .name = "TLBI_VAALE1IS", .state = ARM_CP_STATE_AA64,
1812
.opc0 = 1, .opc2 = 0, .crn = 8, .crm = 3, .opc2 = 7,
1813
.access = PL1_W, .type = ARM_CP_NO_MIGRATE,
1814
.writefn = tlbi_aa64_vaa_write },
1815
{ .name = "TLBI_VMALLE1", .state = ARM_CP_STATE_AA64,
1816
.opc0 = 1, .opc2 = 0, .crn = 8, .crm = 7, .opc2 = 0,
1817
.access = PL1_W, .type = ARM_CP_NO_MIGRATE,
1818
.writefn = tlbiall_write },
1819
{ .name = "TLBI_VAE1", .state = ARM_CP_STATE_AA64,
1820
.opc0 = 1, .opc2 = 0, .crn = 8, .crm = 7, .opc2 = 1,
1821
.access = PL1_W, .type = ARM_CP_NO_MIGRATE,
1822
.writefn = tlbi_aa64_va_write },
1823
{ .name = "TLBI_ASIDE1", .state = ARM_CP_STATE_AA64,
1824
.opc0 = 1, .opc2 = 0, .crn = 8, .crm = 7, .opc2 = 2,
1825
.access = PL1_W, .type = ARM_CP_NO_MIGRATE,
1826
.writefn = tlbi_aa64_asid_write },
1827
{ .name = "TLBI_VAAE1", .state = ARM_CP_STATE_AA64,
1828
.opc0 = 1, .opc2 = 0, .crn = 8, .crm = 7, .opc2 = 3,
1829
.access = PL1_W, .type = ARM_CP_NO_MIGRATE,
1830
.writefn = tlbi_aa64_vaa_write },
1831
{ .name = "TLBI_VALE1", .state = ARM_CP_STATE_AA64,
1832
.opc0 = 1, .opc2 = 0, .crn = 8, .crm = 7, .opc2 = 5,
1833
.access = PL1_W, .type = ARM_CP_NO_MIGRATE,
1834
.writefn = tlbi_aa64_va_write },
1835
{ .name = "TLBI_VAALE1", .state = ARM_CP_STATE_AA64,
1836
.opc0 = 1, .opc2 = 0, .crn = 8, .crm = 7, .opc2 = 7,
1837
.access = PL1_W, .type = ARM_CP_NO_MIGRATE,
1838
.writefn = tlbi_aa64_vaa_write },
1839
/* Dummy implementation of monitor debug system control register:
1840
* we don't support debug.
1842
{ .name = "MDSCR_EL1", .state = ARM_CP_STATE_AA64,
1843
.opc0 = 2, .opc1 = 0, .crn = 0, .crm = 2, .opc2 = 2,
1844
.access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 },
1845
/* We define a dummy WI OSLAR_EL1, because Linux writes to it. */
1846
{ .name = "OSLAR_EL1", .state = ARM_CP_STATE_AA64,
1847
.opc0 = 2, .opc1 = 0, .crn = 1, .crm = 0, .opc2 = 4,
1848
.access = PL1_W, .type = ARM_CP_NOP },
1633
1849
REGINFO_SENTINEL
1636
static int sctlr_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value)
1852
static void sctlr_write(CPUARMState *env, const ARMCPRegInfo *ri,
1855
ARMCPU *cpu = arm_env_get_cpu(env);
1638
1857
env->cp15.c1_sys = value;
1639
1858
/* ??? Lots of these bits are not implemented. */
1640
1859
/* This may enable/disable the MMU, so do a TLB flush. */
1860
tlb_flush(CPU(cpu), 1);
1863
static CPAccessResult ctr_el0_access(CPUARMState *env, const ARMCPRegInfo *ri)
1865
/* Only accessible in EL0 if SCTLR.UCT is set (and only in AArch64,
1866
* but the AArch32 CTR has its own reginfo struct)
1868
if (arm_current_pl(env) == 0 && !(env->cp15.c1_sys & SCTLR_UCT)) {
1869
return CP_ACCESS_TRAP;
1871
return CP_ACCESS_OK;
1874
static void define_aarch64_debug_regs(ARMCPU *cpu)
1876
/* Define breakpoint and watchpoint registers. These do nothing
1877
* but read as written, for now.
1881
for (i = 0; i < 16; i++) {
1882
ARMCPRegInfo dbgregs[] = {
1883
{ .name = "DBGBVR", .state = ARM_CP_STATE_AA64,
1884
.opc0 = 2, .opc1 = 0, .crn = 0, .crm = i, .opc2 = 4,
1886
.fieldoffset = offsetof(CPUARMState, cp15.dbgbvr[i]) },
1887
{ .name = "DBGBCR", .state = ARM_CP_STATE_AA64,
1888
.opc0 = 2, .opc1 = 0, .crn = 0, .crm = i, .opc2 = 5,
1890
.fieldoffset = offsetof(CPUARMState, cp15.dbgbcr[i]) },
1891
{ .name = "DBGWVR", .state = ARM_CP_STATE_AA64,
1892
.opc0 = 2, .opc1 = 0, .crn = 0, .crm = i, .opc2 = 6,
1894
.fieldoffset = offsetof(CPUARMState, cp15.dbgwvr[i]) },
1895
{ .name = "DBGWCR", .state = ARM_CP_STATE_AA64,
1896
.opc0 = 2, .opc1 = 0, .crn = 0, .crm = i, .opc2 = 7,
1898
.fieldoffset = offsetof(CPUARMState, cp15.dbgwcr[i]) },
1901
define_arm_cp_regs(cpu, dbgregs);
1645
1905
void register_cp_regs_for_features(ARMCPU *cpu)
1717
1977
if (arm_feature(env, ARM_FEATURE_V7)) {
1718
1978
/* v7 performance monitor control register: same implementor
1719
* field as main ID register, and we implement no event counters.
1979
* field as main ID register, and we implement only the cycle
1982
#ifndef CONFIG_USER_ONLY
1721
1983
ARMCPRegInfo pmcr = {
1722
1984
.name = "PMCR", .cp = 15, .crn = 9, .crm = 12, .opc1 = 0, .opc2 = 0,
1723
1985
.access = PL0_RW, .resetvalue = cpu->midr & 0xff000000,
1724
1987
.fieldoffset = offsetof(CPUARMState, cp15.c9_pmcr),
1725
.readfn = pmreg_read, .writefn = pmcr_write,
1726
.raw_readfn = raw_read, .raw_writefn = raw_write,
1988
.accessfn = pmreg_access, .writefn = pmcr_write,
1989
.raw_writefn = raw_write,
1991
define_one_arm_cp_reg(cpu, &pmcr);
1728
1993
ARMCPRegInfo clidr = {
1729
.name = "CLIDR", .cp = 15, .crn = 0, .crm = 0, .opc1 = 1, .opc2 = 1,
1994
.name = "CLIDR", .state = ARM_CP_STATE_BOTH,
1995
.opc0 = 3, .crn = 0, .crm = 0, .opc1 = 1, .opc2 = 1,
1730
1996
.access = PL1_R, .type = ARM_CP_CONST, .resetvalue = cpu->clidr
1732
define_one_arm_cp_reg(cpu, &pmcr);
1733
1998
define_one_arm_cp_reg(cpu, &clidr);
1734
1999
define_arm_cp_regs(cpu, v7_cp_reginfo);
1736
2001
define_arm_cp_regs(cpu, not_v7_cp_reginfo);
1738
2003
if (arm_feature(env, ARM_FEATURE_V8)) {
2004
/* AArch64 ID registers, which all have impdef reset values */
2005
ARMCPRegInfo v8_idregs[] = {
2006
{ .name = "ID_AA64PFR0_EL1", .state = ARM_CP_STATE_AA64,
2007
.opc0 = 3, .opc1 = 0, .crn = 0, .crm = 4, .opc2 = 0,
2008
.access = PL1_R, .type = ARM_CP_CONST,
2009
.resetvalue = cpu->id_aa64pfr0 },
2010
{ .name = "ID_AA64PFR1_EL1", .state = ARM_CP_STATE_AA64,
2011
.opc0 = 3, .opc1 = 0, .crn = 0, .crm = 4, .opc2 = 1,
2012
.access = PL1_R, .type = ARM_CP_CONST,
2013
.resetvalue = cpu->id_aa64pfr1},
2014
{ .name = "ID_AA64DFR0_EL1", .state = ARM_CP_STATE_AA64,
2015
.opc0 = 3, .opc1 = 0, .crn = 0, .crm = 5, .opc2 = 0,
2016
.access = PL1_R, .type = ARM_CP_CONST,
2017
.resetvalue = cpu->id_aa64dfr0 },
2018
{ .name = "ID_AA64DFR1_EL1", .state = ARM_CP_STATE_AA64,
2019
.opc0 = 3, .opc1 = 0, .crn = 0, .crm = 5, .opc2 = 1,
2020
.access = PL1_R, .type = ARM_CP_CONST,
2021
.resetvalue = cpu->id_aa64dfr1 },
2022
{ .name = "ID_AA64AFR0_EL1", .state = ARM_CP_STATE_AA64,
2023
.opc0 = 3, .opc1 = 0, .crn = 0, .crm = 5, .opc2 = 4,
2024
.access = PL1_R, .type = ARM_CP_CONST,
2025
.resetvalue = cpu->id_aa64afr0 },
2026
{ .name = "ID_AA64AFR1_EL1", .state = ARM_CP_STATE_AA64,
2027
.opc0 = 3, .opc1 = 0, .crn = 0, .crm = 5, .opc2 = 5,
2028
.access = PL1_R, .type = ARM_CP_CONST,
2029
.resetvalue = cpu->id_aa64afr1 },
2030
{ .name = "ID_AA64ISAR0_EL1", .state = ARM_CP_STATE_AA64,
2031
.opc0 = 3, .opc1 = 0, .crn = 0, .crm = 6, .opc2 = 0,
2032
.access = PL1_R, .type = ARM_CP_CONST,
2033
.resetvalue = cpu->id_aa64isar0 },
2034
{ .name = "ID_AA64ISAR1_EL1", .state = ARM_CP_STATE_AA64,
2035
.opc0 = 3, .opc1 = 0, .crn = 0, .crm = 6, .opc2 = 1,
2036
.access = PL1_R, .type = ARM_CP_CONST,
2037
.resetvalue = cpu->id_aa64isar1 },
2038
{ .name = "ID_AA64MMFR0_EL1", .state = ARM_CP_STATE_AA64,
2039
.opc0 = 3, .opc1 = 0, .crn = 0, .crm = 7, .opc2 = 0,
2040
.access = PL1_R, .type = ARM_CP_CONST,
2041
.resetvalue = cpu->id_aa64mmfr0 },
2042
{ .name = "ID_AA64MMFR1_EL1", .state = ARM_CP_STATE_AA64,
2043
.opc0 = 3, .opc1 = 0, .crn = 0, .crm = 7, .opc2 = 1,
2044
.access = PL1_R, .type = ARM_CP_CONST,
2045
.resetvalue = cpu->id_aa64mmfr1 },
2048
define_arm_cp_regs(cpu, v8_idregs);
1739
2049
define_arm_cp_regs(cpu, v8_cp_reginfo);
2050
define_aarch64_debug_regs(cpu);
1741
2052
if (arm_feature(env, ARM_FEATURE_MPU)) {
1742
2053
/* These are the MPU registers prior to PMSAv6. Any new
4221
4555
return float64_div(int64_to_float64(q_int, s), float64_256, s);
4224
float32 HELPER(recpe_f32)(float32 a, CPUARMState *env)
4226
float_status *s = &env->vfp.standard_fp_status;
4228
uint32_t val32 = float32_val(a);
4231
int a_exp = (val32 & 0x7f800000) >> 23;
4232
int sign = val32 & 0x80000000;
4234
if (float32_is_any_nan(a)) {
4235
if (float32_is_signaling_nan(a)) {
4236
float_raise(float_flag_invalid, s);
4238
return float32_default_nan;
4239
} else if (float32_is_infinity(a)) {
4240
return float32_set_sign(float32_zero, float32_is_neg(a));
4241
} else if (float32_is_zero_or_denormal(a)) {
4242
if (!float32_is_zero(a)) {
4243
float_raise(float_flag_input_denormal, s);
4245
float_raise(float_flag_divbyzero, s);
4246
return float32_set_sign(float32_infinity, float32_is_neg(a));
4247
} else if (a_exp >= 253) {
4248
float_raise(float_flag_underflow, s);
4249
return float32_set_sign(float32_zero, float32_is_neg(a));
4252
f64 = make_float64((0x3feULL << 52)
4253
| ((int64_t)(val32 & 0x7fffff) << 29));
4255
result_exp = 253 - a_exp;
4257
f64 = recip_estimate(f64, env);
4260
| ((result_exp & 0xff) << 23)
4261
| ((float64_val(f64) >> 29) & 0x7fffff);
4262
return make_float32(val32);
4558
/* Common wrapper to call recip_estimate */
4559
static float64 call_recip_estimate(float64 num, int off, float_status *fpst)
4561
uint64_t val64 = float64_val(num);
4562
uint64_t frac = extract64(val64, 0, 52);
4563
int64_t exp = extract64(val64, 52, 11);
4565
float64 scaled, estimate;
4567
/* Generate the scaled number for the estimate function */
4569
if (extract64(frac, 51, 1) == 0) {
4571
frac = extract64(frac, 0, 50) << 2;
4573
frac = extract64(frac, 0, 51) << 1;
4577
/* scaled = '0' : '01111111110' : fraction<51:44> : Zeros(44); */
4578
scaled = make_float64((0x3feULL << 52)
4579
| extract64(frac, 44, 8) << 44);
4581
estimate = recip_estimate(scaled, fpst);
4583
/* Build new result */
4584
val64 = float64_val(estimate);
4585
sbit = 0x8000000000000000ULL & val64;
4587
frac = extract64(val64, 0, 52);
4590
frac = 1ULL << 51 | extract64(frac, 1, 51);
4591
} else if (exp == -1) {
4592
frac = 1ULL << 50 | extract64(frac, 2, 50);
4596
return make_float64(sbit | (exp << 52) | frac);
4599
static bool round_to_inf(float_status *fpst, bool sign_bit)
4601
switch (fpst->float_rounding_mode) {
4602
case float_round_nearest_even: /* Round to Nearest */
4604
case float_round_up: /* Round to +Inf */
4606
case float_round_down: /* Round to -Inf */
4608
case float_round_to_zero: /* Round to Zero */
4612
g_assert_not_reached();
4615
float32 HELPER(recpe_f32)(float32 input, void *fpstp)
4617
float_status *fpst = fpstp;
4618
float32 f32 = float32_squash_input_denormal(input, fpst);
4619
uint32_t f32_val = float32_val(f32);
4620
uint32_t f32_sbit = 0x80000000ULL & f32_val;
4621
int32_t f32_exp = extract32(f32_val, 23, 8);
4622
uint32_t f32_frac = extract32(f32_val, 0, 23);
4628
if (float32_is_any_nan(f32)) {
4630
if (float32_is_signaling_nan(f32)) {
4631
float_raise(float_flag_invalid, fpst);
4632
nan = float32_maybe_silence_nan(f32);
4634
if (fpst->default_nan_mode) {
4635
nan = float32_default_nan;
4638
} else if (float32_is_infinity(f32)) {
4639
return float32_set_sign(float32_zero, float32_is_neg(f32));
4640
} else if (float32_is_zero(f32)) {
4641
float_raise(float_flag_divbyzero, fpst);
4642
return float32_set_sign(float32_infinity, float32_is_neg(f32));
4643
} else if ((f32_val & ~(1ULL << 31)) < (1ULL << 21)) {
4644
/* Abs(value) < 2.0^-128 */
4645
float_raise(float_flag_overflow | float_flag_inexact, fpst);
4646
if (round_to_inf(fpst, f32_sbit)) {
4647
return float32_set_sign(float32_infinity, float32_is_neg(f32));
4649
return float32_set_sign(float32_maxnorm, float32_is_neg(f32));
4651
} else if (f32_exp >= 253 && fpst->flush_to_zero) {
4652
float_raise(float_flag_underflow, fpst);
4653
return float32_set_sign(float32_zero, float32_is_neg(f32));
4657
f64 = make_float64(((int64_t)(f32_exp) << 52) | (int64_t)(f32_frac) << 29);
4658
r64 = call_recip_estimate(f64, 253, fpst);
4659
r64_val = float64_val(r64);
4660
r64_exp = extract64(r64_val, 52, 11);
4661
r64_frac = extract64(r64_val, 0, 52);
4663
/* result = sign : result_exp<7:0> : fraction<51:29>; */
4664
return make_float32(f32_sbit |
4665
(r64_exp & 0xff) << 23 |
4666
extract64(r64_frac, 29, 24));
4669
float64 HELPER(recpe_f64)(float64 input, void *fpstp)
4671
float_status *fpst = fpstp;
4672
float64 f64 = float64_squash_input_denormal(input, fpst);
4673
uint64_t f64_val = float64_val(f64);
4674
uint64_t f64_sbit = 0x8000000000000000ULL & f64_val;
4675
int64_t f64_exp = extract64(f64_val, 52, 11);
4681
/* Deal with any special cases */
4682
if (float64_is_any_nan(f64)) {
4684
if (float64_is_signaling_nan(f64)) {
4685
float_raise(float_flag_invalid, fpst);
4686
nan = float64_maybe_silence_nan(f64);
4688
if (fpst->default_nan_mode) {
4689
nan = float64_default_nan;
4692
} else if (float64_is_infinity(f64)) {
4693
return float64_set_sign(float64_zero, float64_is_neg(f64));
4694
} else if (float64_is_zero(f64)) {
4695
float_raise(float_flag_divbyzero, fpst);
4696
return float64_set_sign(float64_infinity, float64_is_neg(f64));
4697
} else if ((f64_val & ~(1ULL << 63)) < (1ULL << 50)) {
4698
/* Abs(value) < 2.0^-1024 */
4699
float_raise(float_flag_overflow | float_flag_inexact, fpst);
4700
if (round_to_inf(fpst, f64_sbit)) {
4701
return float64_set_sign(float64_infinity, float64_is_neg(f64));
4703
return float64_set_sign(float64_maxnorm, float64_is_neg(f64));
4705
} else if (f64_exp >= 1023 && fpst->flush_to_zero) {
4706
float_raise(float_flag_underflow, fpst);
4707
return float64_set_sign(float64_zero, float64_is_neg(f64));
4710
r64 = call_recip_estimate(f64, 2045, fpst);
4711
r64_val = float64_val(r64);
4712
r64_exp = extract64(r64_val, 52, 11);
4713
r64_frac = extract64(r64_val, 0, 52);
4715
/* result = sign : result_exp<10:0> : fraction<51:0> */
4716
return make_float64(f64_sbit |
4717
((r64_exp & 0x7ff) << 52) |
4265
4721
/* The algorithm that must be used to calculate the estimate
4266
4722
* is specified by the ARM ARM.
4268
static float64 recip_sqrt_estimate(float64 a, CPUARMState *env)
4724
static float64 recip_sqrt_estimate(float64 a, float_status *real_fp_status)
4270
4726
/* These calculations mustn't set any fp exception flags,
4271
4727
* so we use a local copy of the fp_status.
4273
float_status dummy_status = env->vfp.standard_fp_status;
4729
float_status dummy_status = *real_fp_status;
4274
4730
float_status *s = &dummy_status;
4317
4773
return float64_div(int64_to_float64(q_int, s), float64_256, s);
4320
float32 HELPER(rsqrte_f32)(float32 a, CPUARMState *env)
4776
float32 HELPER(rsqrte_f32)(float32 input, void *fpstp)
4322
float_status *s = &env->vfp.standard_fp_status;
4778
float_status *s = fpstp;
4779
float32 f32 = float32_squash_input_denormal(input, s);
4780
uint32_t val = float32_val(f32);
4781
uint32_t f32_sbit = 0x80000000 & val;
4782
int32_t f32_exp = extract32(val, 23, 8);
4783
uint32_t f32_frac = extract32(val, 0, 23);
4326
4785
uint64_t val64;
4328
val = float32_val(a);
4330
if (float32_is_any_nan(a)) {
4331
if (float32_is_signaling_nan(a)) {
4789
if (float32_is_any_nan(f32)) {
4791
if (float32_is_signaling_nan(f32)) {
4332
4792
float_raise(float_flag_invalid, s);
4334
return float32_default_nan;
4335
} else if (float32_is_zero_or_denormal(a)) {
4336
if (!float32_is_zero(a)) {
4337
float_raise(float_flag_input_denormal, s);
4793
nan = float32_maybe_silence_nan(f32);
4795
if (s->default_nan_mode) {
4796
nan = float32_default_nan;
4799
} else if (float32_is_zero(f32)) {
4339
4800
float_raise(float_flag_divbyzero, s);
4340
return float32_set_sign(float32_infinity, float32_is_neg(a));
4341
} else if (float32_is_neg(a)) {
4801
return float32_set_sign(float32_infinity, float32_is_neg(f32));
4802
} else if (float32_is_neg(f32)) {
4342
4803
float_raise(float_flag_invalid, s);
4343
4804
return float32_default_nan;
4344
} else if (float32_is_infinity(a)) {
4805
} else if (float32_is_infinity(f32)) {
4345
4806
return float32_zero;
4348
/* Normalize to a double-precision value between 0.25 and 1.0,
4809
/* Scale and normalize to a double-precision value between 0.25 and 1.0,
4349
4810
* preserving the parity of the exponent. */
4350
if ((val & 0x800000) == 0) {
4351
f64 = make_float64(((uint64_t)(val & 0x80000000) << 32)
4812
f64_frac = ((uint64_t) f32_frac) << 29;
4814
while (extract64(f64_frac, 51, 1) == 0) {
4815
f64_frac = f64_frac << 1;
4816
f32_exp = f32_exp-1;
4818
f64_frac = extract64(f64_frac, 0, 51) << 1;
4821
if (extract64(f32_exp, 0, 1) == 0) {
4822
f64 = make_float64(((uint64_t) f32_sbit) << 32
4352
4823
| (0x3feULL << 52)
4353
| ((uint64_t)(val & 0x7fffff) << 29));
4355
f64 = make_float64(((uint64_t)(val & 0x80000000) << 32)
4826
f64 = make_float64(((uint64_t) f32_sbit) << 32
4356
4827
| (0x3fdULL << 52)
4357
| ((uint64_t)(val & 0x7fffff) << 29));
4360
result_exp = (380 - ((val & 0x7f800000) >> 23)) / 2;
4831
result_exp = (380 - f32_exp) / 2;
4362
f64 = recip_sqrt_estimate(f64, env);
4833
f64 = recip_sqrt_estimate(f64, s);
4364
4835
val64 = float64_val(f64);