# See LICENSE for license details.

#*****************************************************************************
# ma_addr.S
#-----------------------------------------------------------------------------
#
# Test misaligned ld/st trap.
#

#include "riscv_test.h"
#include "test_macros.h"

RVTEST_RV64M
RVTEST_CODE_BEGIN

  .align 2
  .option norvc

  la s0, data

  # indicate it's a load test
  li s1, CAUSE_MISALIGNED_LOAD

#define SEXT(x, n) ((-((x) >> ((n)-1)) << (n)) | ((x) & ((1 << (n))-1)))

/* Check that a misaligned load either writes the correct value, or
   takes an exception and performs no writeback.  */
#define MISALIGNED_LOAD_TEST(testnum, insn, base, offset, res) \
  li TESTNUM, testnum; \
  la t2, 1f; \
  addi t1, base, offset; \
  insn t1, offset(base); \
  li t2, res; \
  bne t1, t2, fail; \
1:

  MISALIGNED_LOAD_TEST(2,  lh,  s0, 1, SEXT(0xbbcc, 16))
  MISALIGNED_LOAD_TEST(3,  lhu, s0, 1, 0xbbcc)
  MISALIGNED_LOAD_TEST(4,  lw,  s0, 1, SEXT(0x99aabbcc, 32))
  MISALIGNED_LOAD_TEST(5,  lw,  s0, 2, SEXT(0x8899aabb, 32))
  MISALIGNED_LOAD_TEST(6,  lw,  s0, 3, SEXT(0x778899aa, 32))

#if __riscv_xlen == 64
  MISALIGNED_LOAD_TEST(7,  lwu, s0, 1, 0x99aabbcc)
  MISALIGNED_LOAD_TEST(8,  lwu, s0, 2, 0x8899aabb)
  MISALIGNED_LOAD_TEST(9,  lwu, s0, 3, 0x778899aa)

  MISALIGNED_LOAD_TEST(10, ld, s0, 1, 0x5566778899aabbcc)
  MISALIGNED_LOAD_TEST(11, ld, s0, 2, 0x445566778899aabb)
  MISALIGNED_LOAD_TEST(12, ld, s0, 3, 0x33445566778899aa)
  MISALIGNED_LOAD_TEST(13, ld, s0, 4, 0x2233445566778899)
  MISALIGNED_LOAD_TEST(14, ld, s0, 5, 0x1122334455667788)
  MISALIGNED_LOAD_TEST(15, ld, s0, 6, 0xee11223344556677)
  MISALIGNED_LOAD_TEST(16, ld, s0, 7, 0xffee112233445566)
#endif

  # indicate it's a store test
  li s1, CAUSE_MISALIGNED_STORE

/* Check that a misaligned store has some effect and takes no exception,
   or takes no effect and generates an exception.  This is not very
   thorough.  */
#define MISALIGNED_STORE_TEST(testnum, insn, base, offset, size) \
  li TESTNUM, testnum; \
  la t2, 1f; \
  addi t1, base, offset; \
  insn x0, offset(base); \
  lb t1, (offset - 1)(base); \
  beqz t1, fail; \
  lb t1, (offset + size)(base); \
  beqz t1, fail; \
  lb t1, (offset + 0)(base); \
  bnez t1, fail; \
  lb t1, (offset + size - 1)(base); \
  bnez t1, fail; \
1:

  MISALIGNED_STORE_TEST(22,  sh,  s0, 1, 2)
  MISALIGNED_STORE_TEST(23,  sw,  s0, 5, 4)
  MISALIGNED_STORE_TEST(24,  sw,  s0, 10, 4)
  MISALIGNED_STORE_TEST(25,  sw,  s0, 15, 4)

#if __riscv_xlen == 64
  MISALIGNED_STORE_TEST(26, sd, s0, 25, 8)
  MISALIGNED_STORE_TEST(27, sd, s0, 34, 8)
  MISALIGNED_STORE_TEST(28, sd, s0, 43, 8)
  MISALIGNED_STORE_TEST(29, sd, s0, 52, 8)
  MISALIGNED_STORE_TEST(30, sd, s0, 61, 8)
  MISALIGNED_STORE_TEST(31, sd, s0, 70, 8)
  MISALIGNED_STORE_TEST(32, sd, s0, 79, 8)
#endif

  TEST_PASSFAIL

  .align 3
  .global mtvec_handler
mtvec_handler:
  csrr t0, mcause
  bne t0, s1, fail

  csrr t0, mbadaddr
  beqz t0, 1f
  bne t0, t1, fail

  lb t0, (t0)
  beqz t0, fail
1:

  csrw mepc, t2
  mret

RVTEST_CODE_END

  .data
RVTEST_DATA_BEGIN

data:
  .align 3
.word 0xaabbccdd
.word 0x66778899
.word 0x22334455
.word 0xeeffee11
.fill 0xff, 1, 80


  TEST_DATA

RVTEST_DATA_END
