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.
This commit is contained in:
Nick Clifton 2016-03-18 09:32:32 +00:00
parent 48427a77ec
commit e101a78be9
5 changed files with 350 additions and 232 deletions

View File

@ -1,3 +1,29 @@
2016-03-18 Nick Clifton <nickc@redhat.com>
* 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-03 Nick Clifton <nickc@redhat.com>
* simulator.c (set_flags_for_sub32): Correct type of signbit.

View File

@ -34,13 +34,13 @@ aarch64_set_reg_u64 (sim_cpu *cpu, GReg reg, int r31_is_sp, uint64_t val)
{
if (reg == R31 && ! r31_is_sp)
{
TRACE_REGISTER (cpu, " GR[31] NOT CHANGED!");
TRACE_REGISTER (cpu, "GR[31] NOT CHANGED!");
return;
}
if (val != cpu->gr[reg].u64)
TRACE_REGISTER (cpu,
" GR[%2d] changes from %16" PRIx64 " to %16" PRIx64,
"GR[%2d] changes from %16" PRIx64 " to %16" PRIx64,
reg, cpu->gr[reg].u64, val);
cpu->gr[reg].u64 = val;
@ -51,13 +51,13 @@ aarch64_set_reg_s64 (sim_cpu *cpu, GReg reg, int r31_is_sp, int64_t val)
{
if (reg == R31 && ! r31_is_sp)
{
TRACE_REGISTER (cpu, " GR[31] NOT CHANGED!");
TRACE_REGISTER (cpu, "GR[31] NOT CHANGED!");
return;
}
if (val != cpu->gr[reg].s64)
TRACE_REGISTER (cpu,
" GR[%2d] changes from %16" PRIx64 " to %16" PRIx64,
"GR[%2d] changes from %16" PRIx64 " to %16" PRIx64,
reg, cpu->gr[reg].s64, val);
cpu->gr[reg].s64 = val;
@ -128,7 +128,7 @@ aarch64_set_next_PC (sim_cpu *cpu, uint64_t next)
{
if (next != cpu->nextpc + 4)
TRACE_REGISTER (cpu,
" NextPC changes from %16" PRIx64 " to %16" PRIx64,
"NextPC changes from %16" PRIx64 " to %16" PRIx64,
cpu->nextpc, next);
cpu->nextpc = next;
@ -139,7 +139,7 @@ aarch64_set_next_PC_by_offset (sim_cpu *cpu, int64_t offset)
{
if (cpu->pc + offset != cpu->nextpc + 4)
TRACE_REGISTER (cpu,
" NextPC changes from %16" PRIx64 " to %16" PRIx64,
"NextPC changes from %16" PRIx64 " to %16" PRIx64,
cpu->nextpc, cpu->pc + offset);
cpu->nextpc = cpu->pc + offset;
@ -163,7 +163,7 @@ aarch64_save_LR (sim_cpu *cpu)
{
if (cpu->gr[LR].u64 != cpu->nextpc)
TRACE_REGISTER (cpu,
" LR changes from %16" PRIx64 " to %16" PRIx64,
"LR changes from %16" PRIx64 " to %16" PRIx64,
cpu->gr[LR].u64, cpu->nextpc);
cpu->gr[LR].u64 = cpu->nextpc;
@ -209,11 +209,11 @@ aarch64_set_CPSR (sim_cpu *cpu, uint32_t new_flags)
{
if (cpu->CPSR != new_flags)
TRACE_REGISTER (cpu,
" CPSR changes from %s to %s",
"CPSR changes from %s to %s",
decode_cpsr (cpu->CPSR), decode_cpsr (new_flags));
else
TRACE_REGISTER (cpu,
" CPSR stays at %s", decode_cpsr (cpu->CPSR));
"CPSR stays at %s", decode_cpsr (cpu->CPSR));
}
cpu->CPSR = new_flags & CPSR_ALL_FLAGS;
@ -238,7 +238,7 @@ aarch64_set_CPSR_bits (sim_cpu *cpu, uint32_t mask, uint32_t value)
if (old_flags != cpu->CPSR)
TRACE_REGISTER (cpu,
" CPSR changes from %s to %s",
"CPSR changes from %s to %s",
decode_cpsr (old_flags), decode_cpsr (cpu->CPSR));
}
@ -259,7 +259,7 @@ aarch64_set_CPSR_bit (sim_cpu *cpu, FlagMask bit)
if (old_flags != cpu->CPSR)
TRACE_REGISTER (cpu,
" CPSR changes from %s to %s",
"CPSR changes from %s to %s",
decode_cpsr (old_flags), decode_cpsr (cpu->CPSR));
}
@ -273,7 +273,7 @@ aarch64_clear_CPSR_bit (sim_cpu *cpu, FlagMask bit)
if (old_flags != cpu->CPSR)
TRACE_REGISTER (cpu,
" CPSR changes from %s to %s",
"CPSR changes from %s to %s",
decode_cpsr (old_flags), decode_cpsr (cpu->CPSR));
}
@ -300,9 +300,14 @@ void
aarch64_set_FP_float (sim_cpu *cpu, VReg reg, float val)
{
if (val != cpu->fr[reg].s)
TRACE_REGISTER (cpu,
" FR[%d] changes from %f to %f",
reg, cpu->fr[reg].s, val);
{
FRegister v;
v.s = val;
TRACE_REGISTER (cpu,
"FR[%d].s changes from %f to %f [hex: %0lx]",
reg, cpu->fr[reg].s, val, v.v[0]);
}
cpu->fr[reg].s = val;
}
@ -311,10 +316,14 @@ void
aarch64_set_FP_double (sim_cpu *cpu, VReg reg, double val)
{
if (val != cpu->fr[reg].d)
TRACE_REGISTER (cpu,
" FR[%d] changes from %f to %f",
reg, cpu->fr[reg].d, val);
{
FRegister v;
v.d = val;
TRACE_REGISTER (cpu,
"FR[%d].d changes from %f to %f [hex: %0lx]",
reg, cpu->fr[reg].d, val, v.v[0]);
}
cpu->fr[reg].d = val;
}
@ -324,7 +333,7 @@ aarch64_set_FP_long_double (sim_cpu *cpu, VReg reg, FRegister a)
if (cpu->fr[reg].v[0] != a.v[0]
|| cpu->fr[reg].v[1] != a.v[1])
TRACE_REGISTER (cpu,
" FR[%d] changes from [%0lx %0lx] to [%lx %lx] ",
"FR[%d].q changes from [%0lx %0lx] to [%0lx %0lx] ",
reg,
cpu->fr[reg].v[0], cpu->fr[reg].v[1],
a.v[0], a.v[1]);
@ -333,82 +342,161 @@ aarch64_set_FP_long_double (sim_cpu *cpu, VReg reg, FRegister a)
cpu->fr[reg].v[1] = a.v[1];
}
#define GET_VEC_ELEMENT(REG, ELEMENT, FIELD) \
do \
{ \
if (element > ARRAY_SIZE (cpu->fr[0].FIELD)) \
{ \
TRACE_REGISTER (cpu, \
"Internal SIM error: invalid element number: %d ",\
ELEMENT); \
sim_engine_halt (CPU_STATE (cpu), cpu, NULL, aarch64_get_PC (cpu), \
sim_stopped, SIM_SIGBUS); \
} \
return cpu->fr[REG].FIELD [ELEMENT]; \
} \
while (0)
uint64_t
aarch64_get_vec_u64 (sim_cpu *cpu, VReg reg, unsigned element)
{
return cpu->fr[reg].v[element];
GET_VEC_ELEMENT (reg, element, v);
}
uint32_t
aarch64_get_vec_u32 (sim_cpu *cpu, VReg regno, unsigned element)
aarch64_get_vec_u32 (sim_cpu *cpu, VReg reg, unsigned element)
{
return cpu->fr[regno].w[element];
GET_VEC_ELEMENT (reg, element, w);
}
uint16_t
aarch64_get_vec_u16 (sim_cpu *cpu, VReg regno, unsigned element)
aarch64_get_vec_u16 (sim_cpu *cpu, VReg reg, unsigned element)
{
return cpu->fr[regno].h[element];
GET_VEC_ELEMENT (reg, element, h);
}
uint8_t
aarch64_get_vec_u8 (sim_cpu *cpu, VReg regno, unsigned element)
aarch64_get_vec_u8 (sim_cpu *cpu, VReg reg, unsigned element)
{
return cpu->fr[regno].b[element];
GET_VEC_ELEMENT (reg, element, b);
}
int64_t
aarch64_get_vec_s64 (sim_cpu *cpu, VReg reg, unsigned element)
{
GET_VEC_ELEMENT (reg, element, V);
}
int32_t
aarch64_get_vec_s32 (sim_cpu *cpu, VReg reg, unsigned element)
{
GET_VEC_ELEMENT (reg, element, W);
}
int16_t
aarch64_get_vec_s16 (sim_cpu *cpu, VReg reg, unsigned element)
{
GET_VEC_ELEMENT (reg, element, H);
}
int8_t
aarch64_get_vec_s8 (sim_cpu *cpu, VReg reg, unsigned element)
{
GET_VEC_ELEMENT (reg, element, B);
}
float
aarch64_get_vec_float (sim_cpu *cpu, VReg reg, unsigned element)
{
GET_VEC_ELEMENT (reg, element, S);
}
double
aarch64_get_vec_double (sim_cpu *cpu, VReg reg, unsigned element)
{
GET_VEC_ELEMENT (reg, element, D);
}
#define SET_VEC_ELEMENT(REG, ELEMENT, VAL, FIELD, PRINTER) \
do \
{ \
if (ELEMENT > ARRAY_SIZE (cpu->fr[0].FIELD)) \
{ \
TRACE_REGISTER (cpu, \
"Internal SIM error: invalid element number: %d ",\
ELEMENT); \
sim_engine_halt (CPU_STATE (cpu), cpu, NULL, aarch64_get_PC (cpu), \
sim_stopped, SIM_SIGBUS); \
} \
if (VAL != cpu->fr[REG].FIELD [ELEMENT]) \
TRACE_REGISTER (cpu, \
"VR[%2d]." #FIELD " [%d] changes from " PRINTER \
" to " PRINTER , REG, \
ELEMENT, cpu->fr[REG].FIELD [ELEMENT], VAL); \
\
cpu->fr[REG].FIELD [ELEMENT] = VAL; \
} \
while (0)
void
aarch64_set_vec_u64 (sim_cpu * cpu, VReg reg, unsigned element, uint64_t val)
{
SET_VEC_ELEMENT (reg, element, val, v, "%16lx");
}
void
aarch64_set_vec_u64 (sim_cpu * cpu,
VReg regno,
unsigned element,
uint64_t value)
aarch64_set_vec_u32 (sim_cpu * cpu, VReg reg, unsigned element, uint32_t val)
{
if (value != cpu->fr[regno].v[element])
TRACE_REGISTER (cpu,
" VR[%2d].<long>[%d] changes from %16" PRIx64
" to %16" PRIx64,
regno, element, cpu->fr[regno].v[element], value);
cpu->fr[regno].v[element] = value;
SET_VEC_ELEMENT (reg, element, val, w, "%8x");
}
void
aarch64_set_vec_u32 (sim_cpu * cpu,
VReg regno,
unsigned element,
uint32_t value)
aarch64_set_vec_u16 (sim_cpu * cpu, VReg reg, unsigned element, uint16_t val)
{
if (value != cpu->fr[regno].w[element])
TRACE_REGISTER (cpu,
" VR[%2d].<word>[%d] changes from %8x to %8x",
regno, element, cpu->fr[regno].w[element], value);
cpu->fr[regno].w[element] = value;
SET_VEC_ELEMENT (reg, element, val, h, "%4x");
}
void
aarch64_set_vec_u16 (sim_cpu * cpu,
VReg regno,
unsigned element,
uint16_t value)
aarch64_set_vec_u8 (sim_cpu * cpu, VReg reg, unsigned element, uint8_t val)
{
if (value != cpu->fr[regno].h[element])
TRACE_REGISTER (cpu,
" VR[%2d].<half>[%d] changes from %4x to %4x",
regno, element, cpu->fr[regno].h[element], value);
cpu->fr[regno].h[element] = value;
SET_VEC_ELEMENT (reg, element, val, b, "%x");
}
void
aarch64_set_vec_u8 (sim_cpu *cpu, VReg regno, unsigned element, uint8_t value)
aarch64_set_vec_s64 (sim_cpu *cpu, VReg reg, unsigned element, int64_t val)
{
if (value != cpu->fr[regno].b[element])
TRACE_REGISTER (cpu,
" VR[%2d].<byte>[%d] changes from %x to %x",
regno, element, cpu->fr[regno].b[element], value);
SET_VEC_ELEMENT (reg, element, val, V, "%16lx");
}
cpu->fr[regno].b[element] = value;
void
aarch64_set_vec_s32 (sim_cpu *cpu, VReg reg, unsigned element, int32_t val)
{
SET_VEC_ELEMENT (reg, element, val, W, "%8x");
}
void
aarch64_set_vec_s16 (sim_cpu *cpu, VReg reg, unsigned element, int16_t val)
{
SET_VEC_ELEMENT (reg, element, val, H, "%4x");
}
void
aarch64_set_vec_s8 (sim_cpu *cpu, VReg reg, unsigned element, int8_t val)
{
SET_VEC_ELEMENT (reg, element, val, B, "%x");
}
void
aarch64_set_vec_float (sim_cpu *cpu, VReg reg, unsigned element, float val)
{
SET_VEC_ELEMENT (reg, element, val, S, "%f");
}
void
aarch64_set_vec_double (sim_cpu *cpu, VReg reg, unsigned element, double val)
{
SET_VEC_ELEMENT (reg, element, val, D, "%f");
}
void
@ -416,7 +504,7 @@ aarch64_set_FPSR (sim_cpu *cpu, uint32_t value)
{
if (cpu->FPSR != value)
TRACE_REGISTER (cpu,
" FPSR changes from %x to %x", cpu->FPSR, value);
"FPSR changes from %x to %x", cpu->FPSR, value);
cpu->FPSR = value & FPSR_ALL_FPSRS;
}
@ -438,7 +526,7 @@ aarch64_set_FPSR_bits (sim_cpu *cpu, uint32_t mask, uint32_t value)
if (cpu->FPSR != old_FPSR)
TRACE_REGISTER (cpu,
" FPSR changes from %x to %x", old_FPSR, cpu->FPSR);
"FPSR changes from %x to %x", old_FPSR, cpu->FPSR);
}
uint32_t
@ -453,105 +541,3 @@ aarch64_test_FPSR_bit (sim_cpu *cpu, FPSRMask flag)
{
return cpu->FPSR & flag;
}
float
aarch64_get_vec_float (sim_cpu *cpu, VReg v, unsigned e)
{
return cpu->fr[v].S[e];
}
double
aarch64_get_vec_double (sim_cpu *cpu, VReg v, unsigned e)
{
return cpu->fr[v].D[e];
}
void
aarch64_set_vec_float (sim_cpu *cpu, VReg v, unsigned e, float f)
{
if (f != cpu->fr[v].S[e])
TRACE_REGISTER (cpu,
" VR[%2d].<float>[%d] changes from %f to %f",
v, e, cpu->fr[v].S[e], f);
cpu->fr[v].S[e] = f;
}
void
aarch64_set_vec_double (sim_cpu *cpu, VReg v, unsigned e, double d)
{
if (d != cpu->fr[v].D[e])
TRACE_REGISTER (cpu,
" VR[%2d].<double>[%d] changes from %f to %f",
v, e, cpu->fr[v].D[e], d);
cpu->fr[v].D[e] = d;
}
int64_t
aarch64_get_vec_s64 (sim_cpu *cpu, VReg regno, unsigned element)
{
return cpu->fr[regno].V[element];
}
int32_t
aarch64_get_vec_s32 (sim_cpu *cpu, VReg regno, unsigned element)
{
return cpu->fr[regno].W[element];
}
int16_t
aarch64_get_vec_s16 (sim_cpu *cpu, VReg regno, unsigned element)
{
return cpu->fr[regno].H[element];
}
int8_t
aarch64_get_vec_s8 (sim_cpu *cpu, VReg regno, unsigned element)
{
return cpu->fr[regno].B[element];
}
void
aarch64_set_vec_s64 (sim_cpu *cpu, VReg regno, unsigned element, int64_t value)
{
if (value != cpu->fr[regno].V[element])
TRACE_REGISTER (cpu,
" VR[%2d].<long>[%d] changes from %16" PRIx64 " to %16" PRIx64,
regno, element, cpu->fr[regno].V[element], value);
cpu->fr[regno].V[element] = value;
}
void
aarch64_set_vec_s32 (sim_cpu *cpu, VReg regno, unsigned element, int32_t value)
{
if (value != cpu->fr[regno].W[element])
TRACE_REGISTER (cpu,
" VR[%2d].<word>[%d] changes from %8x to %8x",
regno, element, cpu->fr[regno].W[element], value);
cpu->fr[regno].W[element] = value;
}
void
aarch64_set_vec_s16 (sim_cpu *cpu, VReg regno, unsigned element, int16_t value)
{
if (value != cpu->fr[regno].H[element])
TRACE_REGISTER (cpu,
" VR[%2d].<half>[%d] changes from %4x to %4x",
regno, element, cpu->fr[regno].H[element], value);
cpu->fr[regno].H[element] = value;
}
void
aarch64_set_vec_s8 (sim_cpu *cpu, VReg regno, unsigned element, int8_t value)
{
if (value != cpu->fr[regno].B[element])
TRACE_REGISTER (cpu,
" VR[%2d].<byte>[%d] changes from %x to %x",
regno, element, cpu->fr[regno].B[element], value);
cpu->fr[regno].B[element] = value;
}

