#ifndef SIFIVE_SMP
#define SIFIVE_SMP

// The maximum number of HARTs this code supports
#ifndef MAX_HARTS
#define MAX_HARTS 32
#endif
#define CLINT_END_HART_IPI CLINT_CTRL_ADDR + (MAX_HARTS*4)

// The hart that non-SMP tests should run on
#ifndef NONSMP_HART
#define NONSMP_HART 0
#endif

/* If your test cannot handle multiple-threads, use this: 
 *   smp_disable(reg1)
 */
#define smp_disable(reg1, reg2)			 \
  csrr reg1, mhartid				;\
  li   reg2, NONSMP_HART			;\
  beq  reg1, reg2, hart0_entry			;\
42:						;\
  wfi    					;\
  j 42b						;\
hart0_entry:

/* If your test needs to temporarily block multiple-threads, do this:
 *    smp_pause(reg1, reg2)
 *    ... single-threaded work ...
 *    smp_resume(reg1, reg2)
 *    ... multi-threaded work ...
 */

#define smp_pause(reg1, reg2)	 \
  li reg2, 0x8			;\
  csrw mie, reg2		;\
  csrr reg2, mhartid		;\
  bnez reg2, 42f

#define smp_resume(reg1, reg2)	 \
  li reg1, CLINT_CTRL_ADDR	;\
41:				;\
  li reg2, 1			;\
  sw reg2, 0(reg1)		;\
  addi reg1, reg1, 4		;\
  li reg2, CLINT_END_HART_IPI	;\
  blt reg1, reg2, 41b		;\
42:				;\
  wfi    			;\
  csrr reg2, mip		;\
  andi reg2, reg2, 0x8		;\
  beqz reg2, 42b		;\
  li reg1, CLINT_CTRL_ADDR	;\
  csrr reg2, mhartid		;\
  slli reg2, reg2, 2		;\
  add reg2, reg2, reg1		;\
  sw zero, 0(reg2)		;\
41:				;\
  lw reg2, 0(reg1)		;\
  bnez reg2, 41b		;\
  addi reg1, reg1, 4		;\
  li reg2, CLINT_END_HART_IPI	;\
  blt reg1, reg2, 41b

#endif
