| # gr28-gr31, fr31, icc3, fcc3 are used as tmps. | |
| # consider them call clobbered by these macros. | |
| .macro start | |
| .data | |
| failmsg: | |
| .ascii "fail\n" | |
| passmsg: | |
| .ascii "pass\n" | |
| .text | |
| .global _start | |
| _start: | |
| ; enable data and insn caches in copy-back mode | |
| ; Also enable all registers | |
| or_spr_immed 0xc80003c0,hsr0 | |
| and_spr_immed 0xfffff3ff,hsr0 | |
| ; turn on psr.nem, psr.cm, psr.ef, psr.em, psr.esr, | |
| ; disable external interrupts | |
| or_spr_immed 0x69f8,psr | |
| ; If fsr exists, enable all fp_exceptions except inexact | |
| movsg psr,gr28 | |
| srli gr28,28,gr28 | |
| subicc gr28,0x2,gr0,icc3 ; is fr400? | |
| beq icc3,0,nofsr0 | |
| or_spr_immed 0x3d000000,fsr0 | |
| nofsr0: | |
| ; Set the stack pointer | |
| sethi.p 0x7,sp | |
| setlo 0xfffc,sp ; TODO -- what's a good value for this? | |
| ; Set the TBR address | |
| sethi.p 0xf,gr28 | |
| setlo 0xf000,gr28 | |
| movgs gr28,tbr ; TODO -- what's a good value for this? | |
| ; Go to user mode -- causes too many problems | |
| ;and_spr_immed 0xfffffffb,psr | |
| .endm | |
| ; Set GR with another GR | |
| .macro set_gr_gr src targ | |
| addi \src,0,\targ | |
| .endm | |
| ; Set GR with immediate value | |
| .macro set_gr_immed val reg | |
| .if (\val >= -32768) && (\val <= 23767) | |
| setlos \val,\reg | |
| .else | |
| setlo.p %lo(\val),\reg | |
| sethi %hi(\val),\reg | |
| .endif | |
| .endm | |
| .macro set_gr_limmed valh vall reg | |
| sethi.p \valh,\reg | |
| setlo \vall,\reg | |
| .endm | |
| ; Set GR with address value | |
| .macro set_gr_addr addr reg | |
| sethi.p %hi(\addr),\reg | |
| setlo %lo(\addr),\reg | |
| .endm | |
| ; Set GR with SPR | |
| .macro set_gr_spr src targ | |
| movsg \src,\targ | |
| .endm | |
| ; Set GR with a value from memory | |
| .macro set_gr_mem addr reg | |
| set_gr_addr \addr,gr28 | |
| ldi @(gr28,0),\reg | |
| .endm | |
| ; Increment GR with immediate value | |
| .macro inc_gr_immed val reg | |
| .if (\val >= -2048) && (\val <= 2047) | |
| addi \reg,\val,\reg | |
| .else | |
| set_gr_immed \val,gr28 | |
| add \reg,gr28,\reg | |
| .endif | |
| .endm | |
| ; AND GR with immediate value | |
| .macro and_gr_immed val reg | |
| .if (\val >= -2048) && (\val <= 2047) | |
| andi \reg,\val,\reg | |
| .else | |
| set_gr_immed \val,gr28 | |
| and \reg,gr28,\reg | |
| .endif | |
| .endm | |
| ; OR GR with immediate value | |
| .macro or_gr_immed val reg | |
| .if (\val >= -2048) && (\val <= 2047) | |
| ori \reg,\val,\reg | |
| .else | |
| set_gr_immed \val,gr28 | |
| or \reg,gr28,\reg | |
| .endif | |
| .endm | |
| ; Set FR with another FR | |
| .macro set_fr_fr src targ | |
| fmovs \src,\targ | |
| .endm | |
| ; Set FR with integer immediate value | |
| .macro set_fr_iimmed valh vall reg | |
| set_gr_limmed \valh,\vall,gr28 | |
| movgf gr28,\reg | |
| .endm | |
| ; Set FR with integer immediate value | |
| .macro set_fr_immed val reg | |
| set_gr_immed \val,gr28 | |
| movgf gr28,\reg | |
| .endm | |
| ; Set FR with a value from memory | |
| .macro set_fr_mem addr reg | |
| set_gr_addr \addr,gr28 | |
| ldfi @(gr28,0),\reg | |
| .endm | |
| ; Set double FR with another double FR | |
| .macro set_dfr_dfr src targ | |
| fmovd \src,\targ | |
| .endm | |
| ; Set double FR with a value from memory | |
| .macro set_dfr_mem addr reg | |
| set_gr_addr \addr,gr28 | |
| lddfi @(gr28,0),\reg | |
| .endm | |
| ; Set CPR with immediate value | |
| .macro set_cpr_immed val reg | |
| addi sp,-4,gr28 | |
| set_gr_immed \val,gr29 | |
| st gr29,@(gr28,gr0) | |
| ldc @(gr28,gr0),\reg | |
| .endm | |
| .macro set_cpr_limmed valh vall reg | |
| addi sp,-4,gr28 | |
| set_gr_limmed \valh,\vall,gr29 | |
| st gr29,@(gr28,gr0) | |
| ldc @(gr28,gr0),\reg | |
| .endm | |
| ; Set SPR with immediate value | |
| .macro set_spr_immed val reg | |
| set_gr_immed \val,gr28 | |
| movgs gr28,\reg | |
| .endm | |
| .macro set_spr_limmed valh vall reg | |
| set_gr_limmed \valh,\vall,gr28 | |
| movgs gr28,\reg | |
| .endm | |
| .macro set_spr_addr addr reg | |
| set_gr_addr \addr,gr28 | |
| movgs gr28,\reg | |
| .endm | |
| ; increment SPR with immediate value | |
| .macro inc_spr_immed val reg | |
| movsg \reg,gr28 | |
| inc_gr_immed \val,gr28 | |
| movgs gr28,\reg | |
| .endm | |
| ; OR spr with immediate value | |
| .macro or_spr_immed val reg | |
| movsg \reg,gr28 | |
| set_gr_immed \val,gr29 | |
| or gr28,gr29,gr28 | |
| movgs gr28,\reg | |
| .endm | |
| ; AND spr with immediate value | |
| .macro and_spr_immed val reg | |
| movsg \reg,gr28 | |
| set_gr_immed \val,gr29 | |
| and gr28,gr29,gr28 | |
| movgs gr28,\reg | |
| .endm | |
| ; Set accumulator with immediate value | |
| .macro set_acc_immed val reg | |
| set_fr_immed \val,fr31 | |
| mwtacc fr31,\reg | |
| .endm | |
| ; Set accumulator guard with immediate value | |
| .macro set_accg_immed val reg | |
| set_fr_immed \val,fr31 | |
| mwtaccg fr31,\reg | |
| .endm | |
| ; Set memory with immediate value | |
| .macro set_mem_immed val base | |
| set_gr_immed \val,gr28 | |
| sti gr28,@(\base,0) | |
| .endm | |
| .macro set_mem_limmed valh vall base | |
| set_gr_limmed \valh,\vall,gr28 | |
| sti gr28,@(\base,0) | |
| .endm | |
| ; Set memory with GR value | |
| .macro set_mem_gr reg addr | |
| set_gr_addr \addr,gr28 | |
| sti \reg,@(gr28,0) | |
| .endm | |
| ; Test the value of a general register against another general register | |
| .macro test_gr_gr reg1 reg2 | |
| subcc \reg1,\reg2,gr0,icc3 | |
| beq icc3,0,test_gr\@ | |
| fail | |
| test_gr\@: | |
| .endm | |
| ; Test the value of an immediate against a general register | |
| .macro test_gr_immed val reg | |
| .if (\val >= -512) && (\val <= 511) | |
| subicc \reg,\val,gr0,icc3 | |
| .else | |
| set_gr_immed \val,gr28 | |
| subcc \reg,gr28,gr0,icc3 | |
| .endif | |
| beq icc3,0,test_gr\@ | |
| fail | |
| test_gr\@: | |
| .endm | |
| .macro test_gr_limmed valh vall reg | |
| set_gr_limmed \valh,\vall,gr28 | |
| subcc \reg,gr28,gr0,icc3 | |
| beq icc3,0,test_gr\@ | |
| fail | |
| test_gr\@: | |
| .endm | |
| ; Test the value of an floating register against an integer immediate | |
| .macro test_fr_limmed valh vall reg | |
| movfg \reg,gr29 | |
| set_gr_limmed \valh,\vall,gr28 | |
| subcc gr29,gr28,gr0,icc3 | |
| beq icc3,0,test_gr\@ | |
| fail | |
| test_gr\@: | |
| .endm | |
| .macro test_fr_iimmed val reg | |
| movfg \reg,gr29 | |
| set_gr_immed \val,gr28 | |
| subcc gr29,gr28,gr0,icc3 | |
| beq icc3,0,test_gr\@ | |
| fail | |
| test_gr\@: | |
| .endm | |
| ; Test the value of a floating register against another floating point register | |
| .macro test_fr_fr reg1 reg2 | |
| fcmps \reg1,\reg2,fcc3 | |
| fbeq fcc3,0,test_gr\@ | |
| fail | |
| test_gr\@: | |
| .endm | |
| ; Test the value of a double floating register against another | |
| ; double floating point register | |
| .macro test_dfr_dfr reg1 reg2 | |
| fcmpd \reg1,\reg2,fcc3 | |
| fbeq fcc3,0,test_gr\@ | |
| fail | |
| test_gr\@: | |
| .endm | |
| ; Test the value of a special purpose register against an integer immediate | |
| .macro test_spr_immed val reg | |
| movsg \reg,gr29 | |
| set_gr_immed \val,gr28 | |
| subcc gr29,gr28,gr0,icc3 | |
| beq icc3,0,test_gr\@ | |
| fail | |
| test_gr\@: | |
| .endm | |
| .macro test_spr_limmed valh vall reg | |
| movsg \reg,gr29 | |
| set_gr_limmed \valh,\vall,gr28 | |
| subcc gr29,gr28,gr0,icc3 | |
| beq icc3,0,test_gr\@ | |
| fail | |
| test_gr\@: | |
| .endm | |
| .macro test_spr_gr spr gr | |
| movsg \spr,gr28 | |
| test_gr_gr \gr,gr28 | |
| .endm | |
| .macro test_spr_addr addr reg | |
| movsg \reg,gr29 | |
| set_gr_addr \addr,gr28 | |
| test_gr_gr gr28,gr29 | |
| .endm | |
| ; Test spr bits masked and shifted against the given value | |
| .macro test_spr_bits mask,shift,val,reg | |
| movsg \reg,gr28 | |
| set_gr_immed \mask,gr29 | |
| and gr28,gr29,gr28 | |
| srli gr28,\shift,gr29 | |
| test_gr_immed \val,gr29 | |
| .endm | |
| ; Test the value of an accumulator against an integer immediate | |
| .macro test_acc_immed val reg | |
| mrdacc \reg,fr31 | |
| test_fr_iimmed \val,fr31 | |
| .endm | |
| ; Test the value of an accumulator against an integer immediate | |
| .macro test_acc_limmed valh vall reg | |
| mrdacc \reg,fr31 | |
| test_fr_limmed \valh,\vall,fr31 | |
| .endm | |
| ; Test the value of an accumulator guard against an integer immediate | |
| .macro test_accg_immed val reg | |
| mrdaccg \reg,fr31 | |
| test_fr_iimmed \val,fr31 | |
| .endm | |
| ; Test CPR agains an immediate value | |
| .macro test_cpr_limmed valh vall reg | |
| addi sp,-4,gr31 | |
| stc \reg,@(gr31,gr0) | |
| test_mem_limmed \valh,\vall,gr31 | |
| .endm | |
| ; Test the value of an immediate against memory | |
| .macro test_mem_immed val base | |
| ldi @(\base,0),gr29 | |
| .if (\val >= -512) && (\val <= 511) | |
| subicc gr29,\val,gr0,icc3 | |
| .else | |
| set_gr_immed \val,gr28 | |
| subcc gr29,gr28,gr0,icc3 | |
| .endif | |
| beq icc3,0,test_gr\@ | |
| fail | |
| test_gr\@: | |
| .endm | |
| .macro test_mem_limmed valh vall base | |
| ldi @(\base,0),gr29 | |
| set_gr_limmed \valh,\vall,gr28 | |
| subcc gr29,gr28,gr0,icc3 | |
| beq icc3,0,test_gr\@ | |
| fail | |
| test_gr\@: | |
| .endm | |
| ; Set an integer condition code | |
| .macro set_icc mask iccno | |
| set_gr_immed 4,gr29 | |
| smuli gr29,\iccno,gr30 | |
| addi gr31,16,gr31 | |
| set_gr_immed 0xf,gr28 | |
| sll gr28,gr31,gr28 | |
| not gr28,gr28 | |
| movsg ccr,gr29 | |
| and gr28,gr29,gr29 | |
| set_gr_immed \mask,gr28 | |
| sll gr28,gr31,gr28 | |
| or gr28,gr29,gr29 | |
| movgs gr29,ccr | |
| .endm | |
| ; started here | |
| ; Test the condition codes | |
| .macro test_icc N Z V C iccno | |
| .if (\N == 1) | |
| bp \iccno,0,fail\@ | |
| .else | |
| bn \iccno,0,fail\@ | |
| .endif | |
| .if (\Z == 1) | |
| bne \iccno,0,fail\@ | |
| .else | |
| beq \iccno,0,fail\@ | |
| .endif | |
| .if (\V == 1) | |
| bnv \iccno,0,fail\@ | |
| .else | |
| bv \iccno,0,fail\@ | |
| .endif | |
| .if (\C == 1) | |
| bnc \iccno,0,fail\@ | |
| .else | |
| bc \iccno,0,fail\@ | |
| .endif | |
| bra test_cc\@ | |
| fail\@: | |
| fail | |
| test_cc\@: | |
| .endm | |
| ; Set an floating point condition code | |
| .macro set_fcc mask fccno | |
| set_gr_immed 4,gr29 | |
| smuli gr29,\fccno,gr30 | |
| set_gr_immed 0xf,gr28 | |
| sll gr28,gr31,gr28 | |
| not gr28,gr28 | |
| movsg ccr,gr29 | |
| and gr28,gr29,gr29 | |
| set_gr_immed \mask,gr28 | |
| sll gr28,gr31,gr28 | |
| or gr28,gr29,gr29 | |
| movgs gr29,ccr | |
| .endm | |
| ; Test the condition codes | |
| .macro test_fcc val fccno | |
| set_gr_immed 4,gr29 | |
| smuli gr29,\fccno,gr30 | |
| movsg ccr,gr29 | |
| srl gr29,gr31,gr29 | |
| andi gr29,0xf,gr29 | |
| test_gr_immed \val,gr29 | |
| .endm | |
| ; Set PSR.ET | |
| .macro set_psr_et val | |
| movsg psr,gr28 | |
| .if (\val == 1) | |
| ori gr28,1,gr28 ; Turn on SPR.ET | |
| .else | |
| andi gr28,0xfffffffe,gr28 ; Turn off SPR.ET | |
| .endif | |
| movgs gr28,psr | |
| .endm | |
| ; Floating point constants | |
| .macro float_constants | |
| f0: .float 0.0 | |
| f1: .float 1.0 | |
| f2: .float 2.0 | |
| f3: .float 3.0 | |
| f6: .float 6.0 | |
| f9: .float 9.0 | |
| fn0: .float -0.0 | |
| fn1: .float -1.0 | |
| finf: .long 0x7f800000 | |
| fninf: .long 0xff800000 | |
| fmax: .long 0x7f7fffff | |
| fmin: .long 0xff7fffff | |
| feps: .long 0x00400000 | |
| fneps: .long 0x80400000 | |
| fnan1: .long 0x7fc00000 | |
| fnan2: .long 0x7f800001 | |
| .endm | |
| .macro double_constants | |
| d0: .double 0.0 | |
| d1: .double 1.0 | |
| d2: .double 2.0 | |
| d3: .double 3.0 | |
| d6: .double 6.0 | |
| d9: .double 9.0 | |
| dn0: .double -0.0 | |
| dn1: .double -1.0 | |
| dinf: .long 0x7ff00000 | |
| .long 0x00000000 | |
| dninf: .long 0xfff00000 | |
| .long 0x00000000 | |
| dmax: .long 0x7fefffff | |
| .long 0xffffffff | |
| dmin: .long 0xffefffff | |
| .long 0xffffffff | |
| deps: .long 0x00080000 | |
| .long 0x00000000 | |
| dneps: .long 0x80080000 | |
| .long 0x00000000 | |
| dnan1: .long 0x7ff80000 | |
| .long 0x00000000 | |
| dnan2: .long 0x7ff00000 | |
| .long 0x00000001 | |
| .endm | |
| ; Load floating point constants | |
| .macro load_float_constants | |
| set_fr_mem fninf,fr0 | |
| set_fr_mem fmin,fr4 | |
| set_fr_mem fn1,fr8 | |
| set_fr_mem fneps,fr12 | |
| set_fr_mem fn0,fr16 | |
| set_fr_mem f0,fr20 | |
| set_fr_mem feps,fr24 | |
| set_fr_mem f1,fr28 | |
| set_fr_mem f2,fr32 | |
| set_fr_mem f3,fr36 | |
| set_fr_mem f6,fr40 | |
| set_fr_mem f9,fr44 | |
| set_fr_mem fmax,fr48 | |
| set_fr_mem finf,fr52 | |
| set_fr_mem fnan1,fr56 | |
| set_fr_mem fnan2,fr60 | |
| .endm | |
| .macro load_float_constants1 | |
| set_fr_mem fninf,fr1 | |
| set_fr_mem fmin,fr5 | |
| set_fr_mem fn1,fr9 | |
| set_fr_mem fneps,fr13 | |
| set_fr_mem fn0,fr17 | |
| set_fr_mem f0,fr21 | |
| set_fr_mem feps,fr25 | |
| set_fr_mem f1,fr29 | |
| set_fr_mem f2,fr33 | |
| set_fr_mem f3,fr37 | |
| set_fr_mem f6,fr41 | |
| set_fr_mem f9,fr45 | |
| set_fr_mem fmax,fr49 | |
| set_fr_mem finf,fr53 | |
| set_fr_mem fnan1,fr57 | |
| set_fr_mem fnan2,fr61 | |
| .endm | |
| .macro load_float_constants2 | |
| set_fr_mem fninf,fr2 | |
| set_fr_mem fmin,fr6 | |
| set_fr_mem fn1,fr10 | |
| set_fr_mem fneps,fr14 | |
| set_fr_mem fn0,fr18 | |
| set_fr_mem f0,fr22 | |
| set_fr_mem feps,fr26 | |
| set_fr_mem f1,fr30 | |
| set_fr_mem f2,fr34 | |
| set_fr_mem f3,fr38 | |
| set_fr_mem f6,fr42 | |
| set_fr_mem f9,fr46 | |
| set_fr_mem fmax,fr50 | |
| set_fr_mem finf,fr54 | |
| set_fr_mem fnan1,fr58 | |
| set_fr_mem fnan2,fr62 | |
| .endm | |
| .macro load_float_constants3 | |
| set_fr_mem fninf,fr3 | |
| set_fr_mem fmin,fr7 | |
| set_fr_mem fn1,fr11 | |
| set_fr_mem fneps,fr15 | |
| set_fr_mem fn0,fr19 | |
| set_fr_mem f0,fr23 | |
| set_fr_mem feps,fr27 | |
| set_fr_mem f1,fr31 | |
| set_fr_mem f2,fr35 | |
| set_fr_mem f3,fr39 | |
| set_fr_mem f6,fr43 | |
| set_fr_mem f9,fr47 | |
| set_fr_mem fmax,fr51 | |
| set_fr_mem finf,fr55 | |
| set_fr_mem fnan1,fr59 | |
| set_fr_mem fnan2,fr63 | |
| .endm | |
| .macro load_double_constants | |
| set_dfr_mem dninf,fr0 | |
| set_dfr_mem dmin,fr4 | |
| set_dfr_mem dn1,fr8 | |
| set_dfr_mem dneps,fr12 | |
| set_dfr_mem dn0,fr16 | |
| set_dfr_mem d0,fr20 | |
| set_dfr_mem deps,fr24 | |
| set_dfr_mem d1,fr28 | |
| set_dfr_mem d2,fr32 | |
| set_dfr_mem d3,fr36 | |
| set_dfr_mem d6,fr40 | |
| set_dfr_mem d9,fr44 | |
| set_dfr_mem dmax,fr48 | |
| set_dfr_mem dinf,fr52 | |
| set_dfr_mem dnan1,fr56 | |
| set_dfr_mem dnan2,fr60 | |
| .endm | |
| ; Lock the insn cache at the given address | |
| .macro lock_insn_cache address | |
| icpl \address,gr0,1 | |
| .endm | |
| ; Lock the data cache at the given address | |
| .macro lock_data_cache address | |
| dcpl \address,gr0,1 | |
| .endm | |
| ; Invalidate the data cache at the given address | |
| .macro invalidate_data_cache address | |
| dci @(\address,gr0) | |
| .endm | |
| ; Flush the data cache at the given address | |
| .macro flush_data_cache address | |
| dcf @(\address,gr0) | |
| .endm | |
| ; Write a bctrlr 0,0 insn at the address contained in the given register | |
| .macro set_bctrlr_0_0 address | |
| set_mem_immed 0x80382000,\address ; bctrlr 0,0 | |
| flush_data_cache \address | |
| .endm | |
| ; Exit with return code | |
| .macro exit rc | |
| setlos #1,gr7 | |
| set_gr_immed \rc,gr8 | |
| tira gr0,#0 | |
| .endm | |
| ; Pass the test case | |
| .macro pass | |
| pass\@: | |
| setlos.p #5,gr10 | |
| setlos #1,gr8 | |
| setlos #5,gr7 | |
| set_gr_addr passmsg,gr9 | |
| tira gr0,#0 | |
| exit #0 | |
| .endm | |
| ; Fail the testcase | |
| .macro fail | |
| fail\@: | |
| setlos.p #5,gr10 | |
| setlos #1,gr8 | |
| setlos #5,gr7 | |
| set_gr_addr failmsg,gr9 | |
| tira gr0,#0 | |
| exit #1 | |
| .endm |