Initial commit of OpenSPARC T2 architecture model.
[OpenSPARC-T2-SAM] / sam-t2 / sam / cpus / vonk / ss / lib / cpu / src / SS_V8Code.s
/*
* ========== Copyright Header Begin ==========================================
*
* OpenSPARC T2 Processor File: SS_V8Code.s
* Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES.
*
* The above named program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public
* License version 2 as published by the Free Software Foundation.
*
* The above named 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 work; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
*
* ========== Copyright Header End ============================================
*/
#if !defined(ARCH_X64)
!============================================================================
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!============================================================================
! tHIS COMMENT SECTION IS A MUST READ fOR THOSE THAT ARE GOING TO CHANGE THIS
! CODE. iF YOU DON'T READ IT OR DO NOT KNOW WHAT YOU ARE DOING THEN KEEP OFF.
!============================================================================
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!============================================================================
! In v9 mode all the functions relevant in the code below use between 4 and 6
! arguments. This means that all there functions pass their arguments in
! registers only as v9 has %0 to %05 available for the first 6 64bit arguments.
!
!
! The v8(plus) standard stack frame looks like:
!
! %fp 0| 16-word window save area | (%fp == %i6)
! +--------------------------------+
! | unspecified |
! | .... |
! | variable size |
! +--------------------------------+
! +92 | (if needed) outgoing arg 6 ... |
! +--------------------------------+
! | six words into which callee |
! +68 | may write outgoing arg 0 to 5 |
! +--------------------------------+
! +64 | struct/union return pointer |
! +--------------------------------+
! %sp 0 | 16-word window save area | (%sp == %o6)
! +--------------------------------+
!
! The picture was taken from the documents found on http://www.sparc.com/standards
!
! On function calls registers %o0 to %o5 are arguments 0 to 5. Argument number
! 6 is placed on the stack at offset %sp + 92. The 7th argument is placed at
! offset %sp + 96, etc. In v8(plus) mode the arguments are 32bits in size.
!
! The v8plus "standard" documents says that the kernel preserves the upper
! 32bits of the global and the out registers on trap or interrupt. This suits
! us well as all our assembly code does not use save and restore, so without
! looking we can say these routines are safe for use in v8plus mode. Note we
! know our assembly only tail calls - it doesn't make "nested calls. Nested
! calls can chop the out registers to 32bits !!!! so v9 assembly code that does
! that wouldn't be safe to use in v8plus mode.
!
! There is one problem that we need to fix however. The stack frame and argument
! passing in v8plus is 32bits, and 64bits in v9 mode. So we need calling
! convention converters around the assembly code.
!
! A 64bit value in v8plus is stored in two 32bit memory locations. Following
! the ldd/std instructions the word(32bits) at addr contains bits 31 to 0 and
! the word at addr + 4 contain bits 63 to 32. For argument passing bits 31
! to 0 is kept argument N and bits 63 to 32 in argumewnt N+1.
!============================================================================
#include "SS_Assembly.h"
.register %g2,#scratch
.register %g3,#scratch
.section ".text"
!============================================================================
! run_exe_v8plus_to_v9 - this is the entry point for all the assembly coded
! routines in the run_exe table. From v8plus we call into v9 code. The run_exe
! routine's type signature is
! SS_Vaddr (*execute)( SS_Vaddr, SS_Vaddr, SS_Strand*,SS_Instr* );
! which fits in 6 registers: %o0 to %o5. However, some of the assembly
! routines need to call routines with more arguments: data_mmu for example.
! Hence this routines created space on the stack for these extra routines,
! it takes the worst case apporach, which is 3 more 4byte arguments is 12
! bytes. The v8(plus) ABI says that we need to move %sp by 92 + 12 = 104.
!============================================================================
.align 8
.global run_exe_v8plus_to_v9
.type run_exe_v8plus_to_v9, #function
run_exe_v8plus_to_v9:
save %sp,-104,%sp ! reserve 12 bytes of stack space
ldsh [%i5 + I_EXE_TBL_IDX],%g2 ! Get exe table index
sllx %i0,32,R_PC ! pc = (%i0 << 32) | %i1
srl %i1,0x0,%g1
or R_PC,%g1,R_PC
ld [%i4 + S_V8_EXE_TABLE],%g3 ! Get real exe table pointer
sllx %i2,32,R_NPC ! npc = (%i2 << 32) | %i3
srl %i3,0x0,%g1
or R_NPC,%g1,R_NPC
sll %g2,2,%g2
ld [%g3 + %g2],%g4 ! Get exe routine function
mov %i4,S_PTR ! %o2 - s
jmpl %g4,%o7 ! call asm exe routine
mov %i5,I_PTR ! and it returns pc in v8plus style.
mov %o0,%i0 ! return pc, in v8plus mode that's
ret
restore %o1,0,%o1
!============================================================================
! v9_to_v8plus - these are the exit points from the assembly routine (v9) to
! the c coded land (v8plus). The code has multiple entry points as the argu-
! ments are pretty much the same.
!============================================================================
v9_to_v8plus_pc_npc_s_i_va_mem:
v9_to_v8plus_pc_npc_s_i_va_tt:
st %o5,[%sp + 100] ! tt - store on the stack
v9_to_v8plus_pc_npc_s_i_va:
st %o4,[%sp + 96] ! store upper part of 64bit
srlx %o4,32,%o4 ! va - store on the stack
v9_to_v8plus_pc_npc_s_i_tt:
st %o4,[%sp + 92] ! lower part of 64bit (va) or
! 32bit argument (tt)
v9_to_v8plus_pc_npc_s_i:
sra I_PTR,0,%o5 ! i is %o5
sra S_PTR,0,%o4 ! s is %o4
srl %o1,0,%o3 ! npc is %o2, %o3
srlx %o1,32,%o2
srl %o0,0,%o1 ! pc is %o0, %o1
jmpl %g4,%g0 ! return (%g4)(pc,npc,s,i,...);
srlx %o0,32,%o0
!============================================================================
! SS_Vaddr (*trap)( SS_Vaddr pc, SS_Vaddr npc, SS_Strand* s, SS_Instr* i,
! SS_Trap::Type tt );
!============================================================================
.global trap_v9_to_v8plus
.type trap_v9_to_v8plus, #function
trap_v9_to_v8plus:
ba %xcc,v9_to_v8plus_pc_npc_s_i_tt
ld [S_PTR + S_TRAP],%g4
!============================================================================
! SS_Vaddr (*inst_trap)( SS_Vaddr pc, SS_Vaddr npc, SS_Strand* s, SS_Instr* i,
! SS_Vaddr va, SS_Trap::Type tt );
!============================================================================
.global inst_trap_v9_to_v8plus
.type inst_trap_v9_to_v8plus, #function
inst_trap_v9_to_v8plus:
ba %xcc,v9_to_v8plus_pc_npc_s_i_va_tt
ld [S_PTR + S_INST_TRAP],%g4
!============================================================================
! SS_Vaddr (*data_trap)( SS_Vaddr pc, SS_Vaddr npc, SS_Strand* s, SS_Instr* i,
! SS_Vaddr va, SS_Trap::Type tt );
!============================================================================
.global data_trap_v9_to_v8plus
.type data_trap_v9_to_v8plus, #function
data_trap_v9_to_v8plus:
ba %xcc,v9_to_v8plus_pc_npc_s_i_va_tt
ld [S_PTR + S_DATA_TRAP],%g4
!============================================================================
! SS_Vaddr (*data_mmu)( SS_Vaddr pc, SS_Vaddr npc, SS_Strand* s, SS_Instr* i,
! SS_Vaddr va, uint_t mem );
!============================================================================
.global data_mmu_v9_to_v8plus
.type data_mmu_v9_to_v8plus, #function
data_mmu_v9_to_v8plus:
ba %xcc,v9_to_v8plus_pc_npc_s_i_va_mem
ld [S_PTR + S_DATA_MMU],%g4
!============================================================================
! SS_Vaddr (*invalid_asi)( SS_Vaddr pc, SS_Vaddr npc, SS_Strand*, SS_Instr*,
! SS_Vaddr );
!============================================================================
.global invalid_asi_v9_to_v8plus
.type invalid_asi_v9_to_v8plus, #function
invalid_asi_v9_to_v8plus:
ba %xcc,v9_to_v8plus_pc_npc_s_i_va
ld [S_PTR + S_INVALID_ASI],%g4
!============================================================================
! SS_Vaddr (*inst_dev)( SS_Vaddr, SS_Vaddr, SS_Strand*,SS_Instr* );
!============================================================================
.global inst_dec_v9_to_v8plus
.type inst_dec_v9_to_v8plus, #function
inst_dec_v9_to_v8plus:
ba %xcc,v9_to_v8plus_pc_npc_s_i
ld [S_PTR + S_INST_DEC],%g4
#endif