mirror of https://gitee.com/openkylin/qemu.git
Hexagon (target/hexagon) circular addressing
The following instructions are added L2_loadrub_pci Rd32 = memub(Rx32++#s4:0:circ(Mu2)) L2_loadrb_pci Rd32 = memb(Rx32++#s4:0:circ(Mu2)) L2_loadruh_pci Rd32 = memuh(Rx32++#s4:1:circ(Mu2)) L2_loadrh_pci Rd32 = memh(Rx32++#s4:1:circ(Mu2)) L2_loadri_pci Rd32 = memw(Rx32++#s4:2:circ(Mu2)) L2_loadrd_pci Rdd32 = memd(Rx32++#s4:3:circ(Mu2)) S2_storerb_pci memb(Rx32++#s4:0:circ(Mu2)) = Rt32 S2_storerh_pci memh(Rx32++#s4:1:circ(Mu2)) = Rt32 S2_storerf_pci memh(Rx32++#s4:1:circ(Mu2)) = Rt.H32 S2_storeri_pci memw(Rx32++#s4:2:circ(Mu2)) = Rt32 S2_storerd_pci memd(Rx32++#s4:3:circ(Mu2)) = Rtt32 S2_storerbnew_pci memb(Rx32++#s4:0:circ(Mu2)) = Nt8.new S2_storerhnew_pci memw(Rx32++#s4:1:circ(Mu2)) = Nt8.new S2_storerinew_pci memw(Rx32++#s4:2:circ(Mu2)) = Nt8.new L2_loadrub_pcr Rd32 = memub(Rx32++I:circ(Mu2)) L2_loadrb_pcr Rd32 = memb(Rx32++I:circ(Mu2)) L2_loadruh_pcr Rd32 = memuh(Rx32++I:circ(Mu2)) L2_loadrh_pcr Rd32 = memh(Rx32++I:circ(Mu2)) L2_loadri_pcr Rd32 = memw(Rx32++I:circ(Mu2)) L2_loadrd_pcr Rdd32 = memd(Rx32++I:circ(Mu2)) S2_storerb_pcr memb(Rx32++I:circ(Mu2)) = Rt32 S2_storerh_pcr memh(Rx32++I:circ(Mu2)) = Rt32 S2_storerf_pcr memh(Rx32++I:circ(Mu2)) = Rt32.H32 S2_storeri_pcr memw(Rx32++I:circ(Mu2)) = Rt32 S2_storerd_pcr memd(Rx32++I:circ(Mu2)) = Rtt32 S2_storerbnew_pcr memb(Rx32++I:circ(Mu2)) = Nt8.new S2_storerhnew_pcr memh(Rx32++I:circ(Mu2)) = Nt8.new S2_storerinew_pcr memw(Rx32++I:circ(Mu2)) = Nt8.new Test cases in tests/tcg/hexagon/circ.c Signed-off-by: Taylor Simpson <tsimpson@quicinc.com> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Message-Id: <1617930474-31979-23-git-send-email-tsimpson@quicinc.com> [rth: Squash <1619667142-29636-1-git-send-email-tsimpson@quicinc.com> removing gen_read_reg and gen_set_byte to avoid clang Werror.] Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
This commit is contained in:
parent
57d352ac29
commit
46ef47e2a7
|
@ -38,6 +38,8 @@
|
|||
* _ap absolute set r0 = memw(r1=##variable)
|
||||
* _pr post increment register r0 = memw(r1++m1)
|
||||
* _pi post increment immediate r0 = memb(r1++#1)
|
||||
* _pci post increment circular immediate r0 = memw(r1++#4:circ(m0))
|
||||
* _pcr post increment circular register r0 = memw(r1++I:circ(m0))
|
||||
*/
|
||||
|
||||
/* Macros for complex addressing modes */
|
||||
|
@ -56,7 +58,22 @@
|
|||
fEA_REG(RxV); \
|
||||
fPM_I(RxV, siV); \
|
||||
} while (0)
|
||||
|
||||
#define GET_EA_pci \
|
||||
do { \
|
||||
TCGv tcgv_siV = tcg_const_tl(siV); \
|
||||
tcg_gen_mov_tl(EA, RxV); \
|
||||
gen_helper_fcircadd(RxV, RxV, tcgv_siV, MuV, \
|
||||
hex_gpr[HEX_REG_CS0 + MuN]); \
|
||||
tcg_temp_free(tcgv_siV); \
|
||||
} while (0)
|
||||
#define GET_EA_pcr(SHIFT) \
|
||||
do { \
|
||||
TCGv ireg = tcg_temp_new(); \
|
||||
tcg_gen_mov_tl(EA, RxV); \
|
||||
gen_read_ireg(ireg, MuV, (SHIFT)); \
|
||||
gen_helper_fcircadd(RxV, RxV, ireg, MuV, hex_gpr[HEX_REG_CS0 + MuN]); \
|
||||
tcg_temp_free(ireg); \
|
||||
} while (0)
|
||||
|
||||
/* Instructions with multiple definitions */
|
||||
#define fGEN_TCG_LOAD_AP(RES, SIZE, SIGN) \
|
||||
|
@ -80,6 +97,36 @@
|
|||
#define fGEN_TCG_L4_loadrd_ap(SHORTCODE) \
|
||||
fGEN_TCG_LOAD_AP(RddV, 8, u)
|
||||
|
||||
#define fGEN_TCG_L2_loadrub_pci(SHORTCODE) SHORTCODE
|
||||
#define fGEN_TCG_L2_loadrb_pci(SHORTCODE) SHORTCODE
|
||||
#define fGEN_TCG_L2_loadruh_pci(SHORTCODE) SHORTCODE
|
||||
#define fGEN_TCG_L2_loadrh_pci(SHORTCODE) SHORTCODE
|
||||
#define fGEN_TCG_L2_loadri_pci(SHORTCODE) SHORTCODE
|
||||
#define fGEN_TCG_L2_loadrd_pci(SHORTCODE) SHORTCODE
|
||||
|
||||
#define fGEN_TCG_LOAD_pcr(SHIFT, LOAD) \
|
||||
do { \
|
||||
TCGv ireg = tcg_temp_new(); \
|
||||
tcg_gen_mov_tl(EA, RxV); \
|
||||
gen_read_ireg(ireg, MuV, SHIFT); \
|
||||
gen_helper_fcircadd(RxV, RxV, ireg, MuV, hex_gpr[HEX_REG_CS0 + MuN]); \
|
||||
LOAD; \
|
||||
tcg_temp_free(ireg); \
|
||||
} while (0)
|
||||
|
||||
#define fGEN_TCG_L2_loadrub_pcr(SHORTCODE) \
|
||||
fGEN_TCG_LOAD_pcr(0, fLOAD(1, 1, u, EA, RdV))
|
||||
#define fGEN_TCG_L2_loadrb_pcr(SHORTCODE) \
|
||||
fGEN_TCG_LOAD_pcr(0, fLOAD(1, 1, s, EA, RdV))
|
||||
#define fGEN_TCG_L2_loadruh_pcr(SHORTCODE) \
|
||||
fGEN_TCG_LOAD_pcr(1, fLOAD(1, 2, u, EA, RdV))
|
||||
#define fGEN_TCG_L2_loadrh_pcr(SHORTCODE) \
|
||||
fGEN_TCG_LOAD_pcr(1, fLOAD(1, 2, s, EA, RdV))
|
||||
#define fGEN_TCG_L2_loadri_pcr(SHORTCODE) \
|
||||
fGEN_TCG_LOAD_pcr(2, fLOAD(1, 4, u, EA, RdV))
|
||||
#define fGEN_TCG_L2_loadrd_pcr(SHORTCODE) \
|
||||
fGEN_TCG_LOAD_pcr(3, fLOAD(1, 8, u, EA, RddV))
|
||||
|
||||
#define fGEN_TCG_L2_loadrub_pr(SHORTCODE) SHORTCODE
|
||||
#define fGEN_TCG_L2_loadrub_pi(SHORTCODE) SHORTCODE
|
||||
#define fGEN_TCG_L2_loadrb_pr(SHORTCODE) SHORTCODE
|
||||
|
@ -195,6 +242,69 @@
|
|||
#define fGEN_TCG_S4_stored_locked(SHORTCODE) \
|
||||
do { SHORTCODE; READ_PREG(PdV, PdN); } while (0)
|
||||
|
||||
#define fGEN_TCG_STORE(SHORTCODE) \
|
||||
do { \
|
||||
TCGv HALF = tcg_temp_new(); \
|
||||
TCGv BYTE = tcg_temp_new(); \
|
||||
SHORTCODE; \
|
||||
tcg_temp_free(HALF); \
|
||||
tcg_temp_free(BYTE); \
|
||||
} while (0)
|
||||
|
||||
#define fGEN_TCG_STORE_pcr(SHIFT, STORE) \
|
||||
do { \
|
||||
TCGv ireg = tcg_temp_new(); \
|
||||
TCGv HALF = tcg_temp_new(); \
|
||||
TCGv BYTE = tcg_temp_new(); \
|
||||
tcg_gen_mov_tl(EA, RxV); \
|
||||
gen_read_ireg(ireg, MuV, SHIFT); \
|
||||
gen_helper_fcircadd(RxV, RxV, ireg, MuV, hex_gpr[HEX_REG_CS0 + MuN]); \
|
||||
STORE; \
|
||||
tcg_temp_free(ireg); \
|
||||
tcg_temp_free(HALF); \
|
||||
tcg_temp_free(BYTE); \
|
||||
} while (0)
|
||||
|
||||
#define fGEN_TCG_S2_storerb_pci(SHORTCODE) \
|
||||
fGEN_TCG_STORE(SHORTCODE)
|
||||
#define fGEN_TCG_S2_storerb_pcr(SHORTCODE) \
|
||||
fGEN_TCG_STORE_pcr(0, fSTORE(1, 1, EA, fGETBYTE(0, RtV)))
|
||||
|
||||
#define fGEN_TCG_S2_storerh_pci(SHORTCODE) \
|
||||
fGEN_TCG_STORE(SHORTCODE)
|
||||
#define fGEN_TCG_S2_storerh_pcr(SHORTCODE) \
|
||||
fGEN_TCG_STORE_pcr(1, fSTORE(1, 2, EA, fGETHALF(0, RtV)))
|
||||
|
||||
#define fGEN_TCG_S2_storerf_pci(SHORTCODE) \
|
||||
fGEN_TCG_STORE(SHORTCODE)
|
||||
#define fGEN_TCG_S2_storerf_pcr(SHORTCODE) \
|
||||
fGEN_TCG_STORE_pcr(1, fSTORE(1, 2, EA, fGETHALF(1, RtV)))
|
||||
|
||||
#define fGEN_TCG_S2_storeri_pci(SHORTCODE) \
|
||||
fGEN_TCG_STORE(SHORTCODE)
|
||||
#define fGEN_TCG_S2_storeri_pcr(SHORTCODE) \
|
||||
fGEN_TCG_STORE_pcr(2, fSTORE(1, 4, EA, RtV))
|
||||
|
||||
#define fGEN_TCG_S2_storerd_pci(SHORTCODE) \
|
||||
fGEN_TCG_STORE(SHORTCODE)
|
||||
#define fGEN_TCG_S2_storerd_pcr(SHORTCODE) \
|
||||
fGEN_TCG_STORE_pcr(3, fSTORE(1, 8, EA, RttV))
|
||||
|
||||
#define fGEN_TCG_S2_storerbnew_pci(SHORTCODE) \
|
||||
fGEN_TCG_STORE(SHORTCODE)
|
||||
#define fGEN_TCG_S2_storerbnew_pcr(SHORTCODE) \
|
||||
fGEN_TCG_STORE_pcr(0, fSTORE(1, 1, EA, fGETBYTE(0, NtN)))
|
||||
|
||||
#define fGEN_TCG_S2_storerhnew_pci(SHORTCODE) \
|
||||
fGEN_TCG_STORE(SHORTCODE)
|
||||
#define fGEN_TCG_S2_storerhnew_pcr(SHORTCODE) \
|
||||
fGEN_TCG_STORE_pcr(1, fSTORE(1, 2, EA, fGETHALF(0, NtN)))
|
||||
|
||||
#define fGEN_TCG_S2_storerinew_pci(SHORTCODE) \
|
||||
fGEN_TCG_STORE(SHORTCODE)
|
||||
#define fGEN_TCG_S2_storerinew_pcr(SHORTCODE) \
|
||||
fGEN_TCG_STORE_pcr(2, fSTORE(1, 4, EA, NtN))
|
||||
|
||||
/*
|
||||
* Mathematical operations with more than one definition require
|
||||
* special handling
|
||||
|
|
|
@ -266,6 +266,16 @@ static inline void gen_write_ctrl_reg_pair(DisasContext *ctx, int reg_num,
|
|||
}
|
||||
}
|
||||
|
||||
static TCGv gen_get_byte(TCGv result, int N, TCGv src, bool sign)
|
||||
{
|
||||
if (sign) {
|
||||
tcg_gen_sextract_tl(result, src, N * 8, 8);
|
||||
} else {
|
||||
tcg_gen_extract_tl(result, src, N * 8, 8);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static TCGv gen_get_byte_i64(TCGv result, int N, TCGv_i64 src, bool sign)
|
||||
{
|
||||
TCGv_i64 res64 = tcg_temp_new_i64();
|
||||
|
@ -280,6 +290,16 @@ static TCGv gen_get_byte_i64(TCGv result, int N, TCGv_i64 src, bool sign)
|
|||
return result;
|
||||
}
|
||||
|
||||
static inline TCGv gen_get_half(TCGv result, int N, TCGv src, bool sign)
|
||||
{
|
||||
if (sign) {
|
||||
tcg_gen_sextract_tl(result, src, N * 16, 16);
|
||||
} else {
|
||||
tcg_gen_extract_tl(result, src, N * 16, 16);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static void gen_set_byte_i64(int N, TCGv_i64 result, TCGv src)
|
||||
{
|
||||
TCGv_i64 src64 = tcg_temp_new_i64();
|
||||
|
@ -361,6 +381,75 @@ static inline void gen_store_conditional8(CPUHexagonState *env,
|
|||
tcg_gen_movi_tl(hex_llsc_addr, ~0);
|
||||
}
|
||||
|
||||
static inline void gen_store32(TCGv vaddr, TCGv src, int width, int slot)
|
||||
{
|
||||
tcg_gen_mov_tl(hex_store_addr[slot], vaddr);
|
||||
tcg_gen_movi_tl(hex_store_width[slot], width);
|
||||
tcg_gen_mov_tl(hex_store_val32[slot], src);
|
||||
}
|
||||
|
||||
static inline void gen_store1(TCGv_env cpu_env, TCGv vaddr, TCGv src,
|
||||
DisasContext *ctx, int slot)
|
||||
{
|
||||
gen_store32(vaddr, src, 1, slot);
|
||||
ctx->store_width[slot] = 1;
|
||||
}
|
||||
|
||||
static inline void gen_store1i(TCGv_env cpu_env, TCGv vaddr, int32_t src,
|
||||
DisasContext *ctx, int slot)
|
||||
{
|
||||
TCGv tmp = tcg_const_tl(src);
|
||||
gen_store1(cpu_env, vaddr, tmp, ctx, slot);
|
||||
tcg_temp_free(tmp);
|
||||
}
|
||||
|
||||
static inline void gen_store2(TCGv_env cpu_env, TCGv vaddr, TCGv src,
|
||||
DisasContext *ctx, int slot)
|
||||
{
|
||||
gen_store32(vaddr, src, 2, slot);
|
||||
ctx->store_width[slot] = 2;
|
||||
}
|
||||
|
||||
static inline void gen_store2i(TCGv_env cpu_env, TCGv vaddr, int32_t src,
|
||||
DisasContext *ctx, int slot)
|
||||
{
|
||||
TCGv tmp = tcg_const_tl(src);
|
||||
gen_store2(cpu_env, vaddr, tmp, ctx, slot);
|
||||
tcg_temp_free(tmp);
|
||||
}
|
||||
|
||||
static inline void gen_store4(TCGv_env cpu_env, TCGv vaddr, TCGv src,
|
||||
DisasContext *ctx, int slot)
|
||||
{
|
||||
gen_store32(vaddr, src, 4, slot);
|
||||
ctx->store_width[slot] = 4;
|
||||
}
|
||||
|
||||
static inline void gen_store4i(TCGv_env cpu_env, TCGv vaddr, int32_t src,
|
||||
DisasContext *ctx, int slot)
|
||||
{
|
||||
TCGv tmp = tcg_const_tl(src);
|
||||
gen_store4(cpu_env, vaddr, tmp, ctx, slot);
|
||||
tcg_temp_free(tmp);
|
||||
}
|
||||
|
||||
static inline void gen_store8(TCGv_env cpu_env, TCGv vaddr, TCGv_i64 src,
|
||||
DisasContext *ctx, int slot)
|
||||
{
|
||||
tcg_gen_mov_tl(hex_store_addr[slot], vaddr);
|
||||
tcg_gen_movi_tl(hex_store_width[slot], 8);
|
||||
tcg_gen_mov_i64(hex_store_val64[slot], src);
|
||||
ctx->store_width[slot] = 8;
|
||||
}
|
||||
|
||||
static inline void gen_store8i(TCGv_env cpu_env, TCGv vaddr, int64_t src,
|
||||
DisasContext *ctx, int slot)
|
||||
{
|
||||
TCGv_i64 tmp = tcg_const_i64(src);
|
||||
gen_store8(cpu_env, vaddr, tmp, ctx, slot);
|
||||
tcg_temp_free_i64(tmp);
|
||||
}
|
||||
|
||||
static TCGv gen_8bitsof(TCGv result, TCGv value)
|
||||
{
|
||||
TCGv zero = tcg_const_tl(0);
|
||||
|
|
|
@ -294,6 +294,7 @@ DEF_CLASS32(ICLASS_LD" ---- -------- PP------ --------",LD)
|
|||
|
||||
|
||||
DEF_CLASS32(ICLASS_LD" 0--- -------- PP------ --------",LD_ADDR_ROFFSET)
|
||||
DEF_CLASS32(ICLASS_LD" 100- -------- PP----0- --------",LD_ADDR_POST_CIRC_IMMED)
|
||||
DEF_CLASS32(ICLASS_LD" 101- -------- PP00---- --------",LD_ADDR_POST_IMMED)
|
||||
DEF_CLASS32(ICLASS_LD" 101- -------- PP01---- --------",LD_ADDR_ABS_UPDATE_V4)
|
||||
DEF_CLASS32(ICLASS_LD" 101- -------- PP1----- --------",LD_ADDR_POST_IMMED_PRED_V2)
|
||||
|
@ -308,18 +309,23 @@ DEF_FIELD32(ICLASS_LD" ---- --!----- PP------ --------",LD_UN,"Unsigned")
|
|||
|
||||
#define STD_LD_ENC(TAG,OPC) \
|
||||
DEF_ENC32(L2_load##TAG##_io, ICLASS_LD" 0 ii "OPC" sssss PPiiiiii iiiddddd")\
|
||||
DEF_ENC32(L2_load##TAG##_pci, ICLASS_LD" 1 00 "OPC" xxxxx PPu0--0i iiiddddd")\
|
||||
DEF_ENC32(L2_load##TAG##_pi, ICLASS_LD" 1 01 "OPC" xxxxx PP00---i iiiddddd")\
|
||||
DEF_ENC32(L4_load##TAG##_ap, ICLASS_LD" 1 01 "OPC" eeeee PP01IIII -IIddddd")\
|
||||
DEF_ENC32(L2_load##TAG##_pr, ICLASS_LD" 1 10 "OPC" xxxxx PPu0---- 0--ddddd")\
|
||||
DEF_ENC32(L4_load##TAG##_ur, ICLASS_LD" 1 10 "OPC" ttttt PPi1IIII iIIddddd")\
|
||||
DEF_ENC32(L2_load##TAG##_pcr, ICLASS_LD" 1 00 "OPC" xxxxx PPu0--1- 0--ddddd")\
|
||||
|
||||
|
||||
#define STD_LDX_ENC(TAG,OPC) \
|
||||
DEF_ENC32(L2_load##TAG##_io, ICLASS_LD" 0 ii "OPC" sssss PPiiiiii iiiyyyyy")\
|
||||
DEF_ENC32(L2_load##TAG##_pci, ICLASS_LD" 1 00 "OPC" xxxxx PPu0--0i iiiyyyyy")\
|
||||
DEF_ENC32(L2_load##TAG##_pi, ICLASS_LD" 1 01 "OPC" xxxxx PP00---i iiiyyyyy")\
|
||||
DEF_ENC32(L4_load##TAG##_ap, ICLASS_LD" 1 01 "OPC" eeeee PP01IIII -IIyyyyy")\
|
||||
DEF_ENC32(L2_load##TAG##_pr, ICLASS_LD" 1 10 "OPC" xxxxx PPu0---- 0--yyyyy")\
|
||||
DEF_ENC32(L4_load##TAG##_ur, ICLASS_LD" 1 10 "OPC" ttttt PPi1IIII iIIyyyyy")\
|
||||
DEF_ENC32(L2_load##TAG##_pcr, ICLASS_LD" 1 00 "OPC" xxxxx PPu0--1- 0--yyyyy")\
|
||||
DEF_ENC32(L2_load##TAG##_pbr, ICLASS_LD" 1 11 "OPC" xxxxx PPu0---- 0--yyyyy")
|
||||
|
||||
|
||||
#define STD_PLD_ENC(TAG,OPC) \
|
||||
|
@ -351,6 +357,7 @@ STD_PLD_ENC(rd, "1 110") /* note dest reg field LSB=0, 1 is reserved */
|
|||
|
||||
DEF_CLASS32( ICLASS_LD" 0--0 000----- PP------ --------",LD_MISC)
|
||||
DEF_ANTICLASS32(ICLASS_LD" 0--0 000----- PP------ --------",LD_ADDR_ROFFSET)
|
||||
DEF_ANTICLASS32(ICLASS_LD" 1000 000----- PP------ --------",LD_ADDR_POST_CIRC_IMMED)
|
||||
DEF_ANTICLASS32(ICLASS_LD" 1010 000----- PP------ --------",LD_ADDR_POST_IMMED)
|
||||
DEF_ANTICLASS32(ICLASS_LD" 1100 000----- PP------ --------",LD_ADDR_POST_REG)
|
||||
DEF_ANTICLASS32(ICLASS_LD" 1110 000----- PP------ --------",LD_ADDR_POST_REG)
|
||||
|
@ -397,6 +404,7 @@ DEF_FIELD32(ICLASS_ST" ---! !!------ PP------ --------",ST_Type,"Type")
|
|||
DEF_FIELD32(ICLASS_ST" ---- --!----- PP------ --------",ST_UN,"Unsigned")
|
||||
|
||||
DEF_CLASS32(ICLASS_ST" 0--1 -------- PP------ --------",ST_ADDR_ROFFSET)
|
||||
DEF_CLASS32(ICLASS_ST" 1001 -------- PP------ ------0-",ST_ADDR_POST_CIRC_IMMED)
|
||||
DEF_CLASS32(ICLASS_ST" 1011 -------- PP0----- 0-----0-",ST_ADDR_POST_IMMED)
|
||||
DEF_CLASS32(ICLASS_ST" 1011 -------- PP0----- 1-------",ST_ADDR_ABS_UPDATE_V4)
|
||||
DEF_CLASS32(ICLASS_ST" 1011 -------- PP1----- --------",ST_ADDR_POST_IMMED_PRED_V2)
|
||||
|
@ -411,10 +419,12 @@ DEF_CLASS32(ICLASS_ST" 0--0 0------- PP------ --------",ST_MISC_CACHEOP)
|
|||
|
||||
#define STD_ST_ENC(TAG,OPC,SRC) \
|
||||
DEF_ENC32(S2_store##TAG##_io, ICLASS_ST" 0 ii "OPC" sssss PPi"SRC" iiiiiiii")\
|
||||
DEF_ENC32(S2_store##TAG##_pci, ICLASS_ST" 1 00 "OPC" xxxxx PPu"SRC" 0iiii-0-")\
|
||||
DEF_ENC32(S2_store##TAG##_pi, ICLASS_ST" 1 01 "OPC" xxxxx PP0"SRC" 0iiii-0-")\
|
||||
DEF_ENC32(S4_store##TAG##_ap, ICLASS_ST" 1 01 "OPC" eeeee PP0"SRC" 1-IIIIII")\
|
||||
DEF_ENC32(S2_store##TAG##_pr, ICLASS_ST" 1 10 "OPC" xxxxx PPu"SRC" 0-------")\
|
||||
DEF_ENC32(S4_store##TAG##_ur, ICLASS_ST" 1 10 "OPC" uuuuu PPi"SRC" 1iIIIIII")\
|
||||
DEF_ENC32(S2_store##TAG##_pcr, ICLASS_ST" 1 00 "OPC" xxxxx PPu"SRC" 0-----1-")\
|
||||
|
||||
|
||||
#define STD_PST_ENC(TAG,OPC,SRC) \
|
||||
|
|
|
@ -26,6 +26,8 @@ Q6INSN(L4_##TAG##_ur, OPER"(Rt32<<#u2+#U6)", ATTRIB,DESCR,{fMUST_IM
|
|||
Q6INSN(L4_##TAG##_ap, OPER"(Re32=#U6)", ATTRIB,DESCR,{fMUST_IMMEXT(UiV); fEA_IMM(UiV); SEMANTICS; ReV=UiV; })\
|
||||
Q6INSN(L2_##TAG##_pr, OPER"(Rx32++Mu2)", ATTRIB,DESCR,{fEA_REG(RxV); fPM_M(RxV,MuV); SEMANTICS;})\
|
||||
Q6INSN(L2_##TAG##_pi, OPER"(Rx32++#s4:"SHFT")", ATTRIB,DESCR,{fEA_REG(RxV); fPM_I(RxV,siV); SEMANTICS;})\
|
||||
Q6INSN(L2_##TAG##_pci, OPER"(Rx32++#s4:"SHFT":circ(Mu2))",ATTRIB,DESCR,{fEA_REG(RxV); fPM_CIRI(RxV,siV,MuV); SEMANTICS;})\
|
||||
Q6INSN(L2_##TAG##_pcr, OPER"(Rx32++I:circ(Mu2))", ATTRIB,DESCR,{fEA_REG(RxV); fPM_CIRR(RxV,fREAD_IREG(MuV)<<SCALE,MuV); SEMANTICS;})
|
||||
|
||||
/* The set of 32-bit load instructions */
|
||||
STD_LD_AMODES(loadrub,"Rd32=memub","Load Unsigned Byte",ATTRIBS(A_LOAD),"0",fLOAD(1,1,u,EA,RdV),0)
|
||||
|
@ -42,6 +44,8 @@ Q6INSN(S2_##TAG##_pi, OPER"(Rx32++#s4:"SHFT")="DEST, ATTRIB,DESCR,{fEA_REG(
|
|||
Q6INSN(S4_##TAG##_ap, OPER"(Re32=#U6)="DEST, ATTRIB,DESCR,{fMUST_IMMEXT(UiV); fEA_IMM(UiV); SEMANTICS; ReV=UiV; })\
|
||||
Q6INSN(S2_##TAG##_pr, OPER"(Rx32++Mu2)="DEST, ATTRIB,DESCR,{fEA_REG(RxV); fPM_M(RxV,MuV); SEMANTICS; })\
|
||||
Q6INSN(S4_##TAG##_ur, OPER"(Ru32<<#u2+#U6)="DEST, ATTRIB,DESCR,{fMUST_IMMEXT(UiV); fEA_IRs(UiV,RuV,uiV); SEMANTICS;})\
|
||||
Q6INSN(S2_##TAG##_pci, OPER"(Rx32++#s4:"SHFT":circ(Mu2))="DEST, ATTRIB,DESCR,{fEA_REG(RxV); fPM_CIRI(RxV,siV,MuV); SEMANTICS;})\
|
||||
Q6INSN(S2_##TAG##_pcr, OPER"(Rx32++I:circ(Mu2))="DEST, ATTRIB,DESCR,{fEA_REG(RxV); fPM_CIRR(RxV,fREAD_IREG(MuV)<<SCALE,MuV); SEMANTICS;})
|
||||
|
||||
|
||||
/* The set of 32-bit store instructions */
|
||||
|
|
|
@ -276,6 +276,12 @@ DEF_MACRO(
|
|||
/* Read and Write Implicit Regs */
|
||||
/*************************************/
|
||||
|
||||
DEF_MACRO(
|
||||
fREAD_IREG, /* read modifier register */
|
||||
(fSXTN(11,64,(((VAL) & 0xf0000000)>>21) | ((VAL>>17)&0x7f) )), /* behavior */
|
||||
()
|
||||
)
|
||||
|
||||
DEF_MACRO(
|
||||
fREAD_LR, /* read link register */
|
||||
(READ_RREG(REG_LR)), /* behavior */
|
||||
|
@ -306,6 +312,12 @@ DEF_MACRO(
|
|||
()
|
||||
)
|
||||
|
||||
DEF_MACRO(
|
||||
fREAD_CSREG, /* read CS register */
|
||||
(READ_RREG(REG_CSA+N)), /* behavior */
|
||||
()
|
||||
)
|
||||
|
||||
DEF_MACRO(
|
||||
fREAD_LC0, /* read loop count */
|
||||
(READ_RREG(REG_LC0)), /* behavior */
|
||||
|
@ -824,6 +836,20 @@ DEF_MACRO(
|
|||
()
|
||||
)
|
||||
|
||||
DEF_MACRO(
|
||||
fPM_CIRI, /* Post Modify Register using Circular arithmetic by Immediate */
|
||||
do { fcirc_add(REG,siV,MuV); } while (0),
|
||||
()
|
||||
)
|
||||
|
||||
DEF_MACRO(
|
||||
fPM_CIRR, /* Post Modify Register using Circular arithmetic by register */
|
||||
do { fcirc_add(REG,VAL,MuV); } while (0),
|
||||
()
|
||||
)
|
||||
|
||||
|
||||
|
||||
DEF_MACRO(
|
||||
fSCALE, /* scale by N */
|
||||
(((size8s_t)(A))<<N),
|
||||
|
|
|
@ -133,6 +133,38 @@
|
|||
CHECK_NOSHUF; \
|
||||
tcg_gen_qemu_ld64(DST, VA, ctx->mem_idx); \
|
||||
} while (0)
|
||||
|
||||
#define MEM_STORE1_FUNC(X) \
|
||||
__builtin_choose_expr(TYPE_INT(X), \
|
||||
gen_store1i, \
|
||||
__builtin_choose_expr(TYPE_TCGV(X), \
|
||||
gen_store1, (void)0))
|
||||
#define MEM_STORE1(VA, DATA, SLOT) \
|
||||
MEM_STORE1_FUNC(DATA)(cpu_env, VA, DATA, ctx, SLOT)
|
||||
|
||||
#define MEM_STORE2_FUNC(X) \
|
||||
__builtin_choose_expr(TYPE_INT(X), \
|
||||
gen_store2i, \
|
||||
__builtin_choose_expr(TYPE_TCGV(X), \
|
||||
gen_store2, (void)0))
|
||||
#define MEM_STORE2(VA, DATA, SLOT) \
|
||||
MEM_STORE2_FUNC(DATA)(cpu_env, VA, DATA, ctx, SLOT)
|
||||
|
||||
#define MEM_STORE4_FUNC(X) \
|
||||
__builtin_choose_expr(TYPE_INT(X), \
|
||||
gen_store4i, \
|
||||
__builtin_choose_expr(TYPE_TCGV(X), \
|
||||
gen_store4, (void)0))
|
||||
#define MEM_STORE4(VA, DATA, SLOT) \
|
||||
MEM_STORE4_FUNC(DATA)(cpu_env, VA, DATA, ctx, SLOT)
|
||||
|
||||
#define MEM_STORE8_FUNC(X) \
|
||||
__builtin_choose_expr(TYPE_INT(X), \
|
||||
gen_store8i, \
|
||||
__builtin_choose_expr(TYPE_TCGV_I64(X), \
|
||||
gen_store8, (void)0))
|
||||
#define MEM_STORE8(VA, DATA, SLOT) \
|
||||
MEM_STORE8_FUNC(DATA)(cpu_env, VA, DATA, ctx, SLOT)
|
||||
#else
|
||||
#define MEM_LOAD1s(VA) ((int8_t)mem_load1(env, slot, VA))
|
||||
#define MEM_LOAD1u(VA) ((uint8_t)mem_load1(env, slot, VA))
|
||||
|
@ -285,6 +317,39 @@ static inline void gen_logical_not(TCGv dest, TCGv src)
|
|||
|
||||
#define fPCALIGN(IMM) IMM = (IMM & ~PCALIGN_MASK)
|
||||
|
||||
#ifdef QEMU_GENERATE
|
||||
static inline TCGv gen_read_ireg(TCGv result, TCGv val, int shift)
|
||||
{
|
||||
/*
|
||||
* Section 2.2.4 of the Hexagon V67 Programmer's Reference Manual
|
||||
*
|
||||
* The "I" value from a modifier register is divided into two pieces
|
||||
* LSB bits 23:17
|
||||
* MSB bits 31:28
|
||||
* The value is signed
|
||||
*
|
||||
* At the end we shift the result according to the shift argument
|
||||
*/
|
||||
TCGv msb = tcg_temp_new();
|
||||
TCGv lsb = tcg_temp_new();
|
||||
|
||||
tcg_gen_extract_tl(lsb, val, 17, 7);
|
||||
tcg_gen_sari_tl(msb, val, 21);
|
||||
tcg_gen_deposit_tl(result, msb, lsb, 0, 7);
|
||||
|
||||
tcg_gen_shli_tl(result, result, shift);
|
||||
|
||||
tcg_temp_free(msb);
|
||||
tcg_temp_free(lsb);
|
||||
|
||||
return result;
|
||||
}
|
||||
#define fREAD_IREG(VAL, SHIFT) gen_read_ireg(ireg, (VAL), (SHIFT))
|
||||
#else
|
||||
#define fREAD_IREG(VAL) \
|
||||
(fSXTN(11, 64, (((VAL) & 0xf0000000) >> 21) | ((VAL >> 17) & 0x7f)))
|
||||
#endif
|
||||
|
||||
#define fREAD_LR() (READ_REG(HEX_REG_LR))
|
||||
|
||||
#define fWRITE_LR(A) WRITE_RREG(HEX_REG_LR, A)
|
||||
|
@ -418,6 +483,13 @@ static inline void gen_logical_not(TCGv dest, TCGv src)
|
|||
#define fEA_REG(REG) tcg_gen_mov_tl(EA, REG)
|
||||
#define fPM_I(REG, IMM) tcg_gen_addi_tl(REG, REG, IMM)
|
||||
#define fPM_M(REG, MVAL) tcg_gen_add_tl(REG, REG, MVAL)
|
||||
#define fPM_CIRI(REG, IMM, MVAL) \
|
||||
do { \
|
||||
TCGv tcgv_siV = tcg_const_tl(siV); \
|
||||
gen_helper_fcircadd(REG, REG, tcgv_siV, MuV, \
|
||||
hex_gpr[HEX_REG_CS0 + MuN]); \
|
||||
tcg_temp_free(tcgv_siV); \
|
||||
} while (0)
|
||||
#else
|
||||
#define fEA_IMM(IMM) do { EA = (IMM); } while (0)
|
||||
#define fEA_REG(REG) do { EA = (REG); } while (0)
|
||||
|
@ -494,23 +566,43 @@ static inline void gen_logical_not(TCGv dest, TCGv src)
|
|||
gen_load_locked##SIZE##SIGN(DST, EA, ctx->mem_idx);
|
||||
#endif
|
||||
|
||||
#ifdef QEMU_GENERATE
|
||||
#define fSTORE(NUM, SIZE, EA, SRC) MEM_STORE##SIZE(EA, SRC, insn->slot)
|
||||
#else
|
||||
#define fSTORE(NUM, SIZE, EA, SRC) MEM_STORE##SIZE(EA, SRC, slot)
|
||||
#endif
|
||||
|
||||
#ifdef QEMU_GENERATE
|
||||
#define fSTORE_LOCKED(NUM, SIZE, EA, SRC, PRED) \
|
||||
gen_store_conditional##SIZE(env, ctx, PdN, PRED, EA, SRC);
|
||||
#endif
|
||||
|
||||
#ifdef QEMU_GENERATE
|
||||
#define GETBYTE_FUNC(X) \
|
||||
__builtin_choose_expr(TYPE_TCGV(X), \
|
||||
gen_get_byte, \
|
||||
__builtin_choose_expr(TYPE_TCGV_I64(X), \
|
||||
gen_get_byte_i64, (void)0))
|
||||
#define fGETBYTE(N, SRC) GETBYTE_FUNC(SRC)(BYTE, N, SRC, true)
|
||||
#define fGETUBYTE(N, SRC) GETBYTE_FUNC(SRC)(BYTE, N, SRC, false)
|
||||
#else
|
||||
#define fGETBYTE(N, SRC) ((int8_t)((SRC >> ((N) * 8)) & 0xff))
|
||||
#define fGETUBYTE(N, SRC) ((uint8_t)((SRC >> ((N) * 8)) & 0xff))
|
||||
#endif
|
||||
|
||||
#define fSETBYTE(N, DST, VAL) \
|
||||
do { \
|
||||
DST = (DST & ~(0x0ffLL << ((N) * 8))) | \
|
||||
(((uint64_t)((VAL) & 0x0ffLL)) << ((N) * 8)); \
|
||||
} while (0)
|
||||
|
||||
#ifdef QEMU_GENERATE
|
||||
#define fGETHALF(N, SRC) gen_get_half(HALF, N, SRC, true)
|
||||
#define fGETUHALF(N, SRC) gen_get_half(HALF, N, SRC, false)
|
||||
#else
|
||||
#define fGETHALF(N, SRC) ((int16_t)((SRC >> ((N) * 16)) & 0xffff))
|
||||
#define fGETUHALF(N, SRC) ((uint16_t)((SRC >> ((N) * 16)) & 0xffff))
|
||||
#endif
|
||||
#define fSETHALF(N, DST, VAL) \
|
||||
do { \
|
||||
DST = (DST & ~(0x0ffffLL << ((N) * 16))) | \
|
||||
|
|
|
@ -251,33 +251,25 @@ void HELPER(debug_commit_end)(CPUHexagonState *env, int has_st0, int has_st1)
|
|||
|
||||
}
|
||||
|
||||
static int32_t fcircadd_v4(int32_t RxV, int32_t offset, int32_t M, int32_t CS)
|
||||
{
|
||||
int32_t length = M & 0x0001ffff;
|
||||
uint32_t new_ptr = RxV + offset;
|
||||
uint32_t start_addr = CS;
|
||||
uint32_t end_addr = start_addr + length;
|
||||
|
||||
if (new_ptr >= end_addr) {
|
||||
new_ptr -= length;
|
||||
} else if (new_ptr < start_addr) {
|
||||
new_ptr += length;
|
||||
}
|
||||
|
||||
return new_ptr;
|
||||
}
|
||||
|
||||
int32_t HELPER(fcircadd)(int32_t RxV, int32_t offset, int32_t M, int32_t CS)
|
||||
{
|
||||
int32_t K_const = (M >> 24) & 0xf;
|
||||
int32_t length = M & 0x1ffff;
|
||||
int32_t mask = (1 << (K_const + 2)) - 1;
|
||||
int32_t K_const = sextract32(M, 24, 4);
|
||||
int32_t length = sextract32(M, 0, 17);
|
||||
uint32_t new_ptr = RxV + offset;
|
||||
uint32_t start_addr = RxV & (~mask);
|
||||
uint32_t end_addr = start_addr | length;
|
||||
uint32_t start_addr;
|
||||
uint32_t end_addr;
|
||||
|
||||
if (K_const == 0 && length >= 4) {
|
||||
return fcircadd_v4(RxV, offset, M, CS);
|
||||
start_addr = CS;
|
||||
end_addr = start_addr + length;
|
||||
} else {
|
||||
/*
|
||||
* Versions v3 and earlier used the K value to specify a power-of-2 size
|
||||
* 2^(K+2) that is greater than the buffer length
|
||||
*/
|
||||
int32_t mask = (1 << (K_const + 2)) - 1;
|
||||
start_addr = RxV & (~mask);
|
||||
end_addr = start_addr | length;
|
||||
}
|
||||
|
||||
if (new_ptr >= end_addr) {
|
||||
|
|
|
@ -28,6 +28,7 @@ endif
|
|||
|
||||
|
||||
CFLAGS += -Wno-incompatible-pointer-types -Wno-undefined-internal
|
||||
CFLAGS += -fno-unroll-loops
|
||||
|
||||
HEX_SRC=$(SRC_PATH)/tests/tcg/hexagon
|
||||
VPATH += $(HEX_SRC)
|
||||
|
@ -41,6 +42,7 @@ HEX_TESTS += preg_alias
|
|||
HEX_TESTS += dual_stores
|
||||
HEX_TESTS += multi_result
|
||||
HEX_TESTS += mem_noshuf
|
||||
HEX_TESTS += circ
|
||||
HEX_TESTS += atomics
|
||||
HEX_TESTS += fpstuff
|
||||
|
||||
|
|
|
@ -0,0 +1,486 @@
|
|||
/*
|
||||
* Copyright(c) 2019-2021 Qualcomm Innovation Center, Inc. All Rights Reserved.
|
||||
*
|
||||
* 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 2 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 <stdio.h>
|
||||
|
||||
#define DEBUG 0
|
||||
#define DEBUG_PRINTF(...) \
|
||||
do { \
|
||||
if (DEBUG) { \
|
||||
printf(__VA_ARGS__); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
|
||||
#define NBYTES (1 << 8)
|
||||
#define NHALFS (NBYTES / sizeof(short))
|
||||
#define NWORDS (NBYTES / sizeof(int))
|
||||
#define NDOBLS (NBYTES / sizeof(long long))
|
||||
|
||||
long long dbuf[NDOBLS] __attribute__((aligned(1 << 12))) = {0};
|
||||
int wbuf[NWORDS] __attribute__((aligned(1 << 12))) = {0};
|
||||
short hbuf[NHALFS] __attribute__((aligned(1 << 12))) = {0};
|
||||
unsigned char bbuf[NBYTES] __attribute__((aligned(1 << 12))) = {0};
|
||||
|
||||
/*
|
||||
* We use the C preporcessor to deal with the combinations of types
|
||||
*/
|
||||
|
||||
#define INIT(BUF, N) \
|
||||
void init_##BUF(void) \
|
||||
{ \
|
||||
int i; \
|
||||
for (i = 0; i < N; i++) { \
|
||||
BUF[i] = i; \
|
||||
} \
|
||||
} \
|
||||
|
||||
INIT(bbuf, NBYTES)
|
||||
INIT(hbuf, NHALFS)
|
||||
INIT(wbuf, NWORDS)
|
||||
INIT(dbuf, NDOBLS)
|
||||
|
||||
/*
|
||||
* Macros for performing circular load
|
||||
* RES result
|
||||
* ADDR address
|
||||
* START start address of buffer
|
||||
* LEN length of buffer (in bytes)
|
||||
* INC address increment (in bytes for IMM, elements for REG)
|
||||
*/
|
||||
#define CIRC_LOAD_IMM(SIZE, RES, ADDR, START, LEN, INC) \
|
||||
__asm__( \
|
||||
"r4 = %3\n\t" \
|
||||
"m0 = r4\n\t" \
|
||||
"cs0 = %2\n\t" \
|
||||
"%0 = mem" #SIZE "(%1++#" #INC ":circ(M0))\n\t" \
|
||||
: "=r"(RES), "+r"(ADDR) \
|
||||
: "r"(START), "r"(LEN) \
|
||||
: "r4", "m0", "cs0")
|
||||
#define CIRC_LOAD_IMM_b(RES, ADDR, START, LEN, INC) \
|
||||
CIRC_LOAD_IMM(b, RES, ADDR, START, LEN, INC)
|
||||
#define CIRC_LOAD_IMM_ub(RES, ADDR, START, LEN, INC) \
|
||||
CIRC_LOAD_IMM(ub, RES, ADDR, START, LEN, INC)
|
||||
#define CIRC_LOAD_IMM_h(RES, ADDR, START, LEN, INC) \
|
||||
CIRC_LOAD_IMM(h, RES, ADDR, START, LEN, INC)
|
||||
#define CIRC_LOAD_IMM_uh(RES, ADDR, START, LEN, INC) \
|
||||
CIRC_LOAD_IMM(uh, RES, ADDR, START, LEN, INC)
|
||||
#define CIRC_LOAD_IMM_w(RES, ADDR, START, LEN, INC) \
|
||||
CIRC_LOAD_IMM(w, RES, ADDR, START, LEN, INC)
|
||||
#define CIRC_LOAD_IMM_d(RES, ADDR, START, LEN, INC) \
|
||||
CIRC_LOAD_IMM(d, RES, ADDR, START, LEN, INC)
|
||||
|
||||
/*
|
||||
* The mreg has the following pieces
|
||||
* mreg[31:28] increment[10:7]
|
||||
* mreg[27:24] K value (used Hexagon v3 and earlier)
|
||||
* mreg[23:17] increment[6:0]
|
||||
* mreg[16:0] circular buffer length
|
||||
*/
|
||||
static int build_mreg(int inc, int K, int len)
|
||||
{
|
||||
return ((inc & 0x780) << 21) |
|
||||
((K & 0xf) << 24) |
|
||||
((inc & 0x7f) << 17) |
|
||||
(len & 0x1ffff);
|
||||
}
|
||||
|
||||
#define CIRC_LOAD_REG(SIZE, RES, ADDR, START, LEN, INC) \
|
||||
__asm__( \
|
||||
"r4 = %2\n\t" \
|
||||
"m1 = r4\n\t" \
|
||||
"cs1 = %3\n\t" \
|
||||
"%0 = mem" #SIZE "(%1++I:circ(M1))\n\t" \
|
||||
: "=r"(RES), "+r"(ADDR) \
|
||||
: "r"(build_mreg((INC), 0, (LEN))), \
|
||||
"r"(START) \
|
||||
: "r4", "m1", "cs1")
|
||||
#define CIRC_LOAD_REG_b(RES, ADDR, START, LEN, INC) \
|
||||
CIRC_LOAD_REG(b, RES, ADDR, START, LEN, INC)
|
||||
#define CIRC_LOAD_REG_ub(RES, ADDR, START, LEN, INC) \
|
||||
CIRC_LOAD_REG(ub, RES, ADDR, START, LEN, INC)
|
||||
#define CIRC_LOAD_REG_h(RES, ADDR, START, LEN, INC) \
|
||||
CIRC_LOAD_REG(h, RES, ADDR, START, LEN, INC)
|
||||
#define CIRC_LOAD_REG_uh(RES, ADDR, START, LEN, INC) \
|
||||
CIRC_LOAD_REG(uh, RES, ADDR, START, LEN, INC)
|
||||
#define CIRC_LOAD_REG_w(RES, ADDR, START, LEN, INC) \
|
||||
CIRC_LOAD_REG(w, RES, ADDR, START, LEN, INC)
|
||||
#define CIRC_LOAD_REG_d(RES, ADDR, START, LEN, INC) \
|
||||
CIRC_LOAD_REG(d, RES, ADDR, START, LEN, INC)
|
||||
|
||||
/*
|
||||
* Macros for performing circular store
|
||||
* VAL value to store
|
||||
* ADDR address
|
||||
* START start address of buffer
|
||||
* LEN length of buffer (in bytes)
|
||||
* INC address increment (in bytes for IMM, elements for REG)
|
||||
*/
|
||||
#define CIRC_STORE_IMM(SIZE, PART, VAL, ADDR, START, LEN, INC) \
|
||||
__asm__( \
|
||||
"r4 = %3\n\t" \
|
||||
"m0 = r4\n\t" \
|
||||
"cs0 = %1\n\t" \
|
||||
"mem" #SIZE "(%0++#" #INC ":circ(M0)) = %2" PART "\n\t" \
|
||||
: "+r"(ADDR) \
|
||||
: "r"(START), "r"(VAL), "r"(LEN) \
|
||||
: "r4", "m0", "cs0", "memory")
|
||||
#define CIRC_STORE_IMM_b(VAL, ADDR, START, LEN, INC) \
|
||||
CIRC_STORE_IMM(b, "", VAL, ADDR, START, LEN, INC)
|
||||
#define CIRC_STORE_IMM_h(VAL, ADDR, START, LEN, INC) \
|
||||
CIRC_STORE_IMM(h, "", VAL, ADDR, START, LEN, INC)
|
||||
#define CIRC_STORE_IMM_f(VAL, ADDR, START, LEN, INC) \
|
||||
CIRC_STORE_IMM(h, ".H", VAL, ADDR, START, LEN, INC)
|
||||
#define CIRC_STORE_IMM_w(VAL, ADDR, START, LEN, INC) \
|
||||
CIRC_STORE_IMM(w, "", VAL, ADDR, START, LEN, INC)
|
||||
#define CIRC_STORE_IMM_d(VAL, ADDR, START, LEN, INC) \
|
||||
CIRC_STORE_IMM(d, "", VAL, ADDR, START, LEN, INC)
|
||||
|
||||
#define CIRC_STORE_NEW_IMM(SIZE, VAL, ADDR, START, LEN, INC) \
|
||||
__asm__( \
|
||||
"r4 = %3\n\t" \
|
||||
"m0 = r4\n\t" \
|
||||
"cs0 = %1\n\t" \
|
||||
"{\n\t" \
|
||||
" r5 = %2\n\t" \
|
||||
" mem" #SIZE "(%0++#" #INC ":circ(M0)) = r5.new\n\t" \
|
||||
"}\n\t" \
|
||||
: "+r"(ADDR) \
|
||||
: "r"(START), "r"(VAL), "r"(LEN) \
|
||||
: "r4", "r5", "m0", "cs0", "memory")
|
||||
#define CIRC_STORE_IMM_bnew(VAL, ADDR, START, LEN, INC) \
|
||||
CIRC_STORE_NEW_IMM(b, VAL, ADDR, START, LEN, INC)
|
||||
#define CIRC_STORE_IMM_hnew(VAL, ADDR, START, LEN, INC) \
|
||||
CIRC_STORE_NEW_IMM(h, VAL, ADDR, START, LEN, INC)
|
||||
#define CIRC_STORE_IMM_wnew(VAL, ADDR, START, LEN, INC) \
|
||||
CIRC_STORE_NEW_IMM(w, VAL, ADDR, START, LEN, INC)
|
||||
|
||||
#define CIRC_STORE_REG(SIZE, PART, VAL, ADDR, START, LEN, INC) \
|
||||
__asm__( \
|
||||
"r4 = %1\n\t" \
|
||||
"m1 = r4\n\t" \
|
||||
"cs1 = %2\n\t" \
|
||||
"mem" #SIZE "(%0++I:circ(M1)) = %3" PART "\n\t" \
|
||||
: "+r"(ADDR) \
|
||||
: "r"(build_mreg((INC), 0, (LEN))), \
|
||||
"r"(START), \
|
||||
"r"(VAL) \
|
||||
: "r4", "m1", "cs1", "memory")
|
||||
#define CIRC_STORE_REG_b(VAL, ADDR, START, LEN, INC) \
|
||||
CIRC_STORE_REG(b, "", VAL, ADDR, START, LEN, INC)
|
||||
#define CIRC_STORE_REG_h(VAL, ADDR, START, LEN, INC) \
|
||||
CIRC_STORE_REG(h, "", VAL, ADDR, START, LEN, INC)
|
||||
#define CIRC_STORE_REG_f(VAL, ADDR, START, LEN, INC) \
|
||||
CIRC_STORE_REG(h, ".H", VAL, ADDR, START, LEN, INC)
|
||||
#define CIRC_STORE_REG_w(VAL, ADDR, START, LEN, INC) \
|
||||
CIRC_STORE_REG(w, "", VAL, ADDR, START, LEN, INC)
|
||||
#define CIRC_STORE_REG_d(VAL, ADDR, START, LEN, INC) \
|
||||
CIRC_STORE_REG(d, "", VAL, ADDR, START, LEN, INC)
|
||||
|
||||
#define CIRC_STORE_NEW_REG(SIZE, VAL, ADDR, START, LEN, INC) \
|
||||
__asm__( \
|
||||
"r4 = %1\n\t" \
|
||||
"m1 = r4\n\t" \
|
||||
"cs1 = %2\n\t" \
|
||||
"{\n\t" \
|
||||
" r5 = %3\n\t" \
|
||||
" mem" #SIZE "(%0++I:circ(M1)) = r5.new\n\t" \
|
||||
"}\n\t" \
|
||||
: "+r"(ADDR) \
|
||||
: "r"(build_mreg((INC), 0, (LEN))), \
|
||||
"r"(START), \
|
||||
"r"(VAL) \
|
||||
: "r4", "r5", "m1", "cs1", "memory")
|
||||
#define CIRC_STORE_REG_bnew(VAL, ADDR, START, LEN, INC) \
|
||||
CIRC_STORE_NEW_REG(b, VAL, ADDR, START, LEN, INC)
|
||||
#define CIRC_STORE_REG_hnew(VAL, ADDR, START, LEN, INC) \
|
||||
CIRC_STORE_NEW_REG(h, VAL, ADDR, START, LEN, INC)
|
||||
#define CIRC_STORE_REG_wnew(VAL, ADDR, START, LEN, INC) \
|
||||
CIRC_STORE_NEW_REG(w, VAL, ADDR, START, LEN, INC)
|
||||
|
||||
|
||||
int err;
|
||||
|
||||
/* We'll test increments +1 and -1 */
|
||||
void check_load(int i, long long result, int inc, int size)
|
||||
{
|
||||
int expect = (i * inc);
|
||||
while (expect >= size) {
|
||||
expect -= size;
|
||||
}
|
||||
while (expect < 0) {
|
||||
expect += size;
|
||||
}
|
||||
if (result != expect) {
|
||||
printf("ERROR(%d): %lld != %d\n", i, result, expect);
|
||||
err++;
|
||||
}
|
||||
}
|
||||
|
||||
#define TEST_LOAD_IMM(SZ, TYPE, BUF, BUFSIZE, INC, FMT) \
|
||||
void circ_test_load_imm_##SZ(void) \
|
||||
{ \
|
||||
TYPE *p = (TYPE *)BUF; \
|
||||
int size = 10; \
|
||||
int i; \
|
||||
for (i = 0; i < BUFSIZE; i++) { \
|
||||
TYPE element; \
|
||||
CIRC_LOAD_IMM_##SZ(element, p, BUF, size * sizeof(TYPE), (INC)); \
|
||||
DEBUG_PRINTF("i = %2d, p = 0x%p, element = %2" #FMT "\n", \
|
||||
i, p, element); \
|
||||
check_load(i, element, ((INC) / (int)sizeof(TYPE)), size); \
|
||||
} \
|
||||
p = (TYPE *)BUF; \
|
||||
for (i = 0; i < BUFSIZE; i++) { \
|
||||
TYPE element; \
|
||||
CIRC_LOAD_IMM_##SZ(element, p, BUF, size * sizeof(TYPE), -(INC)); \
|
||||
DEBUG_PRINTF("i = %2d, p = 0x%p, element = %2" #FMT "\n", \
|
||||
i, p, element); \
|
||||
check_load(i, element, (-(INC) / (int)sizeof(TYPE)), size); \
|
||||
} \
|
||||
}
|
||||
|
||||
TEST_LOAD_IMM(b, char, bbuf, NBYTES, 1, d)
|
||||
TEST_LOAD_IMM(ub, unsigned char, bbuf, NBYTES, 1, d)
|
||||
TEST_LOAD_IMM(h, short, hbuf, NHALFS, 2, d)
|
||||
TEST_LOAD_IMM(uh, unsigned short, hbuf, NHALFS, 2, d)
|
||||
TEST_LOAD_IMM(w, int, wbuf, NWORDS, 4, d)
|
||||
TEST_LOAD_IMM(d, long long, dbuf, NDOBLS, 8, lld)
|
||||
|
||||
#define TEST_LOAD_REG(SZ, TYPE, BUF, BUFSIZE, FMT) \
|
||||
void circ_test_load_reg_##SZ(void) \
|
||||
{ \
|
||||
TYPE *p = (TYPE *)BUF; \
|
||||
int size = 13; \
|
||||
int i; \
|
||||
for (i = 0; i < BUFSIZE; i++) { \
|
||||
TYPE element; \
|
||||
CIRC_LOAD_REG_##SZ(element, p, BUF, size * sizeof(TYPE), 1); \
|
||||
DEBUG_PRINTF("i = %2d, p = 0x%p, element = %2" #FMT "\n", \
|
||||
i, p, element); \
|
||||
check_load(i, element, 1, size); \
|
||||
} \
|
||||
p = (TYPE *)BUF; \
|
||||
for (i = 0; i < BUFSIZE; i++) { \
|
||||
TYPE element; \
|
||||
CIRC_LOAD_REG_##SZ(element, p, BUF, size * sizeof(TYPE), -1); \
|
||||
DEBUG_PRINTF("i = %2d, p = 0x%p, element = %2" #FMT "\n", \
|
||||
i, p, element); \
|
||||
check_load(i, element, -1, size); \
|
||||
} \
|
||||
}
|
||||
|
||||
TEST_LOAD_REG(b, char, bbuf, NBYTES, d)
|
||||
TEST_LOAD_REG(ub, unsigned char, bbuf, NBYTES, d)
|
||||
TEST_LOAD_REG(h, short, hbuf, NHALFS, d)
|
||||
TEST_LOAD_REG(uh, unsigned short, hbuf, NHALFS, d)
|
||||
TEST_LOAD_REG(w, int, wbuf, NWORDS, d)
|
||||
TEST_LOAD_REG(d, long long, dbuf, NDOBLS, lld)
|
||||
|
||||
/* The circular stores will wrap around somewhere inside the buffer */
|
||||
#define CIRC_VAL(SZ, TYPE, BUFSIZE) \
|
||||
TYPE circ_val_##SZ(int i, int inc, int size) \
|
||||
{ \
|
||||
int mod = BUFSIZE % size; \
|
||||
int elem = i * inc; \
|
||||
if (elem < 0) { \
|
||||
if (-elem <= size - mod) { \
|
||||
return (elem + BUFSIZE - mod); \
|
||||
} else { \
|
||||
return (elem + BUFSIZE + size - mod); \
|
||||
} \
|
||||
} else if (elem < mod) {\
|
||||
return (elem + BUFSIZE - mod); \
|
||||
} else { \
|
||||
return (elem + BUFSIZE - size - mod); \
|
||||
} \
|
||||
}
|
||||
|
||||
CIRC_VAL(b, unsigned char, NBYTES)
|
||||
CIRC_VAL(h, short, NHALFS)
|
||||
CIRC_VAL(w, int, NWORDS)
|
||||
CIRC_VAL(d, long long, NDOBLS)
|
||||
|
||||
/*
|
||||
* Circular stores should only write to the first "size" elements of the buffer
|
||||
* the remainder of the elements should have BUF[i] == i
|
||||
*/
|
||||
#define CHECK_STORE(SZ, BUF, BUFSIZE, FMT) \
|
||||
void check_store_##SZ(int inc, int size) \
|
||||
{ \
|
||||
int i; \
|
||||
for (i = 0; i < size; i++) { \
|
||||
DEBUG_PRINTF(#BUF "[%3d] = 0x%02" #FMT ", guess = 0x%02" #FMT "\n", \
|
||||
i, BUF[i], circ_val_##SZ(i, inc, size)); \
|
||||
if (BUF[i] != circ_val_##SZ(i, inc, size)) { \
|
||||
printf("ERROR(%3d): 0x%02" #FMT " != 0x%02" #FMT "\n", \
|
||||
i, BUF[i], circ_val_##SZ(i, inc, size)); \
|
||||
err++; \
|
||||
} \
|
||||
} \
|
||||
for (i = size; i < BUFSIZE; i++) { \
|
||||
if (BUF[i] != i) { \
|
||||
printf("ERROR(%3d): 0x%02" #FMT " != 0x%02x\n", i, BUF[i], i); \
|
||||
err++; \
|
||||
} \
|
||||
} \
|
||||
}
|
||||
|
||||
CHECK_STORE(b, bbuf, NBYTES, x)
|
||||
CHECK_STORE(h, hbuf, NHALFS, x)
|
||||
CHECK_STORE(w, wbuf, NWORDS, x)
|
||||
CHECK_STORE(d, dbuf, NDOBLS, llx)
|
||||
|
||||
#define CIRC_TEST_STORE_IMM(SZ, CHK, TYPE, BUF, BUFSIZE, SHIFT, INC) \
|
||||
void circ_test_store_imm_##SZ(void) \
|
||||
{ \
|
||||
unsigned int size = 27; \
|
||||
TYPE *p = BUF; \
|
||||
TYPE val = 0; \
|
||||
int i; \
|
||||
init_##BUF(); \
|
||||
for (i = 0; i < BUFSIZE; i++) { \
|
||||
CIRC_STORE_IMM_##SZ(val << SHIFT, p, BUF, size * sizeof(TYPE), INC); \
|
||||
val++; \
|
||||
} \
|
||||
check_store_##CHK(((INC) / (int)sizeof(TYPE)), size); \
|
||||
p = BUF; \
|
||||
val = 0; \
|
||||
init_##BUF(); \
|
||||
for (i = 0; i < BUFSIZE; i++) { \
|
||||
CIRC_STORE_IMM_##SZ(val << SHIFT, p, BUF, size * sizeof(TYPE), \
|
||||
-(INC)); \
|
||||
val++; \
|
||||
} \
|
||||
check_store_##CHK((-(INC) / (int)sizeof(TYPE)), size); \
|
||||
}
|
||||
|
||||
CIRC_TEST_STORE_IMM(b, b, unsigned char, bbuf, NBYTES, 0, 1)
|
||||
CIRC_TEST_STORE_IMM(h, h, short, hbuf, NHALFS, 0, 2)
|
||||
CIRC_TEST_STORE_IMM(f, h, short, hbuf, NHALFS, 16, 2)
|
||||
CIRC_TEST_STORE_IMM(w, w, int, wbuf, NWORDS, 0, 4)
|
||||
CIRC_TEST_STORE_IMM(d, d, long long, dbuf, NDOBLS, 0, 8)
|
||||
CIRC_TEST_STORE_IMM(bnew, b, unsigned char, bbuf, NBYTES, 0, 1)
|
||||
CIRC_TEST_STORE_IMM(hnew, h, short, hbuf, NHALFS, 0, 2)
|
||||
CIRC_TEST_STORE_IMM(wnew, w, int, wbuf, NWORDS, 0, 4)
|
||||
|
||||
#define CIRC_TEST_STORE_REG(SZ, CHK, TYPE, BUF, BUFSIZE, SHIFT) \
|
||||
void circ_test_store_reg_##SZ(void) \
|
||||
{ \
|
||||
TYPE *p = BUF; \
|
||||
unsigned int size = 19; \
|
||||
TYPE val = 0; \
|
||||
int i; \
|
||||
init_##BUF(); \
|
||||
for (i = 0; i < BUFSIZE; i++) { \
|
||||
CIRC_STORE_REG_##SZ(val << SHIFT, p, BUF, size * sizeof(TYPE), 1); \
|
||||
val++; \
|
||||
} \
|
||||
check_store_##CHK(1, size); \
|
||||
p = BUF; \
|
||||
val = 0; \
|
||||
init_##BUF(); \
|
||||
for (i = 0; i < BUFSIZE; i++) { \
|
||||
CIRC_STORE_REG_##SZ(val << SHIFT, p, BUF, size * sizeof(TYPE), -1); \
|
||||
val++; \
|
||||
} \
|
||||
check_store_##CHK(-1, size); \
|
||||
}
|
||||
|
||||
CIRC_TEST_STORE_REG(b, b, unsigned char, bbuf, NBYTES, 0)
|
||||
CIRC_TEST_STORE_REG(h, h, short, hbuf, NHALFS, 0)
|
||||
CIRC_TEST_STORE_REG(f, h, short, hbuf, NHALFS, 16)
|
||||
CIRC_TEST_STORE_REG(w, w, int, wbuf, NWORDS, 0)
|
||||
CIRC_TEST_STORE_REG(d, d, long long, dbuf, NDOBLS, 0)
|
||||
CIRC_TEST_STORE_REG(bnew, b, unsigned char, bbuf, NBYTES, 0)
|
||||
CIRC_TEST_STORE_REG(hnew, h, short, hbuf, NHALFS, 0)
|
||||
CIRC_TEST_STORE_REG(wnew, w, int, wbuf, NWORDS, 0)
|
||||
|
||||
/* Test the old scheme used in Hexagon V3 */
|
||||
static void circ_test_v3(void)
|
||||
{
|
||||
int *p = wbuf;
|
||||
int size = 15;
|
||||
int K = 4; /* 64 bytes */
|
||||
int element;
|
||||
int i;
|
||||
|
||||
init_wbuf();
|
||||
|
||||
for (i = 0; i < NWORDS; i++) {
|
||||
__asm__(
|
||||
"r4 = %2\n\t"
|
||||
"m1 = r4\n\t"
|
||||
"%0 = memw(%1++I:circ(M1))\n\t"
|
||||
: "=r"(element), "+r"(p)
|
||||
: "r"(build_mreg(1, K, size * sizeof(int)))
|
||||
: "r4", "m1");
|
||||
DEBUG_PRINTF("i = %2d, p = 0x%p, element = %2d\n", i, p, element);
|
||||
check_load(i, element, 1, size);
|
||||
}
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
init_bbuf();
|
||||
init_hbuf();
|
||||
init_wbuf();
|
||||
init_dbuf();
|
||||
|
||||
DEBUG_PRINTF("NBYTES = %d\n", NBYTES);
|
||||
DEBUG_PRINTF("Address of dbuf = 0x%p\n", dbuf);
|
||||
DEBUG_PRINTF("Address of wbuf = 0x%p\n", wbuf);
|
||||
DEBUG_PRINTF("Address of hbuf = 0x%p\n", hbuf);
|
||||
DEBUG_PRINTF("Address of bbuf = 0x%p\n", bbuf);
|
||||
|
||||
circ_test_load_imm_b();
|
||||
circ_test_load_imm_ub();
|
||||
circ_test_load_imm_h();
|
||||
circ_test_load_imm_uh();
|
||||
circ_test_load_imm_w();
|
||||
circ_test_load_imm_d();
|
||||
|
||||
circ_test_load_reg_b();
|
||||
circ_test_load_reg_ub();
|
||||
circ_test_load_reg_h();
|
||||
circ_test_load_reg_uh();
|
||||
circ_test_load_reg_w();
|
||||
circ_test_load_reg_d();
|
||||
|
||||
circ_test_store_imm_b();
|
||||
circ_test_store_imm_h();
|
||||
circ_test_store_imm_f();
|
||||
circ_test_store_imm_w();
|
||||
circ_test_store_imm_d();
|
||||
circ_test_store_imm_bnew();
|
||||
circ_test_store_imm_hnew();
|
||||
circ_test_store_imm_wnew();
|
||||
|
||||
circ_test_store_reg_b();
|
||||
circ_test_store_reg_h();
|
||||
circ_test_store_reg_f();
|
||||
circ_test_store_reg_w();
|
||||
circ_test_store_reg_d();
|
||||
circ_test_store_reg_bnew();
|
||||
circ_test_store_reg_hnew();
|
||||
circ_test_store_reg_wnew();
|
||||
|
||||
circ_test_v3();
|
||||
|
||||
puts(err ? "FAIL" : "PASS");
|
||||
return err ? 1 : 0;
|
||||
}
|
Loading…
Reference in New Issue