# R0 and P0 are used as tmps, consider them call clobbered by these macros.

# To build for hardware, use:
# bfin-linux-uclibc-gcc -nostdlib -g -Wa,--defsym,BFIN_HOST=1 foo.s

# MACRO: start
# All assembler tests should start with a call to "start"
	.macro start
	.text
	# Pad with EMUEXCPT to make sure "jump to 0" always fails
__panic:
	.rep 0xf
	.word 0x0025
	.endr
	abort;
	jump __panic;

	.global __pass
__pass:
	write 1, _passmsg, 5
	exit 0
.ifdef BFIN_JTAG
__emu_out:
	/* DBGSTAT */
	imm32 P0 0xFFE05008;

1:	R7 = [P0];
	CC = BITTST (R7,0);
	IF CC JUMP 1b;

	EMUDAT = R0;
	RTS;
.endif
	.global __fail
__fail:
.ifndef BFIN_HOST
	P0.H = _rets;
	P0.L = _rets;
	R0 = RETS;
	R0 += -4;
	P1 = 8;
	R2 = '9';
	LSETUP (1f, 3f) LC0 = P1;
1:
	R1 = R0;
	R1 >>= 28;
	R1 += 0x30;
	CC = R2 < R1;
	IF !CC jump 2f;
	R1 += 7;
2:
	B[P0++] = R1;
3:
	R0 <<= 4;

	write 1, _failmsg, 22
.else
	write 1, _failmsg, 5
.endif
	exit 1

.ifndef BFIN_HOST
	.data
_failmsg:
	.ascii "fail at PC=0x"
_rets:
	.ascii "12345678\n"
_passmsg:
	.ascii "pass\n"
	.align 4
_params:
	.long 0
	.long 0
	.long 0
	.long 0

	.text
	.global __start
__start:
.else
.global ___uClibc_main;
___uClibc_main:
.global _main;
_main:
.endif
	.endm

# MACRO: system_call
# Make a libgloss/Linux system call
	.macro system_call nr:req
	P0 = \nr (X);
	EXCPT 0;
	.endm

# MACRO: exit
# Quit the current test
	.macro exit rc:req
	R0 = \rc (X);
.ifndef BFIN_HOST
	P0.H = _params;
	P0.L = _params;
	[P0] = R0;
	R0 = P0;
.endif
	system_call 1
	.endm

# MACRO: pass
# Write 'pass' to stdout via syscalls and quit;
# meant for non-OS operating environments
	.macro pass
	CALL __pass;
	.endm

# MACRO: fail
# Write 'fail' to stdout via syscalls and quit;
# meant for non-OS operating environments
	.macro fail
	CALL __fail;
	.endm

# MACRO: write
# Just like the write() C function; uses system calls
	.macro write fd:req, buf:req, count:req
.ifndef BFIN_HOST
	P0.H = _params;
	P0.L = _params;
	R0 = \fd (X);
	[P0] = R0;
	R0.H = \buf;
	R0.L = \buf;
	[P0 + 4] = R0;
	R0 = \count (X);
	[P0 + 8] = R0;
	R0 = P0;
	system_call 5
.endif
	.endm

# MACRO: outc_str
# Output a string using the debug OUTC insn
	.macro outc_str ch:req, more:vararg
	OUTC \ch;
	.ifnb \more
	outc_str \more
	.endif
	.endm

# MACRO: dbg_pass
# Write 'pass' to stdout and quit (all via debug insns);
# meant for OS operating environments
	.macro dbg_pass
.ifdef BFIN_JTAG
	R0 = 6;
	CALL __emu_out;
	R0.L = 0x6170;	/* 'p'=0x70  'a'=0x70 */
	R0.H = 0x7373;	/* 's'=0x73 */
	CALL __emu_out;

	R0.L = 0x0A;	/* newline */
	R0.H = 0x0000;
	CALL __emu_out;  
1:
	EMUEXCPT;
	JUMP 1b;
