2015-11-24 16:47:59 +08:00
|
|
|
/* memory.c -- Memory accessor functions for the AArch64 simulator
|
|
|
|
|
2018-01-01 12:43:02 +08:00
|
|
|
Copyright (C) 2015-2018 Free Software Foundation, Inc.
|
2015-11-24 16:47:59 +08:00
|
|
|
|
|
|
|
Contributed by Red Hat.
|
|
|
|
|
|
|
|
This file is part of GDB.
|
|
|
|
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
|
|
it under the terms of the GNU General Public License as published by
|
|
|
|
the Free Software Foundation; either version 3 of the License, or
|
|
|
|
(at your option) any later version.
|
|
|
|
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
GNU General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
|
|
|
|
|
|
|
#include "config.h"
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
#include "libiberty.h"
|
|
|
|
|
|
|
|
#include "memory.h"
|
|
|
|
#include "simulator.h"
|
|
|
|
|
|
|
|
#include "sim-core.h"
|
|
|
|
|
|
|
|
static inline void
|
|
|
|
mem_error (sim_cpu *cpu, const char *message, uint64_t addr)
|
|
|
|
{
|
|
|
|
TRACE_MEMORY (cpu, "ERROR: %s: %" PRIx64, message, addr);
|
|
|
|
}
|
|
|
|
|
2016-03-30 17:27:21 +08:00
|
|
|
/* FIXME: AArch64 requires aligned memory access if SCTRLR_ELx.A is set,
|
2016-03-24 01:37:30 +08:00
|
|
|
but we are not implementing that here. */
|
2016-03-30 17:27:21 +08:00
|
|
|
#define FETCH_FUNC64(RETURN_TYPE, ACCESS_TYPE, NAME, N) \
|
2015-11-24 16:47:59 +08:00
|
|
|
RETURN_TYPE \
|
|
|
|
aarch64_get_mem_##NAME (sim_cpu *cpu, uint64_t address) \
|
|
|
|
{ \
|
2016-03-30 17:27:21 +08:00
|
|
|
RETURN_TYPE val = (RETURN_TYPE) (ACCESS_TYPE) \
|
|
|
|
sim_core_read_unaligned_##N (cpu, 0, read_map, address); \
|
|
|
|
TRACE_MEMORY (cpu, "read of %" PRIx64 " (%d bytes) from %" PRIx64, \
|
|
|
|
val, N, address); \
|
|
|
|
\
|
|
|
|
return val; \
|
|
|
|
}
|
|
|
|
|
|
|
|
FETCH_FUNC64 (uint64_t, uint64_t, u64, 8)
|
|
|
|
FETCH_FUNC64 (int64_t, int64_t, s64, 8)
|
|
|
|
|
|
|
|
#define FETCH_FUNC32(RETURN_TYPE, ACCESS_TYPE, NAME, N) \
|
|
|
|
RETURN_TYPE \
|
|
|
|
aarch64_get_mem_##NAME (sim_cpu *cpu, uint64_t address) \
|
|
|
|
{ \
|
|
|
|
RETURN_TYPE val = (RETURN_TYPE) (ACCESS_TYPE) \
|
|
|
|
sim_core_read_unaligned_##N (cpu, 0, read_map, address); \
|
|
|
|
TRACE_MEMORY (cpu, "read of %8x (%d bytes) from %" PRIx64, \
|
|
|
|
val, N, address); \
|
Add simulation of MUL and NEG instructions to AArch64 simulator.
* cpustate.c: Remove spurious spaces from TRACE strings.
Print hex equivalents of floats and doubles.
Check element number against array size when accessing vector
registers.
* memory.c: Trace memory reads when --trace-memory is enabled.
Remove float and double load and store functions.
* memory.h (aarch64_get_mem_float): Delete prototype.
(aarch64_get_mem_double): Likewise.
(aarch64_set_mem_float): Likewise.
(aarch64_set_mem_double): Likewise.
* simulator (IS_SET): Always return either 0 or 1.
(IS_CLEAR): Likewise.
(fldrs_pcrel): Load and store floats using 32-bit memory accesses
and doubles using 64-bit memory accesses.
(fldrd_pcrel, fldrs_wb, fldrs_abs, fldrs_scale_ext): Likewise.
(fldrd_wb, fldrd_abs, fsturs, fsturd, fldurs, fldurd): Likewise.
(fstrs_abs, fstrs_wb, fstrs_scale_ext, fstrd_abs): Likewise.
(fstrd_wb, fstrd_scale_ext, store_pair_float): Likewise.
(store_pair_double, load_pair_float, load_pair_double): Likewise.
(do_vec_MUL_by_element): New function.
(do_vec_op2): Call do_vec_MUL_by_element.
(do_scalar_NEG): New function.
(do_double_add): Call do_scalar_NEG.
2016-03-18 17:32:32 +08:00
|
|
|
\
|
|
|
|
return val; \
|
2015-11-24 16:47:59 +08:00
|
|
|
}
|
|
|
|
|
2016-03-30 17:27:21 +08:00
|
|
|
FETCH_FUNC32 (uint32_t, uint32_t, u32, 4)
|
|
|
|
FETCH_FUNC32 (int32_t, int32_t, s32, 4)
|
|
|
|
FETCH_FUNC32 (uint32_t, uint16_t, u16, 2)
|
|
|
|
FETCH_FUNC32 (int32_t, int16_t, s16, 2)
|
|
|
|
FETCH_FUNC32 (uint32_t, uint8_t, u8, 1)
|
|
|
|
FETCH_FUNC32 (int32_t, int8_t, s8, 1)
|
2015-11-24 16:47:59 +08:00
|
|
|
|
|
|
|
void
|
|
|
|
aarch64_get_mem_long_double (sim_cpu *cpu, uint64_t address, FRegister *a)
|
|
|
|
{
|
|
|
|
a->v[0] = sim_core_read_unaligned_8 (cpu, 0, read_map, address);
|
|
|
|
a->v[1] = sim_core_read_unaligned_8 (cpu, 0, read_map, address + 8);
|
|
|
|
}
|
|
|
|
|
2016-03-24 01:37:30 +08:00
|
|
|
/* FIXME: Aarch64 requires aligned memory access if SCTRLR_ELx.A is set,
|
|
|
|
but we are not implementing that here. */
|
2015-11-24 16:47:59 +08:00
|
|
|
#define STORE_FUNC(TYPE, NAME, N) \
|
|
|
|
void \
|
|
|
|
aarch64_set_mem_##NAME (sim_cpu *cpu, uint64_t address, TYPE value) \
|
|
|
|
{ \
|
|
|
|
TRACE_MEMORY (cpu, \
|
|
|
|
"write of %" PRIx64 " (%d bytes) to %" PRIx64, \
|
|
|
|
(uint64_t) value, N, address); \
|
|
|
|
\
|
|
|
|
sim_core_write_unaligned_##N (cpu, 0, write_map, address, value); \
|
|
|
|
}
|
|
|
|
|
2016-03-24 01:37:30 +08:00
|
|
|
STORE_FUNC (uint64_t, u64, 8)
|
|
|
|
STORE_FUNC (int64_t, s64, 8)
|
|
|
|
STORE_FUNC (uint32_t, u32, 4)
|
|
|
|
STORE_FUNC (int32_t, s32, 4)
|
|
|
|
STORE_FUNC (uint16_t, u16, 2)
|
|
|
|
STORE_FUNC (int16_t, s16, 2)
|
|
|
|
STORE_FUNC (uint8_t, u8, 1)
|
|
|
|
STORE_FUNC (int8_t, s8, 1)
|
2015-11-24 16:47:59 +08:00
|
|
|
|
|
|
|
void
|
|
|
|
aarch64_set_mem_long_double (sim_cpu *cpu, uint64_t address, FRegister a)
|
|
|
|
{
|
|
|
|
TRACE_MEMORY (cpu,
|
|
|
|
"write of long double %" PRIx64 " %" PRIx64 " to %" PRIx64,
|
|
|
|
a.v[0], a.v[1], address);
|
|
|
|
|
|
|
|
sim_core_write_unaligned_8 (cpu, 0, write_map, address, a.v[0]);
|
|
|
|
sim_core_write_unaligned_8 (cpu, 0, write_map, address + 8, a.v[1]);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
aarch64_get_mem_blk (sim_cpu * cpu,
|
|
|
|
uint64_t address,
|
|
|
|
char * buffer,
|
|
|
|
unsigned length)
|
|
|
|
{
|
|
|
|
unsigned len;
|
|
|
|
|
|
|
|
len = sim_core_read_buffer (CPU_STATE (cpu), cpu, read_map,
|
|
|
|
buffer, address, length);
|
|
|
|
if (len == length)
|
|
|
|
return;
|
|
|
|
|
|
|
|
memset (buffer, 0, length);
|
|
|
|
if (cpu)
|
|
|
|
mem_error (cpu, "read of non-existant mem block at", address);
|
|
|
|
|
|
|
|
sim_engine_halt (CPU_STATE (cpu), cpu, NULL, aarch64_get_PC (cpu),
|
|
|
|
sim_stopped, SIM_SIGBUS);
|
|
|
|
}
|
|
|
|
|
|
|
|
const char *
|
|
|
|
aarch64_get_mem_ptr (sim_cpu *cpu, uint64_t address)
|
|
|
|
{
|
|
|
|
char *addr = sim_core_trans_addr (CPU_STATE (cpu), cpu, read_map, address);
|
|
|
|
|
|
|
|
if (addr == NULL)
|
|
|
|
{
|
|
|
|
mem_error (cpu, "request for non-existant mem addr of", address);
|
|
|
|
sim_engine_halt (CPU_STATE (cpu), cpu, NULL, aarch64_get_PC (cpu),
|
|
|
|
sim_stopped, SIM_SIGBUS);
|
|
|
|
}
|
|
|
|
|
|
|
|
return addr;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* We implement a combined stack and heap. That way the sbrk()
|
|
|
|
function in libgloss/aarch64/syscalls.c has a chance to detect
|
|
|
|
an out-of-memory condition by noticing a stack/heap collision.
|
|
|
|
|
|
|
|
The heap starts at the end of loaded memory and carries on up
|
|
|
|
to an arbitary 2Gb limit. */
|
|
|
|
|
|
|
|
uint64_t
|
|
|
|
aarch64_get_heap_start (sim_cpu *cpu)
|
|
|
|
{
|
2016-01-22 11:17:59 +08:00
|
|
|
uint64_t heap = trace_sym_value (CPU_STATE (cpu), "end");
|
2015-11-24 16:47:59 +08:00
|
|
|
|
|
|
|
if (heap == 0)
|
2016-01-22 11:17:59 +08:00
|
|
|
heap = trace_sym_value (CPU_STATE (cpu), "_end");
|
2015-11-24 16:47:59 +08:00
|
|
|
if (heap == 0)
|
|
|
|
{
|
|
|
|
heap = STACK_TOP - 0x100000;
|
|
|
|
sim_io_eprintf (CPU_STATE (cpu),
|
|
|
|
"Unable to find 'end' symbol - using addr based "
|
|
|
|
"upon stack instead %" PRIx64 "\n",
|
|
|
|
heap);
|
|
|
|
}
|
|
|
|
return heap;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint64_t
|
|
|
|
aarch64_get_stack_start (sim_cpu *cpu)
|
|
|
|
{
|
|
|
|
if (aarch64_get_heap_start (cpu) >= STACK_TOP)
|
|
|
|
mem_error (cpu, "executable is too big", aarch64_get_heap_start (cpu));
|
|
|
|
return STACK_TOP;
|
|
|
|
}
|