| # 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 |