.else
	outc_str 'p', 'a', 's', 's', '\n'
	HLT;
.endif
	.endm

# MACRO: dbg_fail
# Write 'fail' to stdout and quit (all via debug insns);
# meant for OS operating environments
	.macro dbg_fail
.ifdef BFIN_JTAG
	R0 = 6;
	CALL __emu_out;
	R0.L = 0x6166;  /* 'f'=0x66  'a'=0x61 */
	R0.H = 0x6c69;  /* 'i'=0x69  'l'=0x6c */
	CALL __emu_out;

	R0.L = 0x0A;    /* newline */
	R0.H = 0x0000;
	CALL __emu_out;
1:
	EMUEXCPT;
	JUMP 1b;
.else
	outc_str 'f', 'a', 'i', 'l', '\n'
.endif
	ABORT;
	.endm

# MACRO: imm32
# Load a 32bit immediate directly into a register
	.macro imm32 reg:req, val:req
	.if (\val) & ~0x7fff
	\reg\().L = ((\val) & 0xffff);
	\reg\().H = (((\val) >> 16) & 0xffff);
	.else
	\reg = \val;
	.endif
	.endm

# MACRO: dmm32
# Load a 32bit immediate indirectly into a register
	.macro dmm32 reg:req, val:req
	[--SP] = R0;
	imm32 R0, \val
	\reg = R0;
	R0 = [SP++];
	.endm

# MACRO: loadsym
# Load a symbol directly into a register
.ifndef BFIN_HOST
	.macro loadsym reg:req, sym:req, offset=0
	\reg\().L = (\sym\() + \offset\());
	\reg\().H = (\sym\() + \offset\());
	.endm
.else
	.macro loadsym reg:req, sym:req, offset=0
	[--SP] = R0;
	R0 = [P3 + \sym\()@GOT17M4];
	.if \offset
	[--SP] = R1;
	R1 = \offset\() (Z);
	R0 = R0 + R1;
	R1 = [SP++];
	.endif
	\reg = R0;
	R0 = [SP++];
	.endm
.endif

# MACRO: CHECKREG
# Use debug insns to verify the value of a register matches
	.macro CHECKREG reg:req, val:req
	DBGAL (\reg, ((\val) & 0xffff));
	DBGAH (\reg, (((\val) >> 16) & 0xffff));
	.endm

# internal helper macros; ignore them
	.macro __init_regs reg:req, max:req, x:req, val:req
	.ifle (\x - \max)
	imm32 \reg\()\x, \val
	.endif
	.endm
	.macro _init_regs reg:req, max:req, val:req
	__init_regs \reg, \max, 0, \val
	__init_regs \reg, \max, 1, \val
	__init_regs \reg, \max, 2, \val
	__init_regs \reg, \max, 3, \val
	__init_regs \reg, \max, 4, \val
	__init_regs \reg, \max, 5, \val
	__init_regs \reg, \max, 6, \val
	__init_regs \reg, \max, 7, \val
	.endm

# MACRO: init_r_regs
# MACRO: init_p_regs
# MACRO: init_b_regs
# MACRO: init_i_regs
# MACRO: init_l_regs
# MACRO: init_m_regs
# Set the specified group of regs to the specified value
	.macro init_r_regs val:req
	_init_regs R, 7, \val
	.endm
	.macro init_p_regs val:req
	_init_regs P, 5, \val
	.endm
	.macro init_b_regs val:req
	_init_regs B, 3, \val
	.endm
	.macro init_i_regs val:req
	_init_regs I, 3, \val
	.endm
	.macro init_l_regs val:req
	_init_regs L, 3, \val
	.endm
	.macro init_m_regs val:req
	_init_regs M, 3, \val
	.endm

	// the test framework needs things to be quiet, so don't
	// print things out by default.
	.macro _DBG reg:req
	//DBG \reg;
	.endm

	.macro _DBGCMPLX reg:req
	//
	.endm
