diff --git a/core/exception_vectors.S b/core/exception_vectors.S index bfda81e..eda3389 100644 --- a/core/exception_vectors.S +++ b/core/exception_vectors.S @@ -302,6 +302,8 @@ UserLoadStoreExceptionHandler: movi a4, 0x001002 /* l16ui opcode after masking */ beq a3, a4, .Lcan_fix_16bit + movi a4, 0x009002 /* l16si opcode after masking */ + beq a3, a4, .Lcan_fix_16bit_signed .Lcant_fix: /* not an l8ui or an l16ui, or not in the instruction space, so bomb out TODO: the exception dump will have some wrong values in it */ @@ -310,6 +312,9 @@ TODO: the exception dump will have some wrong values in it */ call0 printf call0 sdk_user_fatal_exception_handler +.Lcan_fix_16bit_signed: + movi a5, 0x7FFF + j .Lcan_fix .Lcan_fix_16bit: movi a5, 0xFFFF j .Lcan_fix @@ -334,11 +339,15 @@ TODO: the exception dump will have some wrong values in it */ l32i a3, a3, 0 /* perform the actual read */ srl a3, a3 /* shift right correct distance */ - and a3, a3, a5 /* mask off bits we need for an l8/l16 */ + and a4, a3, a5 /* mask off bits we need for an l8/l16 */ + + bbci a5, 15, .Lextend_sign +.Lafter_extend_sign: + /* a4 holds the correctly read value */ /* write read value to register slot */ add a5, sp, a2 - s32i a3, a5, 0 + s32i a4, a5, 0 /* Footer*/ //Increment PC @@ -367,6 +376,13 @@ TODO: the exception dump will have some wrong values in it */ addi sp, sp, 0x40 rfe +.Lextend_sign: /* apply 16-bit sign extension if necessary + a3 holds raw value, a4 holds masked */ + bbci a3, 15, .Lafter_extend_sign /* sign bit not set, do nothing */ + movi a3, (1<<31) + or a4, a3, a4 /* set sign bit */ + j .Lafter_extend_sign + .global _xt_user_exit .type _xt_user_exit, @function _xt_user_exit: diff --git a/examples/experiments/unaligned_load/unaligned_load.c b/examples/experiments/unaligned_load/unaligned_load.c index 033c7be..c65a818 100644 --- a/examples/experiments/unaligned_load/unaligned_load.c +++ b/examples/experiments/unaligned_load/unaligned_load.c @@ -64,6 +64,17 @@ void test_naive_strcpy(const char *string) ; } +void test_l16si(const char *string) +{ + /* This follows most of the l16si path, but as the + values in the string are all 7 bit none of them get sign extended */ + int16_t *src_int16 = (int16_t *)string; + int32_t *dst_int32 = (int32_t *)buf; + dst_int32[0] = src_int16[0]; + dst_int32[1] = src_int16[1]; + dst_int32[2] = src_int16[2]; +} + #define TEST_REPEATS 1000 void test_noop(const char *string) @@ -104,6 +115,7 @@ void test_string(const char *string, char *label, bool evict_cache) run_test(string, test_naive_strcpy, "naive strcpy", nullvalue, evict_cache); run_test(string, test_sprintf, "sprintf", nullvalue, evict_cache); run_test(string, test_sprintf_arg, "sprintf format arg", nullvalue, evict_cache); + run_test(string, test_l16si, "load as l16si", nullvalue, evict_cache); } void user_init(void)