SWAT
Администратор
Сообщений: 7244
Зарегистрирован: 04.01.2005
Рейтинг: 30
Сказал спасибо: 149
Поблагодарили 1216 раз(а) в 764 сообщ.
|
Ответ: Нужна помощь по ассемблеру SH4
Ну а если уж оочень хочется посмотреть на код, вот, пожалуйста:
Код:
! KallistiOS ##version##
!
! arch/dreamcast/kernel/entry.s
! (c)2000-2001 Dan Potter
!
! Assembler code for entry and exit to/from the kernel via exceptions
!
! Routine that all exception handlers jump to after setting
! an error code. Out of neccessity, all of this function is in
! assembler instead of C. Once the registers are saved, we will
! jump into a shared routine. This register save and restore code
! is mostly from my sh-stub code. For now this is pretty high overhead
! for a context switcher (or especially a timer! =) but it can
! be optimized later.
.text
.align 2
.globl _irq_srt_addr
.globl _irq_handle_exception
.globl _irq_save_regs
.globl _irq_force_return
! Static kernel-mode stack; we can get away with this because in our
! tiny microkernel, only one thread will ever actually be sitting inside
! the kernel code. All other threads will be halted at the point at which
! they made their trap call into the kernel. This lets us do all sorts of
! useful things, like freedom to remap memory at any time, safety from
! mis-mapped user-mode stack pointers, etc. It also opens the door for
! hard real-time interrupts and exceptions that interrupt the kernel
! itself.
.space 4096 ! One page
krn_stack:
! All exception vectors lead to Rome (i.e., this label).
_irq_save_regs:
! On the SH4, an exception triggers a toggle of RB in SR. So all
! the R0-R7 registers were convienently saved for us.
mov.l _irq_srt_addr,r0 ! Grab the location of the reg store
add #0x20,r0 ! Start at the top of the BANK regs
stc.l r7_bank,@-r0 ! Save R7
stc.l r6_bank,@-r0 ! Save R6
stc.l r5_bank,@-r0 ! Save R5
stc.l r4_bank,@-r0 ! Save R4
stc.l r3_bank,@-r0 ! Save R3
stc.l r2_bank,@-r0 ! Save R2
stc.l r1_bank,@-r0 ! Save R1
stc.l r0_bank,@-r0 ! Save R0
mov.l r8,@(0x20,r0) ! save R8
mov.l r9,@(0x24,r0) ! save R9
mov.l r10,@(0x28,r0) ! save R10
mov.l r11,@(0x2c,r0) ! save R11
mov.l r12,@(0x30,r0) ! save R12
mov.l r13,@(0x34,r0) ! save R13
mov.l r14,@(0x38,r0) ! save R14
mov.l r15,@(0x3c,r0) ! save R15 (SP)
add #0x5c,r0 ! readjust register pointer
stc.l ssr,@-r0 ! save SSR 0x58
sts.l macl,@-r0 ! save MACL 0x54
sts.l mach,@-r0 ! save MACH 0x50
stc.l vbr,@-r0 ! save VBR 0x4c
stc.l gbr,@-r0 ! save GBR 0x48
sts.l pr,@-r0 ! save PR 0x44
stc.l spc,@-r0 ! save PC 0x40
add #0x60,r0 ! readjust register pointer
add #0x44,r0
sts.l fpul,@-r0 ! save FPUL 0xe0
sts.l fpscr,@-r0 ! save FPSCR 0xdc
mov #0,r2 ! Set known FP flags
lds r2,fpscr
fmov.s fr15,@-r0 ! save FR15 0xd8
fmov.s fr14,@-r0 ! save FR14
fmov.s fr13,@-r0 ! save FR13
fmov.s fr12,@-r0 ! save FR12
fmov.s fr11,@-r0 ! save FR11
fmov.s fr10,@-r0 ! save FR10
fmov.s fr9,@-r0 ! save FR9
fmov.s fr8,@-r0 ! save FR8
fmov.s fr7,@-r0 ! save FR7
fmov.s fr6,@-r0 ! save FR6
fmov.s fr5,@-r0 ! save FR5
fmov.s fr4,@-r0 ! save FR4
fmov.s fr3,@-r0 ! save FR3
fmov.s fr2,@-r0 ! save FR2
fmov.s fr1,@-r0 ! save FR1
fmov.s fr0,@-r0 ! save FR0 0x9c
frchg ! Second FP bank
fmov.s fr15,@-r0 ! save FR15 0x98
fmov.s fr14,@-r0 ! save FR14
fmov.s fr13,@-r0 ! save FR13
fmov.s fr12,@-r0 ! save FR12
fmov.s fr11,@-r0 ! save FR11
fmov.s fr10,@-r0 ! save FR10
fmov.s fr9,@-r0 ! save FR9
fmov.s fr8,@-r0 ! save FR8
fmov.s fr7,@-r0 ! save FR7
fmov.s fr6,@-r0 ! save FR6
fmov.s fr5,@-r0 ! save FR5
fmov.s fr4,@-r0 ! save FR4
fmov.s fr3,@-r0 ! save FR3
fmov.s fr2,@-r0 ! save FR2
fmov.s fr1,@-r0 ! save FR1
fmov.s fr0,@-r0 ! save FR0 0x5c
frchg ! First FP bank again
! Setup our kernel-mode stack
mov.l stkaddr,r15
! Before we enter the main C code again, re-enable exceptions
! (but not interrupts) so we can still debug inside handlers.
bsr _irq_disable
nop
! R4 still contains the exception code
mov.l hdl_except,r2 ! Call handle_exception
jsr @r2
nop
bra _save_regs_finish
nop
! irq_force_return() jumps here; make sure we're in register
! bank 1 (as opposed to 0)
_irq_force_return:
mov.l _irqfr_or,r1
stc sr,r0
or r1,r0
ldc r0,sr
bra _save_regs_finish
nop
.align 2
_irqfr_or:
.long 0x20000000
stkaddr:
.long krn_stack
! Now restore all the registers and jump back to the thread
_save_regs_finish:
mov.l _irq_srt_addr, r1 ! Get register store address
ldc.l @r1+,r0_bank ! restore R0 (r1 is now _irq_srt_addr+0)
ldc.l @r1+,r1_bank ! restore R1
ldc.l @r1+,r2_bank ! restore R2
ldc.l @r1+,r3_bank ! restore R3
ldc.l @r1+,r4_bank ! restore R4
ldc.l @r1+,r5_bank ! restore R5
ldc.l @r1+,r6_bank ! restore R6
ldc.l @r1+,r7_bank ! restore R7
add #-32,r1 ! Go back to the front
mov.l @(0x20,r1), r8 ! restore R8 (r1 is now ...+0)
mov.l @(0x24,r1), r9 ! restore R9
mov.l @(0x28,r1), r10 ! restore R10
mov.l @(0x2c,r1), r11 ! restore R11
mov.l @(0x30,r1), r12 ! restore R12
mov.l @(0x34,r1), r13 ! restore R13
mov.l @(0x38,r1), r14 ! restore R14
mov.l @(0x3c,r1), r15 ! restore program's stack
add #0x40,r1 ! jump up to status words
ldc.l @r1+,spc ! restore SPC 0x40 (r1 is now +0x40)
lds.l @r1+,pr ! restore PR 0x44 (+0x44)
ldc.l @r1+,gbr ! restore GBR 0x48 (+0x48)
! ldc.l @r1+,vbr ! restore VBR (don't play with VBR)
add #4,r1 ! (+0x4c)
lds.l @r1+,mach ! restore MACH 0x50 (+0x50)
lds.l @r1+,macl ! restore MACL 0x54 (+0x54)
ldc.l @r1+,ssr ! restore SSR 0x58 (+0x58)
mov #0,r2 ! Set known FP flags (+0x5c)
lds r2,fpscr
frchg ! Second FP bank
fmov.s @r1+,fr0 ! restore FR0 0x5c
fmov.s @r1+,fr1 ! restore FR1
fmov.s @r1+,fr2s ! restore FR2
fmov.s @r1+,fr3 ! restore FR3
fmov.s @r1+,fr4 ! restore FR4
fmov.s @r1+,fr5 ! restore FR5
fmov.s @r1+,fr6 ! restore FR6
fmov.s @r1+,fr7 ! restore FR7
fmov.s @r1+,fr8 ! restore FR8
fmov.s @r1+,fr9 ! restore FR9
fmov.s @r1+,fr10 ! restore FR10
fmov.s @r1+,fr11 ! restore FR11
fmov.s @r1+,fr12 ! restore FR12
fmov.s @r1+,fr13 ! restore FR13
fmov.s @r1+,fr14 ! restore FR14
fmov.s @r1+,fr15 ! restore FR15 0x98
frchg ! First FP bank
fmov.s @r1+,fr0 ! restore FR0 0x9c
fmov.s @r1+,fr1 ! restore FR1
fmov.s @r1+,fr2 ! restore FR2
fmov.s @r1+,fr3 ! restore FR3
fmov.s @r1+,fr4 ! restore FR4
fmov.s @r1+,fr5 ! restore FR5
fmov.s @r1+,fr6 ! restore FR6
fmov.s @r1+,fr7 ! restore FR7
fmov.s @r1+,fr8 ! restore FR8
fmov.s @r1+,fr9 ! restore FR9
fmov.s @r1+,fr10 ! restore FR10
fmov.s @r1+,fr11 ! restore FR11
fmov.s @r1+,fr12 ! restore FR12
fmov.s @r1+,fr13 ! restore FR13
fmov.s @r1+,fr14 ! restore FR14
fmov.s @r1+,fr15 ! restore FR15 0xd8
lds.l @r1+,fpscr ! restore FPSCR 0xdc
lds.l @r1+,fpul ! restore FPUL 0xe0
! add #-0x70,r1 ! jump back to registers
! add #-0x34,r1
! mov.l @(0,r1),r0 ! restore R0
! mov.l @(4,r1),r1 ! restore R1
mov #2,r0
rte ! return
nop
.align 2
_irq_srt_addr:
.long 0 ! Save Regs Table -- this is an indirection
! so we can easily swap out pointers during a
! context switch.
hdl_except:
.long _irq_handle_exception
! Special case handler for TLB miss exceptions. There are two reasons
! why we'd want to do this and complicate things. The first is speed --
! if TLB misses happen often (which is likely if we're using the MMU
! allocator) then saving the full processor context and switching
! back is going to be a major drain on the dcache and also just
! general processor time. Second reason is that it allows us to process
! these inside an IRQ/exception handler without having to have nestable
! exceptions just yet. That's a whole 'nother egg I don't want to
! break just yet.
!
! !!NOTE!! This is highly dependent on the structure of the MMU tables
! in mmu.h and the MMU code in mmu.c. If either of those change, this will
! likely need to change as well.
.text
.align 2
tlb_miss_hnd:
! Get the exception event code; we want to handle only
! 0x0040 (ITLB_MISS/DTLB_MISS_READ) or 0x0060 (DTLB_MISS_WRITE)
mov #-1,r3 ! 0xff000024 (EXPEVT) -> r3
shll16 r3
shll8 r3
add #0x24,r3
mov.l @r3,r0 ! Get EXPEVT
mov #0x40,r1 ! 0x0040 -> r1
cmp/eq r0,r1
bt.s tmh_doit
mov #0x60,r1
cmp/eq r0,r1
bt tmh_doit
! It's not one of the MISS codes, just send it on to the normal
! irq processing.
bra _irq_save_regs
mov #2,r4
tmh_doit:
! So it's an ITLB or DTLB_MISS code. Look at the MMU module's
! shortcut flag. If that's set, it's safe to pass on processing
! directly to the mapping function.
! Check the shortcut flag
mov.l tmh_shortcut_addr,r0
mov.l @r0,r0
cmp/pz r0
bt tmh_clear
bra _irq_save_regs
mov #2,r4
tmh_clear:
! Coast is clear -- setup the args and call the C function. Regs R0-R7
! are volatile on SH-4 anyway, and R8-R14 will be saved if needed
! onto our temp stack. So all we need to worry about here, at least
! for this small C call, is the stack. To faciliate the stack, we'll
! save R15 and setup a small temp stack.
mov.l tmh_stack_save_addr,r0 ! Setup stack
mov.l r15,@r0
mov.l tmh_temp_stack_addr,r15
mov #0,r4 ! Call gen_miss
mov #0,r5
mov.l tmh_gen_miss_addr,r0
jsr @r0
mov #0,r6
mov.l tmh_stack_save,r15 ! Fix stack back
! Return back from the exception
rte
nop
.align 2
tmh_shortcut_addr:
.long _mmu_shortcut_ok
tmh_stack_save_addr:
.long tmh_stack_save
tmh_stack_save:
.long 0
tmh_temp_stack_addr:
.long tmh_temp_stack
tmh_gen_miss_addr:
.long _mmu_gen_tlb_miss
.data
.space 256
tmh_temp_stack:
! The SH4 has very odd exception handling. Instead of having a vector
! table like a sensible processor, it has a vector code block. *sigh*
! Thus this table of assembly code. Note that we can't catch reset
! exceptions at all, but that really shouldn't matter.
.text
.align 2
.globl _irq_vma_table
_irq_vma_table:
.rep 0x100
.byte 0
.endr
_vma_table_100: ! General exceptions
nop ! Can't have a branch as the first instr
bra _irq_save_regs
mov #1,r4 ! Set exception code
.rep 0x300 - 6
.byte 0
.endr
_vma_table_400: ! TLB miss exceptions (MMU)
nop
! bra tlb_miss_hnd
! nop
bra _irq_save_regs
mov #2,r4 ! Set exception code
.rep 0x200 - 6
.byte 0
.endr
_vma_table_600: ! IRQs
nop
bra _irq_save_regs
mov #3,r4 ! Set exception code
! Disable interrupts, but leave exceptions enabled. Returns the old
! interrupt status.
!
! Calling this inside an exception/interrupt handler will generally not have
! any effect.
!
.globl _irq_disable
_irq_disable:
mov.l _irqd_and,r1
mov.l _irqd_or,r2
stc sr,r0
and r0,r1
or r2,r1
ldc r1,sr
rts
nop
.align 2
_irqd_and:
.long 0xefffff0f
_irqd_or:
.long 0x000000f0
! Enable interrupts and exceptions. Returns the old interrupt status.
!
! Call this inside an exception/interrupt handler only with GREAT CARE.
!
.globl _irq_enable
_irq_enable:
mov.l _irqe_and,r1
stc sr,r0
and r0,r1
ldc r1,sr
rts
nop
.align 2
_irqe_and:
.long 0xefffff0f
! Restore interrupts to the state returned by irq_disable()
! or irq_enable().
.globl _irq_restore
_irq_restore:
ldc r4,sr
rts
nop
! Retrieve SR
.globl _irq_get_sr
_irq_get_sr:
rts
stc sr,r0
|
|