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)