View File

@ -46,7 +46,12 @@ mem_error (sim_cpu *cpu, const char *message, uint64_t addr)
RETURN_TYPE \
aarch64_get_mem_##NAME (sim_cpu *cpu, uint64_t address) \
{ \
return (RETURN_TYPE) sim_core_read_##N (cpu, 0, read_map, address); \
RETURN_TYPE val = (RETURN_TYPE) sim_core_read_##N (cpu, 0, read_map, address); \
TRACE_MEMORY (cpu, \
"read of %" PRIx64 " (%d bytes) from %" PRIx64, \
(uint64_t) val, N, address); \
\
return val; \
}
/* A variant of the FETCH_FUNC macro that uses unaligned reads.
@ -56,7 +61,12 @@ mem_error (sim_cpu *cpu, const char *message, uint64_t addr)
RETURN_TYPE \
aarch64_get_mem_##NAME (sim_cpu *cpu, uint64_t address) \
{ \
return (RETURN_TYPE) sim_core_read_unaligned_8 (cpu, 0, read_map, address); \
RETURN_TYPE val = (RETURN_TYPE) sim_core_read_unaligned_8 (cpu, 0, read_map, address); \
TRACE_MEMORY (cpu, \
"read of %" PRIx64 " (%d bytes) from %" PRIx64 " (unaligned double)", \
(uint64_t) val, N, address); \
\
return val; \
}
FETCH_FUNC_U (uint64_t, uint64_t, u64)
@ -67,8 +77,6 @@ FETCH_FUNC (uint32_t, uint16_t, u16, 2)
FETCH_FUNC (int32_t, int16_t, s16, 2)
FETCH_FUNC (uint32_t, uint8_t, u8, 1)
FETCH_FUNC (int32_t, int8_t, s8, 1)
FETCH_FUNC (float, float, float, 4)
FETCH_FUNC_U (double, double, double)
void
aarch64_get_mem_long_double (sim_cpu *cpu, uint64_t address, FRegister *a)
@ -110,8 +118,6 @@ STORE_FUNC (uint16_t, u16, 2)
STORE_FUNC (int16_t, s16, 2)
STORE_FUNC (uint8_t, u8, 1)
STORE_FUNC (int8_t, s8, 1)
STORE_FUNC (float, float, 4)
STORE_FUNC_U (double, double)
void
aarch64_set_mem_long_double (sim_cpu *cpu, uint64_t address, FRegister a)

View File

@ -26,10 +26,7 @@
#include "bfd.h"
#include "simulator.h"
extern float aarch64_get_mem_float (sim_cpu *, uint64_t);
extern double aarch64_get_mem_double (sim_cpu *, uint64_t);
extern void aarch64_get_mem_long_double (sim_cpu *, uint64_t, FRegister *);
extern uint64_t aarch64_get_mem_u64 (sim_cpu *, uint64_t);
extern int64_t aarch64_get_mem_s64 (sim_cpu *, uint64_t);
extern uint32_t aarch64_get_mem_u32 (sim_cpu *, uint64_t);
@ -41,10 +38,7 @@ extern int32_t aarch64_get_mem_s8 (sim_cpu *, uint64_t);
extern void aarch64_get_mem_blk (sim_cpu *, uint64_t, char *, unsigned);
extern const char * aarch64_get_mem_ptr (sim_cpu *, uint64_t);
extern void aarch64_set_mem_float (sim_cpu *, uint64_t, float);
extern void aarch64_set_mem_double (sim_cpu *, uint64_t, double);
extern void aarch64_set_mem_long_double (sim_cpu *, uint64_t, FRegister);
extern void aarch64_set_mem_u64 (sim_cpu *, uint64_t, uint64_t);
extern void aarch64_set_mem_s64 (sim_cpu *, uint64_t, int64_t);
extern void aarch64_set_mem_u32 (sim_cpu *, uint64_t, uint32_t);

View File

@ -36,8 +36,8 @@
#define SP_OK 1
#define TST(_flag) (aarch64_test_CPSR_bit (cpu, _flag))
#define IS_SET(_X) ( TST (( _X )))
#define IS_CLEAR(_X) (!TST (( _X )))
#define IS_SET(_X) (TST (( _X )) ? 1 : 0)
#define IS_CLEAR(_X) (TST (( _X )) ? 0 : 1)
#define HALT_UNALLOC \
do \
@ -460,9 +460,9 @@ fldrs_pcrel (sim_cpu *cpu, int32_t offset)
{
unsigned int rd = uimm (aarch64_get_instr (cpu), 4, 0);
aarch64_set_FP_float (cpu, rd,
aarch64_get_mem_float
(cpu, aarch64_get_PC (cpu) + offset * 4));
aarch64_set_vec_u32 (cpu, rd, 0,
aarch64_get_mem_u32
(cpu, aarch64_get_PC (cpu) + offset * 4));
}
/* double pc-relative load */
@ -471,9 +471,9 @@ fldrd_pcrel (sim_cpu *cpu, int32_t offset)
{
unsigned int st = uimm (aarch64_get_instr (cpu), 4, 0);
aarch64_set_FP_double (cpu, st,
aarch64_get_mem_double
(cpu, aarch64_get_PC (cpu) + offset * 4));
aarch64_set_vec_u64 (cpu, st, 0,
aarch64_get_mem_u64
(cpu, aarch64_get_PC (cpu) + offset * 4));
}
/* long double pc-relative load. */
@ -545,7 +545,7 @@ fldrs_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
if (wb != Post)
address += offset;
aarch64_set_FP_float (cpu, st, aarch64_get_mem_float (cpu, address));
aarch64_set_vec_u32 (cpu, st, 0, aarch64_get_mem_u32 (cpu, address));
if (wb == Post)
address += offset;
@ -560,10 +560,9 @@ fldrs_abs (sim_cpu *cpu, uint32_t offset)
unsigned st = uimm (aarch64_get_instr (cpu), 4, 0);
unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
aarch64_set_FP_float (cpu, st,
aarch64_get_mem_float
(cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK)
+ SCALE (offset, 32)));
aarch64_set_vec_u32 (cpu, st, 0, aarch64_get_mem_u32
(cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK)
+ SCALE (offset, 32)));
}
/* Load 32 bit scaled or unscaled zero- or sign-extended
@ -578,9 +577,8 @@ fldrs_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP), extension);
uint64_t displacement = OPT_SCALE (extended, 32, scaling);
aarch64_set_FP_float (cpu, st,
aarch64_get_mem_float
(cpu, address + displacement));
aarch64_set_vec_u32 (cpu, st, 0, aarch64_get_mem_u32
(cpu, address + displacement));
}
/* Load 64 bit unscaled signed 9 bit with pre- or post-writeback. */
@ -594,7 +592,7 @@ fldrd_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
if (wb != Post)
address += offset;
aarch64_set_FP_double (cpu, st, aarch64_get_mem_double (cpu, address));
aarch64_set_vec_u64 (cpu, st, 0, aarch64_get_mem_u64 (cpu, address));
if (wb == Post)
address += offset;
@ -611,7 +609,7 @@ fldrd_abs (sim_cpu *cpu, uint32_t offset)
unsigned st = uimm (aarch64_get_instr (cpu), 4, 0);
uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK) + SCALE (offset, 64);
aarch64_set_FP_double (cpu, st, aarch64_get_mem_double (cpu, address));
aarch64_set_vec_u64 (cpu, st, 0, aarch64_get_mem_u64 (cpu, address));
}
/* Load 64 bit scaled or unscaled zero- or sign-extended 32-bit register offset. */
@ -2322,7 +2320,7 @@ static void
sbc32 (sim_cpu *cpu)
{
unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5); /* ngc iff rn == 31. */
unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
aarch64_set_reg_u64 (cpu, rd, NO_SP,
@ -5675,6 +5673,83 @@ do_vec_SSHR_USHR (sim_cpu *cpu)
}
}
static void
do_vec_MUL_by_element (sim_cpu *cpu)
{
/* instr[31] = 0
instr[30] = half/full
instr[29,24] = 00 1111
instr[23,22] = size
instr[21] = L
instr[20] = M
instr[19,16] = m
instr[15,12] = 1000
instr[11] = H
instr[10] = 0
instr[9,5] = Vn
instr[4,0] = Vd */
unsigned full = uimm (aarch64_get_instr (cpu), 30, 30);
unsigned L = uimm (aarch64_get_instr (cpu), 21, 21);
unsigned H = uimm (aarch64_get_instr (cpu), 11, 11);
unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
unsigned size = uimm (aarch64_get_instr (cpu), 23, 22);
unsigned index;
unsigned vm;
unsigned e;
NYI_assert (29, 24, 0x0F);
NYI_assert (15, 12, 0x8);
NYI_assert (10, 10, 0);
switch (size)
{
case 1:
{
/* 16 bit products. */
uint16_t product;
uint16_t element1;
uint16_t element2;
index = (H << 2) | (L << 1) | uimm (aarch64_get_instr (cpu), 20, 20);
vm = uimm (aarch64_get_instr (cpu), 19, 16);
element2 = aarch64_get_vec_u16 (cpu, vm, index);
for (e = 0; e < (full ? 8 : 4); e ++)
{
element1 = aarch64_get_vec_u16 (cpu, vn, e);
product = element1 * element2;
aarch64_set_vec_u16 (cpu, vd, e, product);
}
}
break;
case 2:
{
/* 32 bit products. */
uint32_t product;
uint32_t element1;
uint32_t element2;
index = (H << 1) | L;
vm = uimm (aarch64_get_instr (cpu), 20, 16);
element2 = aarch64_get_vec_u32 (cpu, vm, index);
for (e = 0; e < (full ? 4 : 2); e ++)
{
element1 = aarch64_get_vec_u32 (cpu, vn, e);
product = element1 * element2;
aarch64_set_vec_u32 (cpu, vd, e, product);
}
}
break;
default:
HALT_UNALLOC;
}
}
static void
do_vec_op2 (sim_cpu *cpu)
{
@ -5685,19 +5760,30 @@ do_vec_op2 (sim_cpu *cpu)
instr[22,16] = element size & index
instr[15,10] = sub-opcode
instr[9,5] = Vm
instr[4.0] = Vd */
instr[4,0] = Vd */
NYI_assert (29, 24, 0x0F);
if (uimm (aarch64_get_instr (cpu), 23, 23) != 0)
HALT_NYI;
switch (uimm (aarch64_get_instr (cpu), 15, 10))
{
case 0x01: do_vec_SSHR_USHR (cpu); return;
case 0x15: do_vec_SHL (cpu); return;
case 0x29: do_vec_xtl (cpu); return;
default: HALT_NYI;
switch (uimm (aarch64_get_instr (cpu), 15, 10))
{
case 0x20:
case 0x22: do_vec_MUL_by_element (cpu); return;
default: HALT_NYI;
}
}
else
{
switch (uimm (aarch64_get_instr (cpu), 15, 10))
{
case 0x01: do_vec_SSHR_USHR (cpu); return;
case 0x15: do_vec_SHL (cpu); return;
case 0x20:
case 0x22: do_vec_MUL_by_element (cpu); return;
case 0x29: do_vec_xtl (cpu); return;
default: HALT_NYI;
}
}
}
@ -6831,8 +6917,8 @@ fsturs (sim_cpu *cpu, int32_t offset)
unsigned int rn = uimm (aarch64_get_instr (cpu), 9, 5);
unsigned int st = uimm (aarch64_get_instr (cpu), 4, 0);
aarch64_set_mem_float (cpu, aarch64_get_reg_u64 (cpu, st, 1) + offset,
aarch64_get_FP_float (cpu, rn));
aarch64_set_mem_u32 (cpu, aarch64_get_reg_u64 (cpu, st, 1) + offset,
aarch64_get_vec_u32 (cpu, rn, 0));
}
/* Store 64 bit unscaled signed 9 bit. */
@ -6842,8 +6928,8 @@ fsturd (sim_cpu *cpu, int32_t offset)
unsigned int rn = uimm (aarch64_get_instr (cpu), 9, 5);
unsigned int st = uimm (aarch64_get_instr (cpu), 4, 0);
aarch64_set_mem_double (cpu, aarch64_get_reg_u64 (cpu, st, 1) + offset,
aarch64_get_FP_double (cpu, rn));
aarch64_set_mem_u64 (cpu, aarch64_get_reg_u64 (cpu, st, 1) + offset,
aarch64_get_vec_u64 (cpu, rn, 0));
}
/* Store 128 bit unscaled signed 9 bit. */
@ -6985,8 +7071,8 @@ fldurs (sim_cpu *cpu, int32_t offset)
unsigned int rn = uimm (aarch64_get_instr (cpu), 9, 5);
unsigned int st = uimm (aarch64_get_instr (cpu), 4, 0);
aarch64_set_FP_float (cpu, st, aarch64_get_mem_float
(cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK) + offset));
aarch64_set_vec_u32 (cpu, st, 0, aarch64_get_mem_u32
(cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK) + offset));
}
/* Load 64 bit unscaled signed 9 bit. */
@ -6996,8 +7082,8 @@ fldurd (sim_cpu *cpu, int32_t offset)
unsigned int rn = uimm (aarch64_get_instr (cpu), 9, 5);
unsigned int st = uimm (aarch64_get_instr (cpu), 4, 0);
aarch64_set_FP_double (cpu, st, aarch64_get_mem_double
(cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK) + offset));
aarch64_set_vec_u64 (cpu, st, 0, aarch64_get_mem_u64
(cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK) + offset));
}
/* Load 128 bit unscaled signed 9 bit. */
@ -8189,6 +8275,25 @@ do_scalar_MOV (sim_cpu *cpu)
HALT_UNALLOC;
}
static void
do_scalar_NEG (sim_cpu *cpu)
{
/* instr [31,24] = 0111 1110
instr [23,22] = 11
instr [21,10] = 1000 0010 1110
instr [9, 5] = Rn
instr [4, 0] = Rd. */
unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
NYI_assert (31, 24, 0x7E);
NYI_assert (21, 10, 0x82E);
NYI_assert (23, 22, 3);
aarch64_set_vec_u64 (cpu, rd, 0, - aarch64_get_vec_u64 (cpu, rn, 0));
}
static void
do_double_add (sim_cpu *cpu)
{
@ -8228,6 +8333,7 @@ do_double_add (sim_cpu *cpu)
case 0x35: do_scalar_FABD (cpu); return;
case 0x39: do_scalar_FCM (cpu); return;
case 0x3B: do_scalar_FCM (cpu); return;
case 0x2E: do_scalar_NEG (cpu); return;
default:
HALT_NYI;
}
@ -9464,10 +9570,10 @@ fstrs_abs (sim_cpu *cpu, uint32_t offset)
unsigned st = uimm (aarch64_get_instr (cpu), 4, 0);
unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
aarch64_set_mem_float
aarch64_set_mem_u32
(cpu,
aarch64_get_reg_u64 (cpu, rn, SP_OK) + SCALE (offset, 32),
aarch64_get_FP_float (cpu, st));
aarch64_get_vec_u32 (cpu, st, 0));
}
/* 32 bit store unscaled signed 9 bit with pre- or post-writeback. */
@ -9482,7 +9588,7 @@ fstrs_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
if (wb != Post)
address += offset;
aarch64_set_mem_float (cpu, address, aarch64_get_FP_float (cpu, st));
aarch64_set_mem_u32 (cpu, address, aarch64_get_vec_u32 (cpu, st, 0));
if (wb == Post)
address += offset;
@ -9505,8 +9611,8 @@ fstrs_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
extension);
uint64_t displacement = OPT_SCALE (extended, 32, scaling);
aarch64_set_mem_float
(cpu, address + displacement, aarch64_get_FP_float (cpu, st));
aarch64_set_mem_u32
(cpu, address + displacement, aarch64_get_vec_u32 (cpu, st, 0));
}
/* 64 bit store scaled unsigned 12 bit. */
@ -9516,10 +9622,10 @@ fstrd_abs (sim_cpu *cpu, uint32_t offset)
unsigned st = uimm (aarch64_get_instr (cpu), 4, 0);
unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
aarch64_set_mem_double
aarch64_set_mem_u64
(cpu,
aarch64_get_reg_u64 (cpu, rn, SP_OK) + SCALE (offset, 64),
aarch64_get_FP_double (cpu, st));
aarch64_get_vec_u64 (cpu, st, 0));
}
/* 64 bit store unscaled signed 9 bit with pre- or post-writeback. */
@ -9534,7 +9640,7 @@ fstrd_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
if (wb != Post)
address += offset;
aarch64_set_mem_double (cpu, address, aarch64_get_FP_double (cpu, st));
aarch64_set_mem_u64 (cpu, address, aarch64_get_vec_u64 (cpu, st, 0));
if (wb == Post)
address += offset;
@ -9557,8 +9663,8 @@ fstrd_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
extension);
uint64_t displacement = OPT_SCALE (extended, 64, scaling);
aarch64_set_mem_double
(cpu, address + displacement, aarch64_get_FP_double (cpu, st));
aarch64_set_mem_u64
(cpu, address + displacement, aarch64_get_vec_u64 (cpu, st, 0));
}
/* 128 bit store scaled unsigned 12 bit. */
@ -10093,8 +10199,8 @@ store_pair_float (sim_cpu *cpu, int32_t offset, WriteBack wb)
if (wb != Post)
address += offset;
aarch64_set_mem_float (cpu, address, aarch64_get_FP_float (cpu, rm));
aarch64_set_mem_float (cpu, address + 4, aarch64_get_FP_float (cpu, rn));
aarch64_set_mem_u32 (cpu, address, aarch64_get_vec_u32 (cpu, rm, 0));
aarch64_set_mem_u32 (cpu, address + 4, aarch64_get_vec_u32 (cpu, rn, 0));
if (wb == Post)
address += offset;
@ -10116,8 +10222,8 @@ store_pair_double (sim_cpu *cpu, int32_t offset, WriteBack wb)
if (wb != Post)
address += offset;
aarch64_set_mem_double (cpu, address, aarch64_get_FP_double (cpu, rm));
aarch64_set_mem_double (cpu, address + 8, aarch64_get_FP_double (cpu, rn));
aarch64_set_mem_u64 (cpu, address, aarch64_get_vec_u64 (cpu, rm, 0));
aarch64_set_mem_u64 (cpu, address + 8, aarch64_get_vec_u64 (cpu, rn, 0));
if (wb == Post)
address += offset;
@ -10168,8 +10274,8 @@ load_pair_float (sim_cpu *cpu, int32_t offset, WriteBack wb)
if (wb != Post)
address += offset;
aarch64_set_FP_float (cpu, rm, aarch64_get_mem_float (cpu, address));
aarch64_set_FP_float (cpu, rn, aarch64_get_mem_float (cpu, address + 4));
aarch64_set_vec_u32 (cpu, rm, 0, aarch64_get_mem_u32 (cpu, address));
aarch64_set_vec_u32 (cpu, rn, 0, aarch64_get_mem_u32 (cpu, address + 4));
if (wb == Post)
address += offset;
@ -10194,8 +10300,8 @@ load_pair_double (sim_cpu *cpu, int32_t offset, WriteBack wb)
if (wb != Post)
address += offset;
aarch64_set_FP_double (cpu, rm, aarch64_get_mem_double (cpu, address));
aarch64_set_FP_double (cpu, rn, aarch64_get_mem_double (cpu, address + 8));
aarch64_set_vec_u64 (cpu, rm, 0, aarch64_get_mem_u64 (cpu, address));
aarch64_set_vec_u64 (cpu, rn, 0, aarch64_get_mem_u64 (cpu, address + 8));
if (wb == Post)
address += offset;