Initial commit of OpenSPARC T2 design and verification files.
[OpenSPARC-T2-DV] / verif / diag / assembly / isa3 / isa3_asi_cmp_core_2.s
/*
* ========== Copyright Header Begin ==========================================
*
* OpenSPARC T2 Processor File: isa3_asi_cmp_core_2.s
* Copyright (C) 1995-2007 Sun Microsystems, Inc. All Rights Reserved
* 4150 Network Circle, Santa Clara, California 95054, U.S.A.
*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* For the avoidance of doubt, and except that if any non-GPL license
* choice is available it will apply instead, Sun elects to use only
* the General Public License version 2 (GPLv2) at this time for any
* software where a choice of GPL license versions is made
* available with the language indicating that GPLv2 or any later version
* may be used, or where a choice of which version of the GPL is applied is
* otherwise unspecified.
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*
*
* ========== Copyright Header End ============================================
*/
#define MAIN_PAGE_NUCLEUS_ALSO
#define MAIN_PAGE_HV_ALSO
!#include "nmacros.h"
#include "hboot.s"
! can set this to 1 to stop test after thread 0 & 1 have
! parked/unparked all threads.
! #define STOP_AFTER
#define THREAD_COUNT %l1
! a threads unique addr for incrementing a counter.
#define MY_ADDR %l7
! addr that stores which thread is the master thread.
#define COMN_ADDR %l6
#define COMN_ADDR2 %l5
#define MY_ID %o1
#define MASK_OUT_SELF %l4
! holds user_data_start addr
#define USER_DATA %o3
! what threads are expected to be active
#define EXPECT_ACTIVE %o4
#define LAST_THREAD %o5
#define ALL1S 0xffffffffffffffff
/************************************************************************
Test case code start
************************************************************************/
.text
.global main
main:
!# Input registers
set 0, %i0
set 0, %i1
set 0, %i2
set 0, %i3
set 0, %i4
set 0, %i5
set 0, %i6
set 0, %i7
!# Local registers
set 0, %l0
set 0, %l1
set 0, %l2
set 0, %l3
set 0, %l4
set 0, %l5
set 0, %l6
set 0, %l7
!# Output registers
set 0, %o0
set 0, %o1
set 0, %o2
set 0, %o3
set 0, %o4
set 0, %o5
set 0, %o6
set 0, %o7
ta T_CHANGE_HPRIV ! run in Hpriv mode
nop
rdth_id ! get thread ID in %o1
! 9 64 bit memory locations. last is shared, init all to 0.
! offset 0 = thread 0 counter area
! ...
! offset 8 = common area that stores which thread is the master thread.
!umul MY_ID, 8, MY_ADDR ! per thread offset
sllx MY_ID, 6, MY_ADDR ! per thread offset, ID selects bank
setx user_data_start, %g1, USER_DATA ! data area base
add MY_ADDR, USER_DATA , MY_ADDR ! per thread address ('my' address)
add %g2, 0x40, COMN_ADDR ! common address
add COMN_ADDR, 0x8, COMN_ADDR2 ! common address 2
! what threads are expected to be active
wr %g0, 0x41, %asi
ldxa [%g0 + ASI_CMP_CORE_ENABLED] %asi, EXPECT_ACTIVE
! what thread will be the last thread
mov 0, LAST_THREAD ! init
mov EXPECT_ACTIVE, %g1 ! thread enabled mask
calc_last_thread:
srlx %g1, 1, %g1
cmp %g1, %g0
bne,a calc_last_thread
inc LAST_THREAD
mov LAST_THREAD, THREAD_COUNT
inc THREAD_COUNT
ba thread_x ! all threads do the same
nop
EXIT_BAD
!
! Thread Start
!
thread_x:
wr %g0, ASI_CMP_CORE, %asi
! signal that thread has gotten here (started).
mov 0xff, %g2
stb %g2, [COMN_ADDR2 + MY_ID]
! am I the master thread?
ldx [COMN_ADDR], %g2
cmp %g2, MY_ID
bne not_master
nop
! master waits for other threads to have started.
master_waiting:
ldx [COMN_ADDR2], %g2
cmp %g2, ALL1S
bne master_waiting
nop
! yes, skip first loop and control the parking instead
call park_control
nop
nop
! If we were just master, goto pass_control
ba pass_control !call will ret here
nop
not_master:
! not master, then loop doing visible busy work,
! waiting to become master on return
call counter1 ! %o7
nop
nop
! now we are master. next, pass control
call park_control
nop
nop
pass_control:
! pass control to next thread
add MY_ID, 1, %g2
stx %g2, [COMN_ADDR]
! now we do second loop,
! waiting to exit
call counter2 ! %o7
nop
nop
test_passed:
EXIT_GOOD
thread_not_parked:
nop
thread_not_running:
nop
bad_reg_value:
nop
test_failed:
nop
EXIT_BAD
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
! subroutines
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
! make sure all other threads are spinning counters.
! park all other threads.
! make sure all other threads are NOT spinning counters.
! UN park all other threads.
! make sure all other threads are spinning counters.
! return.
! CHECK FOR ERRORS!
park_control:
! save return address, nested calls
mov %o7, %i0
! make a mask, the only 0 is for self
sub %g0, 1, %g1
mov 1, MASK_OUT_SELF
sllx MASK_OUT_SELF, MY_ID, MASK_OUT_SELF
xor MASK_OUT_SELF, %g1, MASK_OUT_SELF ! the only 0 is for me
! make sure all other threads are spinning counters
call run_check ! changes %o7
nop
nop
return_from_run_check:
! park all other threads except self
stxa MASK_OUT_SELF, [%g0 + ASI_CMP_CORE_RUNNING_W1C] %asi
! check reg
ldxa [%g0 + ASI_CMP_CORE_RUNNING_RW] %asi, %l0
xor %l0, ALL1S, %l0
cmp %l0, MASK_OUT_SELF
bne bad_reg_value
mov %g0, %l0
! make sure all other threads are NOT spinning counters
call park_check ! changes %o7
nop
nop
return_from_park_check:
! UN park all other threads
stxa MASK_OUT_SELF, [%g0 + ASI_CMP_CORE_RUNNING_W1S] %asi
! checks reg
ldxa [%g0 + ASI_CMP_CORE_RUNNING_RW] %asi, %l0
cmp %l0, EXPECT_ACTIVE
bne bad_reg_value
mov %g0, %l0
! make sure all other threads are spinning counters
call run_check ! changes %o7
nop
! restore original return address
mov %i0, %o7
retl ! to %o7
nop
! ---
! confirm all threads are running/counting. (except for myself)
! loop for each thread.
run_check:
! save return address, nested calls
mov %o7, %i1
mov LAST_THREAD, %g4
loop_rc:
! skip self
cmp MY_ID, %g4
beq next_rc
nop
!umul %g4, 0x8, %g5 ! g4=tid, offset
sllx %g4, 6, %g5 ! move tid up to bank select position
!read counter location
ldx [USER_DATA + %g5], %g6
call delay
nop
delay_rtn1:
!read counter location
ldx [USER_DATA + %g5], %g7
!has it incremented?
cmp %g6, %g7
beq thread_not_running
nop
next_rc:
deccc %g4
bpos loop_rc
nop
! check ASI_CORE_RUNNING_STATUS, all active
ldxa [%g0 + ASI_CMP_CORE_RUNNING_STATUS] %asi, %g6
cmp %g6, EXPECT_ACTIVE ! what threads are expected to be active
bne bad_reg_value
nop
! restore original return address
mov %i1, %o7
retl ! to %o7
nop
! ---
! confirm, all threads are parked, except self.
! loop for each thread and insure counter does not inc
park_check:
! save return address, nested calls
mov %o7, %i2
mov LAST_THREAD, %g4
loop_pc:
! skip self
cmp MY_ID, %g4
beq next_pc
nop
!umul %g4, 0x8, %g5 ! g4=tid, offset
sllx %g4, 6, %g5 ! move tid up to bank select position
!read counter location
ldx [USER_DATA + %g5], %g6
call delay
nop
delay_rtn2:
!read counter location
ldx [USER_DATA + %g5], %g7
!has it incremented?
cmp %g6, %g7
bne thread_not_parked
nop
next_pc:
deccc %g4
bpos loop_pc
nop
! check ASI_CORE_RUNNING_STATUS, all active
ldxa [%g0 + ASI_CMP_CORE_RUNNING_STATUS] %asi, %g6
xor MASK_OUT_SELF, ALL1S, %g7 ! only self is set
cmp %g6, %g7
bne bad_reg_value
nop
! restore original return address
mov %i2, %o7
retl ! %o7
nop
! ---
! spin incrementing a mem location.
! look at the master address to see when I become master.
counter1:
mov 1, %g1
loop_1:
stx %g1, [MY_ADDR]
ldx [COMN_ADDR], %g2
cmp %g2, MY_ID ! thread id
bne,a loop_1
inc %g1
retl ! %o7
nop
! ---
! spin incrementing a mem location.
! look at the master address to see when I need to exit
counter2:
mov 1, %g3
loop_2:
stx %g3, [MY_ADDR]
ldx [COMN_ADDR], %g2
cmp %g2, THREAD_COUNT ! final thread is done
bne,a loop_2
inc %g3
retl ! %o7
nop
! ---
! kill time, do a few divides
delay:
!do a divide a few times
ldd [COMN_ADDR + 0x10], %f0
ldd [COMN_ADDR + 0x18], %f2
fdivd %f0, %f2, %f4
fdivd %f4, %f6, %f0
! fdivd %f0, %f2, %f4
! fdivd %f4, %f6, %f0
! fmuld %f0, %f2, %f4
! fmuld %f4, %f6, %f0
! fdivd %f0, %f2, %f4
! fdivd %f4, %f6, %f0
! fdivd %f0, %f2, %f4
! fdivd %f4, %f6, %f0
! fmuld %f0, %f2, %f4
! fmuld %f4, %f6, %f0
! fmuld %f0, %f2, %f4
! fmuld %f4, %f6, %f0
fdivd %f0, %f2, %f4
fdivd %f4, %f6, %f0
fdivd %f0, %f2, %f4
fdivd %f4, %f6, %f0
fmuld %f0, %f2, %f4
fmuld %f4, %f6, %f0
fdivd %f0, %f2, %f4
fdivd %f4, %f6, %f0
fdivd %f0, %f2, %f4
fdivd %f4, %f6, %f0
fmuld %f0, %f2, %f4
! fmuld %f4, %f6, %f0
! fmuld %f0, %f2, %f4
! fmuld %f4, %f6, %f0
! fdivd %f0, %f2, %f4
! fdivd %f4, %f6, %f0
fdivd %f0, %f2, %f4
retl ! %o7
nop
! ---
/************************************************************************
Test case data start
************************************************************************/
.data
user_data_start:
.xword 0x0
.xword 0x0
.xword 0x0
.xword 0x0
.xword 0x0
.xword 0x0
.xword 0x0
.xword 0x0
.xword 0x0
.xword 0x5555555555555555
.xword 0xaaaaaaaaaaaaaaaa
.xword 0x5555555555555555
.xword 0xaaaaaaaaaaaaaaaa
.xword 0x5555555555555555
.xword 0xaaaaaaaaaaaaaaaa
.xword 0x5555555555555555
.xword 0xaaaaaaaaaaaaaaaa
.xword 0x5555555555555555
.xword 0xaaaaaaaaaaaaaaaa
.xword 0x5555555555555555
.xword 0xaaaaaaaaaaaaaaaa
.xword 0x5555555555555555
.xword 0xaaaaaaaaaaaaaaaa
.xword 0x5555555555555555
.xword 0xaaaaaaaaaaaaaaaa
.end